1 use std::ffi::{CStr, CString};
2 use std::{mem, slice};
3 use std::path::PathBuf;
4 use std::ptr;
5 use std::rc::Rc;
6 use std::sync::Arc;
7 use std::os::raw::{c_void, c_char, c_float};
8 use gleam::gl;
9
10 use webrender::api::*;
11 use webrender::{ReadPixelsFormat, Renderer, RendererOptions, ThreadListener};
12 use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource};
13 use webrender::DebugFlags;
14 use webrender::{ApiRecordingReceiver, BinaryRecorder};
15 use webrender::{ProgramCache, UploadMethod, VertexUsageHint};
16 use thread_profiler::register_thread_with_profiler;
17 use moz2d_renderer::Moz2dImageRenderer;
18 use app_units::Au;
19 use rayon;
20 use euclid::SideOffsets2D;
21 use log;
22
23 #[cfg(target_os = "windows")]
24 use dwrote::{FontDescriptor, FontWeight, FontStretch, FontStyle};
25
26 #[cfg(target_os = "macos")]
27 use core_foundation::string::CFString;
28 #[cfg(target_os = "macos")]
29 use core_graphics::font::CGFont;
30
31 #[repr(C)]
32 pub enum WrExternalImageBufferType {
33 TextureHandle = 0,
34 TextureRectHandle = 1,
35 TextureArrayHandle = 2,
36 TextureExternalHandle = 3,
37 ExternalBuffer = 4,
38 }
39
40 impl WrExternalImageBufferType {
to_wr(self) -> ExternalImageType41 fn to_wr(self) -> ExternalImageType {
42 match self {
43 WrExternalImageBufferType::TextureHandle =>
44 ExternalImageType::TextureHandle(TextureTarget::Default),
45 WrExternalImageBufferType::TextureRectHandle =>
46 ExternalImageType::TextureHandle(TextureTarget::Rect),
47 WrExternalImageBufferType::TextureArrayHandle =>
48 ExternalImageType::TextureHandle(TextureTarget::Array),
49 WrExternalImageBufferType::TextureExternalHandle =>
50 ExternalImageType::TextureHandle(TextureTarget::External),
51 WrExternalImageBufferType::ExternalBuffer =>
52 ExternalImageType::Buffer,
53 }
54 }
55 }
56
57 /// cbindgen:field-names=[mHandle]
58 /// cbindgen:derive-lt=true
59 /// cbindgen:derive-lte=true
60 type WrEpoch = Epoch;
61 /// cbindgen:field-names=[mHandle]
62 /// cbindgen:derive-lt=true
63 /// cbindgen:derive-lte=true
64 /// cbindgen:derive-neq=true
65 type WrIdNamespace = IdNamespace;
66
67 /// cbindgen:field-names=[mNamespace, mHandle]
68 type WrPipelineId = PipelineId;
69 /// cbindgen:field-names=[mNamespace, mHandle]
70 /// cbindgen:derive-neq=true
71 type WrImageKey = ImageKey;
72 /// cbindgen:field-names=[mNamespace, mHandle]
73 pub type WrFontKey = FontKey;
74 /// cbindgen:field-names=[mNamespace, mHandle]
75 type WrFontInstanceKey = FontInstanceKey;
76 /// cbindgen:field-names=[mNamespace, mHandle]
77 type WrYuvColorSpace = YuvColorSpace;
78 /// cbindgen:field-names=[mNamespace, mHandle]
79 type WrLogLevelFilter = log::LevelFilter;
80
make_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T]81 fn make_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
82 if ptr.is_null() {
83 &[]
84 } else {
85 unsafe { slice::from_raw_parts(ptr, len) }
86 }
87 }
88
make_slice_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T]89 fn make_slice_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T] {
90 if ptr.is_null() {
91 &mut []
92 } else {
93 unsafe { slice::from_raw_parts_mut(ptr, len) }
94 }
95 }
96
97 pub struct DocumentHandle {
98 api: RenderApi,
99 document_id: DocumentId,
100 }
101
102 impl DocumentHandle {
new(api: RenderApi, size: DeviceUintSize, layer: i8) -> DocumentHandle103 pub fn new(api: RenderApi, size: DeviceUintSize, layer: i8) -> DocumentHandle {
104 let doc = api.add_document(size, layer);
105 DocumentHandle {
106 api: api,
107 document_id: doc
108 }
109 }
110 }
111
112 #[repr(C)]
113 pub struct WrVecU8 {
114 data: *mut u8,
115 length: usize,
116 capacity: usize,
117 }
118
119 impl WrVecU8 {
to_vec(self) -> Vec<u8>120 fn to_vec(self) -> Vec<u8> {
121 unsafe { Vec::from_raw_parts(self.data, self.length, self.capacity) }
122 }
123
124 // Equivalent to `to_vec` but clears self instead of consuming the value.
flush_into_vec(&mut self) -> Vec<u8>125 fn flush_into_vec(&mut self) -> Vec<u8> {
126 self.convert_into_vec::<u8>()
127 }
128
129 // Like flush_into_vec, but also does an unsafe conversion to the desired type.
convert_into_vec<T>(&mut self) -> Vec<T>130 fn convert_into_vec<T>(&mut self) -> Vec<T> {
131 let vec = unsafe {
132 Vec::from_raw_parts(
133 self.data as *mut T,
134 self.length / mem::size_of::<T>(),
135 self.capacity / mem::size_of::<T>(),
136 )
137 };
138 self.data = ptr::null_mut();
139 self.length = 0;
140 self.capacity = 0;
141 vec
142 }
143
from_vec(mut v: Vec<u8>) -> WrVecU8144 fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
145 let w = WrVecU8 {
146 data: v.as_mut_ptr(),
147 length: v.len(),
148 capacity: v.capacity(),
149 };
150 mem::forget(v);
151 w
152 }
153
push_bytes(&mut self, bytes: &[u8])154 fn push_bytes(&mut self, bytes: &[u8]) {
155 let mut vec = self.flush_into_vec();
156 vec.extend_from_slice(bytes);
157 *self = Self::from_vec(vec);
158 }
159 }
160
161
162 #[no_mangle]
wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice)163 pub extern "C" fn wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice) {
164 v.push_bytes(bytes.as_slice());
165 }
166
167 #[no_mangle]
wr_vec_u8_free(v: WrVecU8)168 pub extern "C" fn wr_vec_u8_free(v: WrVecU8) {
169 v.to_vec();
170 }
171
172 #[repr(C)]
173 pub struct ByteSlice {
174 buffer: *const u8,
175 len: usize,
176 }
177
178 impl ByteSlice {
new(slice: &[u8]) -> ByteSlice179 pub fn new(slice: &[u8]) -> ByteSlice {
180 ByteSlice {
181 buffer: slice.as_ptr(),
182 len: slice.len(),
183 }
184 }
185
as_slice(&self) -> &[u8]186 pub fn as_slice(&self) -> &[u8] {
187 make_slice(self.buffer, self.len)
188 }
189 }
190
191 #[repr(C)]
192 pub struct MutByteSlice {
193 buffer: *mut u8,
194 len: usize,
195 }
196
197 impl MutByteSlice {
new(slice: &mut [u8]) -> MutByteSlice198 pub fn new(slice: &mut [u8]) -> MutByteSlice {
199 let len = slice.len();
200 MutByteSlice {
201 buffer: slice.as_mut_ptr(),
202 len: len,
203 }
204 }
205
as_mut_slice(&mut self) -> &mut [u8]206 pub fn as_mut_slice(&mut self) -> &mut [u8] {
207 make_slice_mut(self.buffer, self.len)
208 }
209 }
210
211 #[repr(C)]
212 #[derive(Debug, Clone, Copy)]
213 pub struct WrImageMask {
214 image: WrImageKey,
215 rect: LayoutRect,
216 repeat: bool,
217 }
218
219 impl Into<ImageMask> for WrImageMask {
into(self) -> ImageMask220 fn into(self) -> ImageMask {
221 ImageMask {
222 image: self.image,
223 rect: self.rect.into(),
224 repeat: self.repeat,
225 }
226 }
227 }
228 impl<'a> Into<ImageMask> for &'a WrImageMask {
into(self) -> ImageMask229 fn into(self) -> ImageMask {
230 ImageMask {
231 image: self.image,
232 rect: self.rect.into(),
233 repeat: self.repeat,
234 }
235 }
236 }
237 impl From<ImageMask> for WrImageMask {
from(image_mask: ImageMask) -> Self238 fn from(image_mask: ImageMask) -> Self {
239 WrImageMask {
240 image: image_mask.image,
241 rect: image_mask.rect.into(),
242 repeat: image_mask.repeat,
243 }
244 }
245 }
246
247 #[repr(C)]
248 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
249 pub struct WrImageDescriptor {
250 pub format: ImageFormat,
251 pub width: u32,
252 pub height: u32,
253 pub stride: u32,
254 pub is_opaque: bool,
255 }
256
257 impl<'a> Into<ImageDescriptor> for &'a WrImageDescriptor {
into(self) -> ImageDescriptor258 fn into(self) -> ImageDescriptor {
259 ImageDescriptor {
260 width: self.width,
261 height: self.height,
262 stride: if self.stride != 0 {
263 Some(self.stride)
264 } else {
265 None
266 },
267 format: self.format,
268 is_opaque: self.is_opaque,
269 offset: 0,
270 }
271 }
272 }
273
274 /// cbindgen:field-names=[mHandle]
275 #[repr(C)]
276 #[derive(Copy, Clone)]
277 pub struct WrExternalImageId(pub u64);
278
279 impl Into<ExternalImageId> for WrExternalImageId {
into(self) -> ExternalImageId280 fn into(self) -> ExternalImageId {
281 ExternalImageId(self.0)
282 }
283 }
284 impl Into<WrExternalImageId> for ExternalImageId {
into(self) -> WrExternalImageId285 fn into(self) -> WrExternalImageId {
286 WrExternalImageId(self.0)
287 }
288 }
289
290 #[repr(u32)]
291 #[allow(dead_code)]
292 enum WrExternalImageType {
293 RawData,
294 NativeTexture,
295 Invalid,
296 }
297
298 #[repr(C)]
299 struct WrExternalImage {
300 image_type: WrExternalImageType,
301
302 // external texture handle
303 handle: u32,
304 // external texture coordinate
305 u0: f32,
306 v0: f32,
307 u1: f32,
308 v1: f32,
309
310 // external image buffer
311 buff: *const u8,
312 size: usize,
313 }
314
315 type LockExternalImageCallback = fn(*mut c_void, WrExternalImageId, u8) -> WrExternalImage;
316 type UnlockExternalImageCallback = fn(*mut c_void, WrExternalImageId, u8);
317
318 #[repr(C)]
319 pub struct WrExternalImageHandler {
320 external_image_obj: *mut c_void,
321 lock_func: LockExternalImageCallback,
322 unlock_func: UnlockExternalImageCallback,
323 }
324
325 impl ExternalImageHandler for WrExternalImageHandler {
lock(&mut self, id: ExternalImageId, channel_index: u8) -> ExternalImage326 fn lock(&mut self,
327 id: ExternalImageId,
328 channel_index: u8)
329 -> ExternalImage {
330 let image = (self.lock_func)(self.external_image_obj, id.into(), channel_index);
331 ExternalImage {
332 uv: TexelRect::new(image.u0, image.v0, image.u1, image.v1),
333 source: match image.image_type {
334 WrExternalImageType::NativeTexture => ExternalImageSource::NativeTexture(image.handle),
335 WrExternalImageType::RawData => ExternalImageSource::RawData(make_slice(image.buff, image.size)),
336 WrExternalImageType::Invalid => ExternalImageSource::Invalid,
337 },
338 }
339 }
340
unlock(&mut self, id: ExternalImageId, channel_index: u8)341 fn unlock(&mut self,
342 id: ExternalImageId,
343 channel_index: u8) {
344 (self.unlock_func)(self.external_image_obj, id.into(), channel_index);
345 }
346 }
347
348 #[repr(u32)]
349 pub enum WrAnimationType {
350 Transform = 0,
351 Opacity = 1,
352 }
353
354 #[repr(C)]
355 pub struct WrAnimationProperty {
356 effect_type: WrAnimationType,
357 id: u64,
358 }
359
360 #[repr(u32)]
361 #[derive(Copy, Clone)]
362 pub enum WrFilterOpType {
363 Blur = 0,
364 Brightness = 1,
365 Contrast = 2,
366 Grayscale = 3,
367 HueRotate = 4,
368 Invert = 5,
369 Opacity = 6,
370 Saturate = 7,
371 Sepia = 8,
372 DropShadow = 9,
373 ColorMatrix = 10,
374 }
375
376 #[repr(C)]
377 #[derive(Copy, Clone)]
378 pub struct WrFilterOp {
379 filter_type: WrFilterOpType,
380 argument: c_float, // holds radius for DropShadow; value for other filters
381 offset: LayoutVector2D, // only used for DropShadow
382 color: ColorF, // only used for DropShadow
383 matrix: [f32;20], // only used in ColorMatrix
384 }
385
386 /// cbindgen:derive-eq=false
387 #[repr(C)]
388 #[derive(Debug)]
389 pub struct WrTransformProperty {
390 pub id: u64,
391 pub transform: LayoutTransform,
392 }
393
394 #[repr(C)]
395 #[derive(Copy, Clone, Debug)]
396 pub struct WrOpacityProperty {
397 pub id: u64,
398 pub opacity: f32,
399 }
400
401 /// cbindgen:field-names=[mHandle]
402 /// cbindgen:derive-lt=true
403 /// cbindgen:derive-lte=true
404 #[repr(C)]
405 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
406 pub struct WrWindowId(u64);
407
get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void408 fn get_proc_address(glcontext_ptr: *mut c_void,
409 name: &str)
410 -> *const c_void {
411
412 extern "C" {
413 fn get_proc_address_from_glcontext(glcontext_ptr: *mut c_void,
414 procname: *const c_char)
415 -> *const c_void;
416 }
417
418 let symbol_name = CString::new(name).unwrap();
419 let symbol = unsafe { get_proc_address_from_glcontext(glcontext_ptr, symbol_name.as_ptr()) };
420
421 // For now panic, not sure we should be though or if we can recover
422 if symbol.is_null() {
423 // XXX Bug 1322949 Make whitelist for extensions
424 println!("Could not find symbol {:?} by glcontext", symbol_name);
425 }
426
427 symbol as *const _
428 }
429
430 extern "C" {
is_in_compositor_thread() -> bool431 fn is_in_compositor_thread() -> bool;
is_in_render_thread() -> bool432 fn is_in_render_thread() -> bool;
is_in_main_thread() -> bool433 fn is_in_main_thread() -> bool;
is_glcontext_egl(glcontext_ptr: *mut c_void) -> bool434 fn is_glcontext_egl(glcontext_ptr: *mut c_void) -> bool;
is_glcontext_angle(glcontext_ptr: *mut c_void) -> bool435 fn is_glcontext_angle(glcontext_ptr: *mut c_void) -> bool;
436 // Enables binary recording that can be used with `wrench replay`
437 // Outputs a wr-record-*.bin file for each window that is shown
438 // Note: wrench will panic if external images are used, they can
439 // be disabled in WebRenderBridgeParent::ProcessWebRenderCommands
440 // by commenting out the path that adds an external image ID
gfx_use_wrench() -> bool441 fn gfx_use_wrench() -> bool;
gfx_wr_resource_path_override() -> *const c_char442 fn gfx_wr_resource_path_override() -> *const c_char;
443 // TODO: make gfx_critical_error() work.
444 // We still have problem to pass the error message from render/render_backend
445 // thread to main thread now.
446 #[allow(dead_code)]
gfx_critical_error(msg: *const c_char)447 fn gfx_critical_error(msg: *const c_char);
gfx_critical_note(msg: *const c_char)448 fn gfx_critical_note(msg: *const c_char);
gecko_printf_stderr_output(msg: *const c_char)449 fn gecko_printf_stderr_output(msg: *const c_char);
450 }
451
452 struct CppNotifier {
453 window_id: WrWindowId,
454 }
455
456 unsafe impl Send for CppNotifier {}
457
458 extern "C" {
wr_notifier_wake_up(window_id: WrWindowId)459 fn wr_notifier_wake_up(window_id: WrWindowId);
wr_notifier_new_frame_ready(window_id: WrWindowId)460 fn wr_notifier_new_frame_ready(window_id: WrWindowId);
wr_notifier_new_scroll_frame_ready(window_id: WrWindowId, composite_needed: bool)461 fn wr_notifier_new_scroll_frame_ready(window_id: WrWindowId,
462 composite_needed: bool);
wr_notifier_external_event(window_id: WrWindowId, raw_event: usize)463 fn wr_notifier_external_event(window_id: WrWindowId,
464 raw_event: usize);
465 }
466
467 impl RenderNotifier for CppNotifier {
clone(&self) -> Box<RenderNotifier>468 fn clone(&self) -> Box<RenderNotifier> {
469 Box::new(CppNotifier {
470 window_id: self.window_id,
471 })
472 }
473
wake_up(&self)474 fn wake_up(&self) {
475 unsafe {
476 wr_notifier_wake_up(self.window_id);
477 }
478 }
479
new_document_ready(&self, _: DocumentId, scrolled: bool, composite_needed: bool)480 fn new_document_ready(&self,
481 _: DocumentId,
482 scrolled: bool,
483 composite_needed: bool) {
484 unsafe {
485 if scrolled {
486 wr_notifier_new_scroll_frame_ready(self.window_id, composite_needed);
487 } else if composite_needed {
488 wr_notifier_new_frame_ready(self.window_id);
489 }
490 }
491 }
492
external_event(&self, event: ExternalEvent)493 fn external_event(&self,
494 event: ExternalEvent) {
495 unsafe {
496 wr_notifier_external_event(self.window_id, event.unwrap());
497 }
498 }
499 }
500
501 #[no_mangle]
wr_renderer_set_external_image_handler(renderer: &mut Renderer, external_image_handler: *mut WrExternalImageHandler)502 pub extern "C" fn wr_renderer_set_external_image_handler(renderer: &mut Renderer,
503 external_image_handler: *mut WrExternalImageHandler) {
504 if !external_image_handler.is_null() {
505 renderer.set_external_image_handler(Box::new(unsafe {
506 WrExternalImageHandler {
507 external_image_obj:
508 (*external_image_handler).external_image_obj,
509 lock_func: (*external_image_handler).lock_func,
510 unlock_func: (*external_image_handler).unlock_func,
511 }
512 }));
513 }
514 }
515
516 #[no_mangle]
wr_renderer_update(renderer: &mut Renderer)517 pub extern "C" fn wr_renderer_update(renderer: &mut Renderer) {
518 renderer.update();
519 }
520
521 #[no_mangle]
wr_renderer_render(renderer: &mut Renderer, width: u32, height: u32) -> bool522 pub extern "C" fn wr_renderer_render(renderer: &mut Renderer,
523 width: u32,
524 height: u32) -> bool {
525 match renderer.render(DeviceUintSize::new(width, height)) {
526 Ok(_) => true,
527 Err(errors) => {
528 for e in errors {
529 println!(" Failed to render: {:?}", e);
530 let msg = CString::new(format!("wr_renderer_render: {:?}", e)).unwrap();
531 unsafe {
532 gfx_critical_note(msg.as_ptr());
533 }
534 }
535 false
536 },
537 }
538 }
539
540 // Call wr_renderer_render() before calling this function.
541 #[no_mangle]
wr_renderer_readback(renderer: &mut Renderer, width: u32, height: u32, dst_buffer: *mut u8, buffer_size: usize)542 pub unsafe extern "C" fn wr_renderer_readback(renderer: &mut Renderer,
543 width: u32,
544 height: u32,
545 dst_buffer: *mut u8,
546 buffer_size: usize) {
547 assert!(is_in_render_thread());
548
549 let mut slice = make_slice_mut(dst_buffer, buffer_size);
550 renderer.read_pixels_into(DeviceUintRect::new(
551 DeviceUintPoint::new(0, 0),
552 DeviceUintSize::new(width, height)),
553 ReadPixelsFormat::Standard(ImageFormat::BGRA8),
554 &mut slice);
555 }
556
557 /// cbindgen:field-names=[mBits]
558 #[repr(C)]
559 pub struct WrDebugFlags {
560 bits: u32,
561 }
562
563 #[no_mangle]
wr_renderer_get_debug_flags(renderer: &mut Renderer) -> WrDebugFlags564 pub extern "C" fn wr_renderer_get_debug_flags(renderer: &mut Renderer) -> WrDebugFlags {
565 WrDebugFlags { bits: renderer.get_debug_flags().bits() }
566 }
567
568 #[no_mangle]
wr_renderer_set_debug_flags(renderer: &mut Renderer, flags: WrDebugFlags)569 pub extern "C" fn wr_renderer_set_debug_flags(renderer: &mut Renderer, flags: WrDebugFlags) {
570 if let Some(dbg_flags) = DebugFlags::from_bits(flags.bits) {
571 renderer.set_debug_flags(dbg_flags);
572 }
573 }
574
575 #[no_mangle]
wr_renderer_current_epoch(renderer: &mut Renderer, pipeline_id: WrPipelineId, out_epoch: &mut WrEpoch) -> bool576 pub extern "C" fn wr_renderer_current_epoch(renderer: &mut Renderer,
577 pipeline_id: WrPipelineId,
578 out_epoch: &mut WrEpoch)
579 -> bool {
580 if let Some(epoch) = renderer.current_epoch(pipeline_id) {
581 *out_epoch = epoch;
582 return true;
583 }
584 return false;
585 }
586
587 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
588 #[no_mangle]
wr_renderer_delete(renderer: *mut Renderer)589 pub unsafe extern "C" fn wr_renderer_delete(renderer: *mut Renderer) {
590 let renderer = Box::from_raw(renderer);
591 renderer.deinit();
592 // let renderer go out of scope and get dropped
593 }
594
595 pub struct WrPipelineInfo {
596 epochs: Vec<(WrPipelineId, WrEpoch)>,
597 removed_pipelines: Vec<PipelineId>,
598 }
599
600 #[no_mangle]
wr_renderer_flush_pipeline_info(renderer: &mut Renderer) -> *mut WrPipelineInfo601 pub unsafe extern "C" fn wr_renderer_flush_pipeline_info(renderer: &mut Renderer) -> *mut WrPipelineInfo {
602 let info = renderer.flush_pipeline_info();
603 let pipeline_epochs = Box::new(
604 WrPipelineInfo {
605 epochs: info.epochs.into_iter().collect(),
606 removed_pipelines: info.removed_pipelines,
607 }
608 );
609 return Box::into_raw(pipeline_epochs);
610 }
611
612 #[no_mangle]
wr_pipeline_info_next_epoch( info: &mut WrPipelineInfo, out_pipeline: &mut WrPipelineId, out_epoch: &mut WrEpoch ) -> bool613 pub unsafe extern "C" fn wr_pipeline_info_next_epoch(
614 info: &mut WrPipelineInfo,
615 out_pipeline: &mut WrPipelineId,
616 out_epoch: &mut WrEpoch
617 ) -> bool {
618 if let Some((pipeline, epoch)) = info.epochs.pop() {
619 *out_pipeline = pipeline;
620 *out_epoch = epoch;
621 return true;
622 }
623 return false;
624 }
625
626 #[no_mangle]
wr_pipeline_info_next_removed_pipeline( info: &mut WrPipelineInfo, out_pipeline: &mut WrPipelineId, ) -> bool627 pub unsafe extern "C" fn wr_pipeline_info_next_removed_pipeline(
628 info: &mut WrPipelineInfo,
629 out_pipeline: &mut WrPipelineId,
630 ) -> bool {
631 if let Some(pipeline) = info.removed_pipelines.pop() {
632 *out_pipeline = pipeline;
633 return true;
634 }
635 return false;
636 }
637
638 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
639 #[no_mangle]
wr_pipeline_info_delete(info: *mut WrPipelineInfo)640 pub unsafe extern "C" fn wr_pipeline_info_delete(info: *mut WrPipelineInfo) {
641 Box::from_raw(info);
642 }
643
644 extern "C" {
gecko_profiler_register_thread(name: *const ::std::os::raw::c_char)645 fn gecko_profiler_register_thread(name: *const ::std::os::raw::c_char);
gecko_profiler_unregister_thread()646 fn gecko_profiler_unregister_thread();
647 }
648
649 struct GeckoProfilerThreadListener {}
650
651 impl GeckoProfilerThreadListener {
new() -> GeckoProfilerThreadListener652 pub fn new() -> GeckoProfilerThreadListener {
653 GeckoProfilerThreadListener{}
654 }
655 }
656
657 impl ThreadListener for GeckoProfilerThreadListener {
thread_started(&self, thread_name: &str)658 fn thread_started(&self, thread_name: &str) {
659 let name = CString::new(thread_name).unwrap();
660 unsafe {
661 // gecko_profiler_register_thread copies the passed name here.
662 gecko_profiler_register_thread(name.as_ptr());
663 }
664 }
665
thread_stopped(&self, _: &str)666 fn thread_stopped(&self, _: &str) {
667 unsafe {
668 gecko_profiler_unregister_thread();
669 }
670 }
671 }
672
673 pub struct WrThreadPool(Arc<rayon::ThreadPool>);
674
675 #[no_mangle]
wr_thread_pool_new() -> *mut WrThreadPool676 pub unsafe extern "C" fn wr_thread_pool_new() -> *mut WrThreadPool {
677 let worker = rayon::ThreadPoolBuilder::new()
678 .thread_name(|idx|{ format!("WRWorker#{}", idx) })
679 .start_handler(|idx| {
680 let name = format!("WRWorker#{}", idx);
681 register_thread_with_profiler(name.clone());
682 gecko_profiler_register_thread(CString::new(name).unwrap().as_ptr());
683 })
684 .exit_handler(|_idx| {
685 gecko_profiler_unregister_thread();
686 })
687 .build();
688
689 let workers = Arc::new(worker.unwrap());
690
691 Box::into_raw(Box::new(WrThreadPool(workers)))
692 }
693
694 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
695 #[no_mangle]
wr_thread_pool_delete(thread_pool: *mut WrThreadPool)696 pub unsafe extern "C" fn wr_thread_pool_delete(thread_pool: *mut WrThreadPool) {
697 Box::from_raw(thread_pool);
698 }
699
700 pub struct WrProgramCache(Rc<ProgramCache>);
701
702 #[no_mangle]
wr_program_cache_new() -> *mut WrProgramCache703 pub unsafe extern "C" fn wr_program_cache_new() -> *mut WrProgramCache {
704 let program_cache = ProgramCache::new();
705 Box::into_raw(Box::new(WrProgramCache(program_cache)))
706 }
707
708 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
709 #[no_mangle]
wr_program_cache_delete(program_cache: *mut WrProgramCache)710 pub unsafe extern "C" fn wr_program_cache_delete(program_cache: *mut WrProgramCache) {
711 Rc::from_raw(program_cache);
712 }
713
714 #[no_mangle]
wr_renderer_update_program_cache(renderer: &mut Renderer, program_cache: &mut WrProgramCache)715 pub extern "C" fn wr_renderer_update_program_cache(renderer: &mut Renderer, program_cache: &mut WrProgramCache) {
716 let program_cache = Rc::clone(&program_cache.0);
717 renderer.update_program_cache(program_cache);
718 }
719
720 // Call MakeCurrent before this.
721 #[no_mangle]
wr_window_new(window_id: WrWindowId, window_width: u32, window_height: u32, gl_context: *mut c_void, thread_pool: *mut WrThreadPool, out_handle: &mut *mut DocumentHandle, out_renderer: &mut *mut Renderer, out_max_texture_size: *mut u32) -> bool722 pub extern "C" fn wr_window_new(window_id: WrWindowId,
723 window_width: u32,
724 window_height: u32,
725 gl_context: *mut c_void,
726 thread_pool: *mut WrThreadPool,
727 out_handle: &mut *mut DocumentHandle,
728 out_renderer: &mut *mut Renderer,
729 out_max_texture_size: *mut u32)
730 -> bool {
731 assert!(unsafe { is_in_render_thread() });
732
733 let recorder: Option<Box<ApiRecordingReceiver>> = if unsafe { gfx_use_wrench() } {
734 let name = format!("wr-record-{}.bin", window_id.0);
735 Some(Box::new(BinaryRecorder::new(&PathBuf::from(name))))
736 } else {
737 None
738 };
739
740 let gl;
741 if unsafe { is_glcontext_egl(gl_context) } {
742 gl = unsafe { gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
743 } else {
744 gl = unsafe { gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
745 }
746 gl.clear_color(0.0, 0.0, 0.0, 1.0);
747
748 let version = gl.get_string(gl::VERSION);
749
750 println!("WebRender - OpenGL version new {}", version);
751
752 let workers = unsafe {
753 Arc::clone(&(*thread_pool).0)
754 };
755
756 let upload_method = if unsafe { is_glcontext_angle(gl_context) } {
757 UploadMethod::Immediate
758 } else {
759 UploadMethod::PixelBuffer(VertexUsageHint::Dynamic)
760 };
761
762 let opts = RendererOptions {
763 enable_aa: true,
764 enable_subpixel_aa: true,
765 recorder: recorder,
766 blob_image_renderer: Some(Box::new(Moz2dImageRenderer::new(workers.clone()))),
767 workers: Some(workers.clone()),
768 thread_listener: Some(Box::new(GeckoProfilerThreadListener::new())),
769 enable_render_on_scroll: false,
770 resource_override_path: unsafe {
771 let override_charptr = gfx_wr_resource_path_override();
772 if override_charptr.is_null() {
773 None
774 } else {
775 match CStr::from_ptr(override_charptr).to_str() {
776 Ok(override_str) => Some(PathBuf::from(override_str)),
777 _ => None
778 }
779 }
780 },
781 renderer_id: Some(window_id.0),
782 upload_method,
783 ..Default::default()
784 };
785
786 let notifier = Box::new(CppNotifier {
787 window_id: window_id,
788 });
789 let (renderer, sender) = match Renderer::new(gl, notifier, opts) {
790 Ok((renderer, sender)) => (renderer, sender),
791 Err(e) => {
792 println!(" Failed to create a Renderer: {:?}", e);
793 let msg = CString::new(format!("wr_window_new: {:?}", e)).unwrap();
794 unsafe {
795 gfx_critical_note(msg.as_ptr());
796 }
797 return false;
798 },
799 };
800
801 unsafe {
802 *out_max_texture_size = renderer.get_max_texture_size();
803 }
804 let window_size = DeviceUintSize::new(window_width, window_height);
805 let layer = 0;
806 *out_handle = Box::into_raw(Box::new(
807 DocumentHandle::new(sender.create_api(), window_size, layer)));
808 *out_renderer = Box::into_raw(Box::new(renderer));
809
810 return true;
811 }
812
813 #[no_mangle]
wr_api_create_document( root_dh: &mut DocumentHandle, out_handle: &mut *mut DocumentHandle, doc_size: DeviceUintSize, layer: i8, )814 pub extern "C" fn wr_api_create_document(
815 root_dh: &mut DocumentHandle,
816 out_handle: &mut *mut DocumentHandle,
817 doc_size: DeviceUintSize,
818 layer: i8,
819 ) {
820 assert!(unsafe { is_in_compositor_thread() });
821
822 *out_handle = Box::into_raw(Box::new(DocumentHandle::new(
823 root_dh.api.clone_sender().create_api(),
824 doc_size,
825 layer
826 )));
827 }
828
829 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
830 #[no_mangle]
wr_api_delete_document(dh: &mut DocumentHandle)831 pub unsafe extern "C" fn wr_api_delete_document(dh: &mut DocumentHandle) {
832 dh.api.delete_document(dh.document_id);
833 }
834
835 #[no_mangle]
wr_api_clone( dh: &mut DocumentHandle, out_handle: &mut *mut DocumentHandle )836 pub extern "C" fn wr_api_clone(
837 dh: &mut DocumentHandle,
838 out_handle: &mut *mut DocumentHandle
839 ) {
840 assert!(unsafe { is_in_compositor_thread() });
841
842 let handle = DocumentHandle {
843 api: dh.api.clone_sender().create_api(),
844 document_id: dh.document_id,
845 };
846 *out_handle = Box::into_raw(Box::new(handle));
847 }
848
849 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
850 #[no_mangle]
wr_api_delete(dh: *mut DocumentHandle)851 pub unsafe extern "C" fn wr_api_delete(dh: *mut DocumentHandle) {
852 let _ = Box::from_raw(dh);
853 }
854
855 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
856 #[no_mangle]
wr_api_shut_down(dh: &mut DocumentHandle)857 pub unsafe extern "C" fn wr_api_shut_down(dh: &mut DocumentHandle) {
858 dh.api.shut_down();
859 }
860
861 #[no_mangle]
wr_transaction_new() -> *mut Transaction862 pub extern "C" fn wr_transaction_new() -> *mut Transaction {
863 Box::into_raw(Box::new(Transaction::new()))
864 }
865
866 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
867 #[no_mangle]
wr_transaction_delete(txn: *mut Transaction)868 pub extern "C" fn wr_transaction_delete(txn: *mut Transaction) {
869 unsafe { let _ = Box::from_raw(txn); }
870 }
871
872 #[no_mangle]
wr_transaction_is_empty(txn: &Transaction) -> bool873 pub extern "C" fn wr_transaction_is_empty(txn: &Transaction) -> bool {
874 txn.is_empty()
875 }
876
877 #[no_mangle]
wr_transaction_update_epoch( txn: &mut Transaction, pipeline_id: WrPipelineId, epoch: WrEpoch, )878 pub extern "C" fn wr_transaction_update_epoch(
879 txn: &mut Transaction,
880 pipeline_id: WrPipelineId,
881 epoch: WrEpoch,
882 ) {
883 txn.update_epoch(pipeline_id, epoch);
884 }
885
886 #[no_mangle]
wr_transaction_set_root_pipeline( txn: &mut Transaction, pipeline_id: WrPipelineId, )887 pub extern "C" fn wr_transaction_set_root_pipeline(
888 txn: &mut Transaction,
889 pipeline_id: WrPipelineId,
890 ) {
891 txn.set_root_pipeline(pipeline_id);
892 }
893
894 #[no_mangle]
wr_transaction_remove_pipeline( txn: &mut Transaction, pipeline_id: WrPipelineId, )895 pub extern "C" fn wr_transaction_remove_pipeline(
896 txn: &mut Transaction,
897 pipeline_id: WrPipelineId,
898 ) {
899 txn.remove_pipeline(pipeline_id);
900 }
901
902 #[no_mangle]
wr_transaction_set_display_list( txn: &mut Transaction, epoch: WrEpoch, background: ColorF, viewport_width: f32, viewport_height: f32, pipeline_id: WrPipelineId, content_size: LayoutSize, dl_descriptor: BuiltDisplayListDescriptor, dl_data: &mut WrVecU8, )903 pub extern "C" fn wr_transaction_set_display_list(
904 txn: &mut Transaction,
905 epoch: WrEpoch,
906 background: ColorF,
907 viewport_width: f32,
908 viewport_height: f32,
909 pipeline_id: WrPipelineId,
910 content_size: LayoutSize,
911 dl_descriptor: BuiltDisplayListDescriptor,
912 dl_data: &mut WrVecU8,
913 ) {
914 let color = if background.a == 0.0 { None } else { Some(background) };
915
916 // See the documentation of set_display_list in api.rs. I don't think
917 // it makes a difference in gecko at the moment(until APZ is figured out)
918 // but I suppose it is a good default.
919 let preserve_frame_state = true;
920
921 let dl_vec = dl_data.flush_into_vec();
922 let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
923
924 txn.set_display_list(
925 epoch,
926 color,
927 LayoutSize::new(viewport_width, viewport_height),
928 (pipeline_id, content_size, dl),
929 preserve_frame_state,
930 );
931 }
932
933 #[no_mangle]
wr_transaction_update_resources( txn: &mut Transaction, resource_updates: &mut ResourceUpdates )934 pub extern "C" fn wr_transaction_update_resources(
935 txn: &mut Transaction,
936 resource_updates: &mut ResourceUpdates
937 ) {
938 if resource_updates.updates.is_empty() {
939 return;
940 }
941 txn.update_resources(mem::replace(resource_updates, ResourceUpdates::new()));
942 }
943
944 #[no_mangle]
wr_transaction_set_window_parameters( txn: &mut Transaction, window_size: &DeviceUintSize, doc_rect: &DeviceUintRect, )945 pub extern "C" fn wr_transaction_set_window_parameters(
946 txn: &mut Transaction,
947 window_size: &DeviceUintSize,
948 doc_rect: &DeviceUintRect,
949 ) {
950 txn.set_window_parameters(
951 *window_size,
952 *doc_rect,
953 1.0,
954 );
955 }
956
957 #[no_mangle]
wr_transaction_generate_frame(txn: &mut Transaction)958 pub extern "C" fn wr_transaction_generate_frame(txn: &mut Transaction) {
959 txn.generate_frame();
960 }
961
962 #[no_mangle]
wr_transaction_update_dynamic_properties( txn: &mut Transaction, opacity_array: *const WrOpacityProperty, opacity_count: usize, transform_array: *const WrTransformProperty, transform_count: usize, )963 pub extern "C" fn wr_transaction_update_dynamic_properties(
964 txn: &mut Transaction,
965 opacity_array: *const WrOpacityProperty,
966 opacity_count: usize,
967 transform_array: *const WrTransformProperty,
968 transform_count: usize,
969 ) {
970 debug_assert!(transform_count > 0 || opacity_count > 0);
971
972 let mut properties = DynamicProperties {
973 transforms: Vec::new(),
974 floats: Vec::new(),
975 };
976
977 if transform_count > 0 {
978 let transform_slice = make_slice(transform_array, transform_count);
979
980 for element in transform_slice.iter() {
981 let prop = PropertyValue {
982 key: PropertyBindingKey::new(element.id),
983 value: element.transform.into(),
984 };
985
986 properties.transforms.push(prop);
987 }
988 }
989
990 if opacity_count > 0 {
991 let opacity_slice = make_slice(opacity_array, opacity_count);
992
993 for element in opacity_slice.iter() {
994 let prop = PropertyValue {
995 key: PropertyBindingKey::new(element.id),
996 value: element.opacity,
997 };
998 properties.floats.push(prop);
999 }
1000 }
1001
1002 txn.update_dynamic_properties(properties);
1003 }
1004
1005 #[no_mangle]
wr_transaction_scroll_layer( txn: &mut Transaction, pipeline_id: WrPipelineId, scroll_id: u64, new_scroll_origin: LayoutPoint )1006 pub extern "C" fn wr_transaction_scroll_layer(
1007 txn: &mut Transaction,
1008 pipeline_id: WrPipelineId,
1009 scroll_id: u64,
1010 new_scroll_origin: LayoutPoint
1011 ) {
1012 assert!(unsafe { is_in_compositor_thread() });
1013 let scroll_id = ExternalScrollId(scroll_id, pipeline_id);
1014 txn.scroll_node_with_id(new_scroll_origin, scroll_id, ScrollClamping::NoClamping);
1015 }
1016
1017 #[no_mangle]
wr_resource_updates_add_image( resources: &mut ResourceUpdates, image_key: WrImageKey, descriptor: &WrImageDescriptor, bytes: &mut WrVecU8, )1018 pub extern "C" fn wr_resource_updates_add_image(
1019 resources: &mut ResourceUpdates,
1020 image_key: WrImageKey,
1021 descriptor: &WrImageDescriptor,
1022 bytes: &mut WrVecU8,
1023 ) {
1024 resources.add_image(
1025 image_key,
1026 descriptor.into(),
1027 ImageData::new(bytes.flush_into_vec()),
1028 None
1029 );
1030 }
1031
1032 #[no_mangle]
wr_resource_updates_add_blob_image( resources: &mut ResourceUpdates, image_key: WrImageKey, descriptor: &WrImageDescriptor, bytes: &mut WrVecU8, )1033 pub extern "C" fn wr_resource_updates_add_blob_image(
1034 resources: &mut ResourceUpdates,
1035 image_key: WrImageKey,
1036 descriptor: &WrImageDescriptor,
1037 bytes: &mut WrVecU8,
1038 ) {
1039 resources.add_image(
1040 image_key,
1041 descriptor.into(),
1042 ImageData::new_blob_image(bytes.flush_into_vec()),
1043 None
1044 );
1045 }
1046
1047 #[no_mangle]
wr_resource_updates_add_external_image( resources: &mut ResourceUpdates, image_key: WrImageKey, descriptor: &WrImageDescriptor, external_image_id: WrExternalImageId, buffer_type: WrExternalImageBufferType, channel_index: u8 )1048 pub extern "C" fn wr_resource_updates_add_external_image(
1049 resources: &mut ResourceUpdates,
1050 image_key: WrImageKey,
1051 descriptor: &WrImageDescriptor,
1052 external_image_id: WrExternalImageId,
1053 buffer_type: WrExternalImageBufferType,
1054 channel_index: u8
1055 ) {
1056 resources.add_image(
1057 image_key,
1058 descriptor.into(),
1059 ImageData::External(
1060 ExternalImageData {
1061 id: external_image_id.into(),
1062 channel_index: channel_index,
1063 image_type: buffer_type.to_wr(),
1064 }
1065 ),
1066 None
1067 );
1068 }
1069
1070 #[no_mangle]
wr_resource_updates_update_image( resources: &mut ResourceUpdates, key: WrImageKey, descriptor: &WrImageDescriptor, bytes: &mut WrVecU8, )1071 pub extern "C" fn wr_resource_updates_update_image(
1072 resources: &mut ResourceUpdates,
1073 key: WrImageKey,
1074 descriptor: &WrImageDescriptor,
1075 bytes: &mut WrVecU8,
1076 ) {
1077 resources.update_image(
1078 key,
1079 descriptor.into(),
1080 ImageData::new(bytes.flush_into_vec()),
1081 None
1082 );
1083 }
1084
1085 #[no_mangle]
wr_resource_updates_update_external_image( resources: &mut ResourceUpdates, key: WrImageKey, descriptor: &WrImageDescriptor, external_image_id: WrExternalImageId, image_type: WrExternalImageBufferType, channel_index: u8 )1086 pub extern "C" fn wr_resource_updates_update_external_image(
1087 resources: &mut ResourceUpdates,
1088 key: WrImageKey,
1089 descriptor: &WrImageDescriptor,
1090 external_image_id: WrExternalImageId,
1091 image_type: WrExternalImageBufferType,
1092 channel_index: u8
1093 ) {
1094 resources.update_image(
1095 key,
1096 descriptor.into(),
1097 ImageData::External(
1098 ExternalImageData {
1099 id: external_image_id.into(),
1100 channel_index,
1101 image_type: image_type.to_wr(),
1102 }
1103 ),
1104 None
1105 );
1106 }
1107
1108 #[no_mangle]
wr_resource_updates_update_blob_image( resources: &mut ResourceUpdates, image_key: WrImageKey, descriptor: &WrImageDescriptor, bytes: &mut WrVecU8, dirty_rect: DeviceUintRect, )1109 pub extern "C" fn wr_resource_updates_update_blob_image(
1110 resources: &mut ResourceUpdates,
1111 image_key: WrImageKey,
1112 descriptor: &WrImageDescriptor,
1113 bytes: &mut WrVecU8,
1114 dirty_rect: DeviceUintRect,
1115 ) {
1116 resources.update_image(
1117 image_key,
1118 descriptor.into(),
1119 ImageData::new_blob_image(bytes.flush_into_vec()),
1120 Some(dirty_rect)
1121 );
1122 }
1123
1124 #[no_mangle]
wr_resource_updates_delete_image( resources: &mut ResourceUpdates, key: WrImageKey )1125 pub extern "C" fn wr_resource_updates_delete_image(
1126 resources: &mut ResourceUpdates,
1127 key: WrImageKey
1128 ) {
1129 resources.delete_image(key);
1130 }
1131
1132 #[no_mangle]
wr_api_send_transaction( dh: &mut DocumentHandle, transaction: &mut Transaction )1133 pub extern "C" fn wr_api_send_transaction(
1134 dh: &mut DocumentHandle,
1135 transaction: &mut Transaction
1136 ) {
1137 if transaction.is_empty() {
1138 return;
1139 }
1140 let txn = mem::replace(transaction, Transaction::new());
1141 dh.api.send_transaction(dh.document_id, txn);
1142 }
1143
1144 #[no_mangle]
wr_transaction_clear_display_list( txn: &mut Transaction, epoch: WrEpoch, pipeline_id: WrPipelineId, )1145 pub unsafe extern "C" fn wr_transaction_clear_display_list(
1146 txn: &mut Transaction,
1147 epoch: WrEpoch,
1148 pipeline_id: WrPipelineId,
1149 ) {
1150 let preserve_frame_state = true;
1151 let frame_builder = WebRenderFrameBuilder::new(pipeline_id, LayoutSize::zero());
1152
1153 txn.set_display_list(
1154 epoch,
1155 None,
1156 LayoutSize::new(0.0, 0.0),
1157 frame_builder.dl_builder.finalize(),
1158 preserve_frame_state,
1159 );
1160 }
1161
1162 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
1163 #[no_mangle]
wr_api_send_external_event(dh: &mut DocumentHandle, evt: usize)1164 pub extern "C" fn wr_api_send_external_event(dh: &mut DocumentHandle,
1165 evt: usize) {
1166 assert!(unsafe { !is_in_render_thread() });
1167
1168 dh.api.send_external_event(ExternalEvent::from_raw(evt));
1169 }
1170
1171 #[no_mangle]
wr_resource_updates_add_raw_font( resources: &mut ResourceUpdates, key: WrFontKey, bytes: &mut WrVecU8, index: u32 )1172 pub extern "C" fn wr_resource_updates_add_raw_font(
1173 resources: &mut ResourceUpdates,
1174 key: WrFontKey,
1175 bytes: &mut WrVecU8,
1176 index: u32
1177 ) {
1178 resources.add_raw_font(key, bytes.flush_into_vec(), index);
1179 }
1180
1181 #[no_mangle]
wr_api_capture( dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32, )1182 pub extern "C" fn wr_api_capture(
1183 dh: &mut DocumentHandle,
1184 path: *const c_char,
1185 bits_raw: u32,
1186 ) {
1187 use std::fs::{File, create_dir_all};
1188 use std::io::Write;
1189
1190 let cstr = unsafe { CStr::from_ptr(path) };
1191 let path = PathBuf::from(&*cstr.to_string_lossy());
1192
1193 let _ = create_dir_all(&path);
1194 match File::create(path.join("wr.txt")) {
1195 Ok(mut file) => {
1196 let revision = include_bytes!("../revision.txt");
1197 file.write(revision).unwrap();
1198 }
1199 Err(e) => {
1200 println!("Unable to create path '{:?}' for capture: {:?}", path, e);
1201 return
1202 }
1203 }
1204
1205 let bits = CaptureBits::from_bits(bits_raw as _).unwrap();
1206 dh.api.save_capture(path, bits);
1207 }
1208
1209 #[cfg(target_os = "windows")]
read_font_descriptor( bytes: &mut WrVecU8, index: u32 ) -> NativeFontHandle1210 fn read_font_descriptor(
1211 bytes: &mut WrVecU8,
1212 index: u32
1213 ) -> NativeFontHandle {
1214 let wchars = bytes.convert_into_vec::<u16>();
1215 FontDescriptor {
1216 family_name: String::from_utf16(&wchars).unwrap(),
1217 weight: FontWeight::from_u32(index & 0xffff),
1218 stretch: FontStretch::from_u32((index >> 16) & 0xff),
1219 style: FontStyle::from_u32((index >> 24) & 0xff),
1220 }
1221 }
1222
1223 #[cfg(target_os = "macos")]
read_font_descriptor( bytes: &mut WrVecU8, _index: u32 ) -> NativeFontHandle1224 fn read_font_descriptor(
1225 bytes: &mut WrVecU8,
1226 _index: u32
1227 ) -> NativeFontHandle {
1228 let chars = bytes.flush_into_vec();
1229 let name = String::from_utf8(chars).unwrap();
1230 let font = CGFont::from_name(&CFString::new(&*name)).unwrap();
1231 NativeFontHandle(font)
1232 }
1233
1234 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
read_font_descriptor( bytes: &mut WrVecU8, index: u32 ) -> NativeFontHandle1235 fn read_font_descriptor(
1236 bytes: &mut WrVecU8,
1237 index: u32
1238 ) -> NativeFontHandle {
1239 let cstr = CString::new(bytes.flush_into_vec()).unwrap();
1240 NativeFontHandle {
1241 pathname: String::from(cstr.to_str().unwrap()),
1242 index,
1243 }
1244 }
1245
1246 #[no_mangle]
wr_resource_updates_add_font_descriptor( resources: &mut ResourceUpdates, key: WrFontKey, bytes: &mut WrVecU8, index: u32 )1247 pub extern "C" fn wr_resource_updates_add_font_descriptor(
1248 resources: &mut ResourceUpdates,
1249 key: WrFontKey,
1250 bytes: &mut WrVecU8,
1251 index: u32
1252 ) {
1253 let native_font_handle = read_font_descriptor(bytes, index);
1254 resources.add_native_font(key, native_font_handle);
1255 }
1256
1257 #[no_mangle]
wr_resource_updates_delete_font( resources: &mut ResourceUpdates, key: WrFontKey )1258 pub extern "C" fn wr_resource_updates_delete_font(
1259 resources: &mut ResourceUpdates,
1260 key: WrFontKey
1261 ) {
1262 resources.delete_font(key);
1263 }
1264
1265 #[no_mangle]
wr_resource_updates_add_font_instance( resources: &mut ResourceUpdates, key: WrFontInstanceKey, font_key: WrFontKey, glyph_size: f32, options: *const FontInstanceOptions, platform_options: *const FontInstancePlatformOptions, variations: &mut WrVecU8, )1266 pub extern "C" fn wr_resource_updates_add_font_instance(
1267 resources: &mut ResourceUpdates,
1268 key: WrFontInstanceKey,
1269 font_key: WrFontKey,
1270 glyph_size: f32,
1271 options: *const FontInstanceOptions,
1272 platform_options: *const FontInstancePlatformOptions,
1273 variations: &mut WrVecU8,
1274 ) {
1275 resources.add_font_instance(
1276 key,
1277 font_key,
1278 Au::from_f32_px(glyph_size),
1279 unsafe { options.as_ref().cloned() },
1280 unsafe { platform_options.as_ref().cloned() },
1281 variations.convert_into_vec::<FontVariation>(),
1282 );
1283 }
1284
1285 #[no_mangle]
wr_resource_updates_delete_font_instance( resources: &mut ResourceUpdates, key: WrFontInstanceKey )1286 pub extern "C" fn wr_resource_updates_delete_font_instance(
1287 resources: &mut ResourceUpdates,
1288 key: WrFontInstanceKey
1289 ) {
1290 resources.delete_font_instance(key);
1291 }
1292
1293 #[no_mangle]
wr_resource_updates_new() -> *mut ResourceUpdates1294 pub extern "C" fn wr_resource_updates_new() -> *mut ResourceUpdates {
1295 let updates = Box::new(ResourceUpdates::new());
1296 Box::into_raw(updates)
1297 }
1298
1299 #[no_mangle]
wr_resource_updates_clear(resources: &mut ResourceUpdates)1300 pub extern "C" fn wr_resource_updates_clear(resources: &mut ResourceUpdates) {
1301 resources.updates.clear();
1302 }
1303
1304 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
1305 #[no_mangle]
wr_resource_updates_delete(updates: *mut ResourceUpdates)1306 pub extern "C" fn wr_resource_updates_delete(updates: *mut ResourceUpdates) {
1307 unsafe {
1308 Box::from_raw(updates);
1309 }
1310 }
1311
1312 #[no_mangle]
wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace1313 pub unsafe extern "C" fn wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace {
1314 dh.api.get_namespace_id()
1315 }
1316
1317 // RenderThread WIP notes:
1318 // In order to separate the compositor thread (or ipc receiver) and the render
1319 // thread, some of the logic below needs to be rewritten. In particular
1320 // the WrWindowState and Notifier implementations aren't designed to work with
1321 // a separate render thread.
1322 // As part of that I am moving the bindings closer to WebRender's API boundary,
1323 // and moving more of the logic in C++ land.
1324 // This work is tracked by bug 1328602.
1325 //
1326 // See RenderThread.h for some notes about how the pieces fit together.
1327
1328 pub struct WebRenderFrameBuilder {
1329 pub root_pipeline_id: WrPipelineId,
1330 pub dl_builder: DisplayListBuilder,
1331 }
1332
1333 impl WebRenderFrameBuilder {
new(root_pipeline_id: WrPipelineId, content_size: LayoutSize) -> WebRenderFrameBuilder1334 pub fn new(root_pipeline_id: WrPipelineId,
1335 content_size: LayoutSize) -> WebRenderFrameBuilder {
1336 WebRenderFrameBuilder {
1337 root_pipeline_id: root_pipeline_id,
1338 dl_builder: DisplayListBuilder::new(root_pipeline_id, content_size),
1339 }
1340 }
with_capacity(root_pipeline_id: WrPipelineId, content_size: LayoutSize, capacity: usize) -> WebRenderFrameBuilder1341 pub fn with_capacity(root_pipeline_id: WrPipelineId,
1342 content_size: LayoutSize,
1343 capacity: usize) -> WebRenderFrameBuilder {
1344 WebRenderFrameBuilder {
1345 root_pipeline_id: root_pipeline_id,
1346 dl_builder: DisplayListBuilder::with_capacity(root_pipeline_id, content_size, capacity),
1347 }
1348 }
1349
1350 }
1351
1352 pub struct WrState {
1353 pipeline_id: WrPipelineId,
1354 frame_builder: WebRenderFrameBuilder,
1355 current_tag: Option<ItemTag>,
1356 }
1357
1358 #[no_mangle]
wr_state_new(pipeline_id: WrPipelineId, content_size: LayoutSize, capacity: usize) -> *mut WrState1359 pub extern "C" fn wr_state_new(pipeline_id: WrPipelineId,
1360 content_size: LayoutSize,
1361 capacity: usize) -> *mut WrState {
1362 assert!(unsafe { !is_in_render_thread() });
1363
1364 let state = Box::new(WrState {
1365 pipeline_id: pipeline_id,
1366 frame_builder: WebRenderFrameBuilder::with_capacity(pipeline_id,
1367 content_size,
1368 capacity),
1369 current_tag: None,
1370 });
1371
1372 Box::into_raw(state)
1373 }
1374
1375 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
1376 #[no_mangle]
wr_state_delete(state: *mut WrState)1377 pub extern "C" fn wr_state_delete(state: *mut WrState) {
1378 assert!(unsafe { !is_in_render_thread() });
1379
1380 unsafe {
1381 Box::from_raw(state);
1382 }
1383 }
1384
1385 #[no_mangle]
wr_dp_save(state: &mut WrState)1386 pub extern "C" fn wr_dp_save(state: &mut WrState) {
1387 state.frame_builder.dl_builder.save();
1388 }
1389
1390 #[no_mangle]
wr_dp_restore(state: &mut WrState)1391 pub extern "C" fn wr_dp_restore(state: &mut WrState) {
1392 state.frame_builder.dl_builder.restore();
1393 }
1394
1395 #[no_mangle]
wr_dp_clear_save(state: &mut WrState)1396 pub extern "C" fn wr_dp_clear_save(state: &mut WrState) {
1397 state.frame_builder.dl_builder.clear_save();
1398 }
1399
1400 #[no_mangle]
wr_dp_push_stacking_context(state: &mut WrState, bounds: LayoutRect, animation: *const WrAnimationProperty, opacity: *const f32, transform: *const LayoutTransform, transform_style: TransformStyle, perspective: *const LayoutTransform, mix_blend_mode: MixBlendMode, filters: *const WrFilterOp, filter_count: usize, is_backface_visible: bool)1401 pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
1402 bounds: LayoutRect,
1403 animation: *const WrAnimationProperty,
1404 opacity: *const f32,
1405 transform: *const LayoutTransform,
1406 transform_style: TransformStyle,
1407 perspective: *const LayoutTransform,
1408 mix_blend_mode: MixBlendMode,
1409 filters: *const WrFilterOp,
1410 filter_count: usize,
1411 is_backface_visible: bool) {
1412 debug_assert!(unsafe { !is_in_render_thread() });
1413
1414 let c_filters = make_slice(filters, filter_count);
1415 let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
1416 match c_filter.filter_type {
1417 WrFilterOpType::Blur => FilterOp::Blur(c_filter.argument),
1418 WrFilterOpType::Brightness => FilterOp::Brightness(c_filter.argument),
1419 WrFilterOpType::Contrast => FilterOp::Contrast(c_filter.argument),
1420 WrFilterOpType::Grayscale => FilterOp::Grayscale(c_filter.argument),
1421 WrFilterOpType::HueRotate => FilterOp::HueRotate(c_filter.argument),
1422 WrFilterOpType::Invert => FilterOp::Invert(c_filter.argument),
1423 WrFilterOpType::Opacity => FilterOp::Opacity(PropertyBinding::Value(c_filter.argument), c_filter.argument),
1424 WrFilterOpType::Saturate => FilterOp::Saturate(c_filter.argument),
1425 WrFilterOpType::Sepia => FilterOp::Sepia(c_filter.argument),
1426 WrFilterOpType::DropShadow => FilterOp::DropShadow(c_filter.offset,
1427 c_filter.argument,
1428 c_filter.color),
1429 WrFilterOpType::ColorMatrix => FilterOp::ColorMatrix(c_filter.matrix),
1430 }
1431 }).collect();
1432
1433 let opacity_ref = unsafe { opacity.as_ref() };
1434 if let Some(opacity) = opacity_ref {
1435 if *opacity < 1.0 {
1436 filters.push(FilterOp::Opacity(PropertyBinding::Value(*opacity), *opacity));
1437 }
1438 }
1439
1440 let transform_ref = unsafe { transform.as_ref() };
1441 let mut transform_binding = match transform_ref {
1442 Some(transform) => Some(PropertyBinding::Value(transform.clone())),
1443 None => None,
1444 };
1445
1446 let anim = unsafe { animation.as_ref() };
1447 if let Some(anim) = anim {
1448 debug_assert!(anim.id > 0);
1449 match anim.effect_type {
1450 WrAnimationType::Opacity => filters.push(FilterOp::Opacity(PropertyBinding::Binding(PropertyBindingKey::new(anim.id)), 1.0)),
1451 WrAnimationType::Transform => transform_binding = Some(PropertyBinding::Binding(PropertyBindingKey::new(anim.id))),
1452 }
1453 }
1454
1455 let perspective_ref = unsafe { perspective.as_ref() };
1456 let perspective = match perspective_ref {
1457 Some(perspective) => Some(perspective.clone()),
1458 None => None,
1459 };
1460
1461 let mut prim_info = LayoutPrimitiveInfo::new(bounds);
1462 prim_info.is_backface_visible = is_backface_visible;
1463 prim_info.tag = state.current_tag;
1464
1465 state.frame_builder
1466 .dl_builder
1467 .push_stacking_context(&prim_info,
1468 ScrollPolicy::Scrollable,
1469 transform_binding,
1470 transform_style,
1471 perspective,
1472 mix_blend_mode,
1473 filters);
1474 }
1475
1476 #[no_mangle]
wr_dp_pop_stacking_context(state: &mut WrState)1477 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
1478 debug_assert!(unsafe { !is_in_render_thread() });
1479 state.frame_builder.dl_builder.pop_stacking_context();
1480 }
1481
make_scroll_info(state: &mut WrState, scroll_id: Option<&usize>, clip_id: Option<&usize>) -> Option<ClipAndScrollInfo>1482 fn make_scroll_info(state: &mut WrState,
1483 scroll_id: Option<&usize>,
1484 clip_id: Option<&usize>)
1485 -> Option<ClipAndScrollInfo> {
1486 if let Some(&sid) = scroll_id {
1487 if let Some(&cid) = clip_id {
1488 Some(ClipAndScrollInfo::new(
1489 ClipId::Clip(sid , state.pipeline_id),
1490 ClipId::Clip(cid, state.pipeline_id)))
1491 } else {
1492 Some(ClipAndScrollInfo::simple(
1493 ClipId::Clip(sid, state.pipeline_id)))
1494 }
1495 } else if let Some(&cid) = clip_id {
1496 Some(ClipAndScrollInfo::simple(
1497 ClipId::Clip(cid, state.pipeline_id)))
1498 } else {
1499 None
1500 }
1501 }
1502
1503 #[no_mangle]
wr_dp_define_clip(state: &mut WrState, ancestor_scroll_id: *const usize, ancestor_clip_id: *const usize, clip_rect: LayoutRect, complex: *const ComplexClipRegion, complex_count: usize, mask: *const WrImageMask) -> usize1504 pub extern "C" fn wr_dp_define_clip(state: &mut WrState,
1505 ancestor_scroll_id: *const usize,
1506 ancestor_clip_id: *const usize,
1507 clip_rect: LayoutRect,
1508 complex: *const ComplexClipRegion,
1509 complex_count: usize,
1510 mask: *const WrImageMask)
1511 -> usize {
1512 debug_assert!(unsafe { is_in_main_thread() });
1513
1514 let info = make_scroll_info(state,
1515 unsafe { ancestor_scroll_id.as_ref() },
1516 unsafe { ancestor_clip_id.as_ref() });
1517
1518 let complex_slice = make_slice(complex, complex_count);
1519 let complex_iter = complex_slice.iter().cloned();
1520 let mask : Option<ImageMask> = unsafe { mask.as_ref() }.map(|x| x.into());
1521
1522 let clip_id = if info.is_some() {
1523 state.frame_builder.dl_builder.define_clip_with_parent(
1524 info.unwrap().scroll_node_id, clip_rect, complex_iter, mask)
1525 } else {
1526 state.frame_builder.dl_builder.define_clip(clip_rect, complex_iter, mask)
1527 };
1528 // return the usize id value from inside the ClipId::Clip(..)
1529 match clip_id {
1530 ClipId::Clip(id, pipeline_id) => {
1531 assert!(pipeline_id == state.pipeline_id);
1532 id
1533 },
1534 _ => panic!("Got unexpected clip id type"),
1535 }
1536 }
1537
1538 #[no_mangle]
wr_dp_push_clip(state: &mut WrState, clip_id: usize)1539 pub extern "C" fn wr_dp_push_clip(state: &mut WrState,
1540 clip_id: usize) {
1541 debug_assert!(unsafe { is_in_main_thread() });
1542 state.frame_builder.dl_builder.push_clip_id(ClipId::Clip(clip_id, state.pipeline_id));
1543 }
1544
1545 #[no_mangle]
wr_dp_pop_clip(state: &mut WrState)1546 pub extern "C" fn wr_dp_pop_clip(state: &mut WrState) {
1547 debug_assert!(unsafe { !is_in_render_thread() });
1548 state.frame_builder.dl_builder.pop_clip_id();
1549 }
1550
1551 #[no_mangle]
wr_dp_define_sticky_frame(state: &mut WrState, 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) -> usize1552 pub extern "C" fn wr_dp_define_sticky_frame(state: &mut WrState,
1553 content_rect: LayoutRect,
1554 top_margin: *const f32,
1555 right_margin: *const f32,
1556 bottom_margin: *const f32,
1557 left_margin: *const f32,
1558 vertical_bounds: StickyOffsetBounds,
1559 horizontal_bounds: StickyOffsetBounds,
1560 applied_offset: LayoutVector2D)
1561 -> usize {
1562 assert!(unsafe { is_in_main_thread() });
1563 let clip_id = state.frame_builder.dl_builder.define_sticky_frame(
1564 content_rect, SideOffsets2D::new(
1565 unsafe { top_margin.as_ref() }.cloned(),
1566 unsafe { right_margin.as_ref() }.cloned(),
1567 unsafe { bottom_margin.as_ref() }.cloned(),
1568 unsafe { left_margin.as_ref() }.cloned()
1569 ),
1570 vertical_bounds, horizontal_bounds, applied_offset);
1571 match clip_id {
1572 ClipId::Clip(id, pipeline_id) => {
1573 assert!(pipeline_id == state.pipeline_id);
1574 id
1575 },
1576 _ => panic!("Got unexpected clip id type"),
1577 }
1578 }
1579
1580 #[no_mangle]
wr_dp_define_scroll_layer(state: &mut WrState, scroll_id: u64, ancestor_scroll_id: *const usize, ancestor_clip_id: *const usize, content_rect: LayoutRect, clip_rect: LayoutRect) -> usize1581 pub extern "C" fn wr_dp_define_scroll_layer(state: &mut WrState,
1582 scroll_id: u64,
1583 ancestor_scroll_id: *const usize,
1584 ancestor_clip_id: *const usize,
1585 content_rect: LayoutRect,
1586 clip_rect: LayoutRect)
1587 -> usize {
1588 assert!(unsafe { is_in_main_thread() });
1589
1590 let info = make_scroll_info(state,
1591 unsafe { ancestor_scroll_id.as_ref() },
1592 unsafe { ancestor_clip_id.as_ref() });
1593
1594 let new_id = if info.is_some() {
1595 state.frame_builder.dl_builder.define_scroll_frame_with_parent(
1596 info.unwrap().scroll_node_id,
1597 Some(ExternalScrollId(scroll_id, state.pipeline_id)),
1598 content_rect,
1599 clip_rect,
1600 vec![],
1601 None,
1602 ScrollSensitivity::Script
1603 )
1604 } else {
1605 state.frame_builder.dl_builder.define_scroll_frame(
1606 Some(ExternalScrollId(scroll_id, state.pipeline_id)),
1607 content_rect,
1608 clip_rect,
1609 vec![],
1610 None,
1611 ScrollSensitivity::Script
1612 )
1613 };
1614
1615 match new_id {
1616 ClipId::Clip(id, pipeline_id) => {
1617 assert!(pipeline_id == state.pipeline_id);
1618 id
1619 },
1620 _ => panic!("Got unexpected clip id type"),
1621 }
1622 }
1623
1624 #[no_mangle]
wr_dp_push_scroll_layer(state: &mut WrState, scroll_id: usize)1625 pub extern "C" fn wr_dp_push_scroll_layer(state: &mut WrState,
1626 scroll_id: usize) {
1627 debug_assert!(unsafe { is_in_main_thread() });
1628 let clip_id = ClipId::Clip(scroll_id, state.pipeline_id);
1629 state.frame_builder.dl_builder.push_clip_id(clip_id);
1630 }
1631
1632 #[no_mangle]
wr_dp_pop_scroll_layer(state: &mut WrState)1633 pub extern "C" fn wr_dp_pop_scroll_layer(state: &mut WrState) {
1634 debug_assert!(unsafe { is_in_main_thread() });
1635 state.frame_builder.dl_builder.pop_clip_id();
1636 }
1637
1638 #[no_mangle]
wr_dp_push_clip_and_scroll_info(state: &mut WrState, scroll_id: usize, clip_id: *const usize)1639 pub extern "C" fn wr_dp_push_clip_and_scroll_info(state: &mut WrState,
1640 scroll_id: usize,
1641 clip_id: *const usize) {
1642 debug_assert!(unsafe { is_in_main_thread() });
1643 let info = make_scroll_info(state, Some(&scroll_id), unsafe { clip_id.as_ref() });
1644 debug_assert!(info.is_some());
1645 state.frame_builder.dl_builder.push_clip_and_scroll_info(info.unwrap());
1646 }
1647
1648 #[no_mangle]
wr_dp_pop_clip_and_scroll_info(state: &mut WrState)1649 pub extern "C" fn wr_dp_pop_clip_and_scroll_info(state: &mut WrState) {
1650 debug_assert!(unsafe { is_in_main_thread() });
1651 state.frame_builder.dl_builder.pop_clip_id();
1652 }
1653
1654 #[no_mangle]
wr_dp_push_iframe(state: &mut WrState, rect: LayoutRect, is_backface_visible: bool, pipeline_id: WrPipelineId)1655 pub extern "C" fn wr_dp_push_iframe(state: &mut WrState,
1656 rect: LayoutRect,
1657 is_backface_visible: bool,
1658 pipeline_id: WrPipelineId) {
1659 debug_assert!(unsafe { is_in_main_thread() });
1660
1661 let mut prim_info = LayoutPrimitiveInfo::new(rect);
1662 prim_info.is_backface_visible = is_backface_visible;
1663 prim_info.tag = state.current_tag;
1664 state.frame_builder.dl_builder.push_iframe(&prim_info, pipeline_id);
1665 }
1666
1667 #[no_mangle]
wr_dp_push_rect(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, color: ColorF)1668 pub extern "C" fn wr_dp_push_rect(state: &mut WrState,
1669 rect: LayoutRect,
1670 clip: LayoutRect,
1671 is_backface_visible: bool,
1672 color: ColorF) {
1673 debug_assert!(unsafe { !is_in_render_thread() });
1674
1675 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
1676 prim_info.is_backface_visible = is_backface_visible;
1677 prim_info.tag = state.current_tag;
1678 state.frame_builder.dl_builder.push_rect(&prim_info,
1679 color);
1680 }
1681
1682 #[no_mangle]
wr_dp_push_clear_rect(state: &mut WrState, rect: LayoutRect)1683 pub extern "C" fn wr_dp_push_clear_rect(state: &mut WrState,
1684 rect: LayoutRect) {
1685 debug_assert!(unsafe { !is_in_render_thread() });
1686
1687 let prim_info = LayoutPrimitiveInfo::new(rect);
1688 state.frame_builder.dl_builder.push_clear_rect(&prim_info);
1689 }
1690
1691 #[no_mangle]
wr_dp_push_image(state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, stretch_size: LayoutSize, tile_spacing: LayoutSize, image_rendering: ImageRendering, key: WrImageKey, premultiplied_alpha: bool)1692 pub extern "C" fn wr_dp_push_image(state: &mut WrState,
1693 bounds: LayoutRect,
1694 clip: LayoutRect,
1695 is_backface_visible: bool,
1696 stretch_size: LayoutSize,
1697 tile_spacing: LayoutSize,
1698 image_rendering: ImageRendering,
1699 key: WrImageKey,
1700 premultiplied_alpha: bool) {
1701 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
1702
1703 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
1704 prim_info.is_backface_visible = is_backface_visible;
1705 prim_info.tag = state.current_tag;
1706 let alpha_type = if premultiplied_alpha {
1707 AlphaType::PremultipliedAlpha
1708 } else {
1709 AlphaType::Alpha
1710 };
1711 state.frame_builder
1712 .dl_builder
1713 .push_image(&prim_info,
1714 stretch_size,
1715 tile_spacing,
1716 image_rendering,
1717 alpha_type,
1718 key);
1719 }
1720
1721 /// Push a 3 planar yuv image.
1722 #[no_mangle]
wr_dp_push_yuv_planar_image(state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, image_key_0: WrImageKey, image_key_1: WrImageKey, image_key_2: WrImageKey, color_space: WrYuvColorSpace, image_rendering: ImageRendering)1723 pub extern "C" fn wr_dp_push_yuv_planar_image(state: &mut WrState,
1724 bounds: LayoutRect,
1725 clip: LayoutRect,
1726 is_backface_visible: bool,
1727 image_key_0: WrImageKey,
1728 image_key_1: WrImageKey,
1729 image_key_2: WrImageKey,
1730 color_space: WrYuvColorSpace,
1731 image_rendering: ImageRendering) {
1732 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
1733
1734 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
1735 prim_info.is_backface_visible = is_backface_visible;
1736 prim_info.tag = state.current_tag;
1737 state.frame_builder
1738 .dl_builder
1739 .push_yuv_image(&prim_info,
1740 YuvData::PlanarYCbCr(image_key_0, image_key_1, image_key_2),
1741 color_space,
1742 image_rendering);
1743 }
1744
1745 /// Push a 2 planar NV12 image.
1746 #[no_mangle]
wr_dp_push_yuv_NV12_image(state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, image_key_0: WrImageKey, image_key_1: WrImageKey, color_space: WrYuvColorSpace, image_rendering: ImageRendering)1747 pub extern "C" fn wr_dp_push_yuv_NV12_image(state: &mut WrState,
1748 bounds: LayoutRect,
1749 clip: LayoutRect,
1750 is_backface_visible: bool,
1751 image_key_0: WrImageKey,
1752 image_key_1: WrImageKey,
1753 color_space: WrYuvColorSpace,
1754 image_rendering: ImageRendering) {
1755 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
1756
1757 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
1758 prim_info.is_backface_visible = is_backface_visible;
1759 prim_info.tag = state.current_tag;
1760 state.frame_builder
1761 .dl_builder
1762 .push_yuv_image(&prim_info,
1763 YuvData::NV12(image_key_0, image_key_1),
1764 color_space,
1765 image_rendering);
1766 }
1767
1768 /// Push a yuv interleaved image.
1769 #[no_mangle]
wr_dp_push_yuv_interleaved_image(state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, image_key_0: WrImageKey, color_space: WrYuvColorSpace, image_rendering: ImageRendering)1770 pub extern "C" fn wr_dp_push_yuv_interleaved_image(state: &mut WrState,
1771 bounds: LayoutRect,
1772 clip: LayoutRect,
1773 is_backface_visible: bool,
1774 image_key_0: WrImageKey,
1775 color_space: WrYuvColorSpace,
1776 image_rendering: ImageRendering) {
1777 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
1778
1779 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
1780 prim_info.is_backface_visible = is_backface_visible;
1781 prim_info.tag = state.current_tag;
1782 state.frame_builder
1783 .dl_builder
1784 .push_yuv_image(&prim_info,
1785 YuvData::InterleavedYCbCr(image_key_0),
1786 color_space,
1787 image_rendering);
1788 }
1789
1790 #[no_mangle]
wr_dp_push_text(state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, color: ColorF, font_key: WrFontInstanceKey, glyphs: *const GlyphInstance, glyph_count: u32, glyph_options: *const GlyphOptions)1791 pub extern "C" fn wr_dp_push_text(state: &mut WrState,
1792 bounds: LayoutRect,
1793 clip: LayoutRect,
1794 is_backface_visible: bool,
1795 color: ColorF,
1796 font_key: WrFontInstanceKey,
1797 glyphs: *const GlyphInstance,
1798 glyph_count: u32,
1799 glyph_options: *const GlyphOptions) {
1800 debug_assert!(unsafe { is_in_main_thread() });
1801
1802 let glyph_slice = make_slice(glyphs, glyph_count as usize);
1803
1804 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
1805 prim_info.is_backface_visible = is_backface_visible;
1806 prim_info.tag = state.current_tag;
1807 state.frame_builder
1808 .dl_builder
1809 .push_text(&prim_info,
1810 &glyph_slice,
1811 font_key,
1812 color,
1813 unsafe { glyph_options.as_ref().cloned() });
1814 }
1815
1816 #[no_mangle]
wr_dp_push_shadow(state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, shadow: Shadow)1817 pub extern "C" fn wr_dp_push_shadow(state: &mut WrState,
1818 bounds: LayoutRect,
1819 clip: LayoutRect,
1820 is_backface_visible: bool,
1821 shadow: Shadow) {
1822 debug_assert!(unsafe { is_in_main_thread() });
1823
1824 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
1825 prim_info.is_backface_visible = is_backface_visible;
1826 prim_info.tag = state.current_tag;
1827 state.frame_builder.dl_builder.push_shadow(&prim_info, shadow.into());
1828 }
1829
1830 #[no_mangle]
wr_dp_pop_all_shadows(state: &mut WrState)1831 pub extern "C" fn wr_dp_pop_all_shadows(state: &mut WrState) {
1832 debug_assert!(unsafe { is_in_main_thread() });
1833
1834 state.frame_builder.dl_builder.pop_all_shadows();
1835 }
1836
1837 #[no_mangle]
wr_dp_push_line(state: &mut WrState, clip: &LayoutRect, is_backface_visible: bool, bounds: &LayoutRect, wavy_line_thickness: f32, orientation: LineOrientation, color: &ColorF, style: LineStyle)1838 pub extern "C" fn wr_dp_push_line(state: &mut WrState,
1839 clip: &LayoutRect,
1840 is_backface_visible: bool,
1841 bounds: &LayoutRect,
1842 wavy_line_thickness: f32,
1843 orientation: LineOrientation,
1844 color: &ColorF,
1845 style: LineStyle) {
1846 debug_assert!(unsafe { is_in_main_thread() });
1847
1848 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(*bounds, (*clip).into());
1849 prim_info.is_backface_visible = is_backface_visible;
1850 prim_info.tag = state.current_tag;
1851 state.frame_builder
1852 .dl_builder
1853 .push_line(&prim_info,
1854 wavy_line_thickness,
1855 orientation,
1856 color,
1857 style);
1858
1859 }
1860
1861 #[no_mangle]
wr_dp_push_border(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, widths: BorderWidths, top: BorderSide, right: BorderSide, bottom: BorderSide, left: BorderSide, radius: BorderRadius)1862 pub extern "C" fn wr_dp_push_border(state: &mut WrState,
1863 rect: LayoutRect,
1864 clip: LayoutRect,
1865 is_backface_visible: bool,
1866 widths: BorderWidths,
1867 top: BorderSide,
1868 right: BorderSide,
1869 bottom: BorderSide,
1870 left: BorderSide,
1871 radius: BorderRadius) {
1872 debug_assert!(unsafe { is_in_main_thread() });
1873
1874 let border_details = BorderDetails::Normal(NormalBorder {
1875 left: left.into(),
1876 right: right.into(),
1877 top: top.into(),
1878 bottom: bottom.into(),
1879 radius: radius.into(),
1880 });
1881 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
1882 prim_info.is_backface_visible = is_backface_visible;
1883 prim_info.tag = state.current_tag;
1884 state.frame_builder
1885 .dl_builder
1886 .push_border(&prim_info,
1887 widths,
1888 border_details);
1889 }
1890
1891 #[no_mangle]
wr_dp_push_border_image(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, widths: BorderWidths, image: WrImageKey, patch: NinePatchDescriptor, outset: SideOffsets2D<f32>, repeat_horizontal: RepeatMode, repeat_vertical: RepeatMode)1892 pub extern "C" fn wr_dp_push_border_image(state: &mut WrState,
1893 rect: LayoutRect,
1894 clip: LayoutRect,
1895 is_backface_visible: bool,
1896 widths: BorderWidths,
1897 image: WrImageKey,
1898 patch: NinePatchDescriptor,
1899 outset: SideOffsets2D<f32>,
1900 repeat_horizontal: RepeatMode,
1901 repeat_vertical: RepeatMode) {
1902 debug_assert!(unsafe { is_in_main_thread() });
1903 let border_details =
1904 BorderDetails::Image(ImageBorder {
1905 image_key: image,
1906 patch: patch.into(),
1907 fill: false,
1908 outset: outset.into(),
1909 repeat_horizontal: repeat_horizontal.into(),
1910 repeat_vertical: repeat_vertical.into(),
1911 });
1912 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
1913 prim_info.is_backface_visible = is_backface_visible;
1914 prim_info.tag = state.current_tag;
1915 state.frame_builder
1916 .dl_builder
1917 .push_border(&prim_info,
1918 widths.into(),
1919 border_details);
1920 }
1921
1922 #[no_mangle]
wr_dp_push_border_gradient(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, widths: BorderWidths, start_point: LayoutPoint, end_point: LayoutPoint, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, outset: SideOffsets2D<f32>)1923 pub extern "C" fn wr_dp_push_border_gradient(state: &mut WrState,
1924 rect: LayoutRect,
1925 clip: LayoutRect,
1926 is_backface_visible: bool,
1927 widths: BorderWidths,
1928 start_point: LayoutPoint,
1929 end_point: LayoutPoint,
1930 stops: *const GradientStop,
1931 stops_count: usize,
1932 extend_mode: ExtendMode,
1933 outset: SideOffsets2D<f32>) {
1934 debug_assert!(unsafe { is_in_main_thread() });
1935
1936 let stops_slice = make_slice(stops, stops_count);
1937 let stops_vector = stops_slice.to_owned();
1938
1939 let border_details = BorderDetails::Gradient(GradientBorder {
1940 gradient:
1941 state.frame_builder
1942 .dl_builder
1943 .create_gradient(start_point.into(),
1944 end_point.into(),
1945 stops_vector,
1946 extend_mode.into()),
1947 outset: outset.into(),
1948 });
1949 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
1950 prim_info.is_backface_visible = is_backface_visible;
1951 prim_info.tag = state.current_tag;
1952 state.frame_builder
1953 .dl_builder
1954 .push_border(&prim_info,
1955 widths.into(),
1956 border_details);
1957 }
1958
1959 #[no_mangle]
wr_dp_push_border_radial_gradient(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, widths: BorderWidths, center: LayoutPoint, radius: LayoutSize, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, outset: SideOffsets2D<f32>)1960 pub extern "C" fn wr_dp_push_border_radial_gradient(state: &mut WrState,
1961 rect: LayoutRect,
1962 clip: LayoutRect,
1963 is_backface_visible: bool,
1964 widths: BorderWidths,
1965 center: LayoutPoint,
1966 radius: LayoutSize,
1967 stops: *const GradientStop,
1968 stops_count: usize,
1969 extend_mode: ExtendMode,
1970 outset: SideOffsets2D<f32>) {
1971 debug_assert!(unsafe { is_in_main_thread() });
1972
1973 let stops_slice = make_slice(stops, stops_count);
1974 let stops_vector = stops_slice.to_owned();
1975
1976 let border_details =
1977 BorderDetails::RadialGradient(RadialGradientBorder {
1978 gradient:
1979 state.frame_builder
1980 .dl_builder
1981 .create_radial_gradient(center.into(),
1982 radius.into(),
1983 stops_vector,
1984 extend_mode.into()),
1985 outset: outset.into(),
1986 });
1987 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
1988 prim_info.is_backface_visible = is_backface_visible;
1989 prim_info.tag = state.current_tag;
1990 state.frame_builder
1991 .dl_builder
1992 .push_border(&prim_info,
1993 widths.into(),
1994 border_details);
1995 }
1996
1997 #[no_mangle]
wr_dp_push_linear_gradient(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, start_point: LayoutPoint, end_point: LayoutPoint, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, tile_size: LayoutSize, tile_spacing: LayoutSize)1998 pub extern "C" fn wr_dp_push_linear_gradient(state: &mut WrState,
1999 rect: LayoutRect,
2000 clip: LayoutRect,
2001 is_backface_visible: bool,
2002 start_point: LayoutPoint,
2003 end_point: LayoutPoint,
2004 stops: *const GradientStop,
2005 stops_count: usize,
2006 extend_mode: ExtendMode,
2007 tile_size: LayoutSize,
2008 tile_spacing: LayoutSize) {
2009 debug_assert!(unsafe { is_in_main_thread() });
2010
2011 let stops_slice = make_slice(stops, stops_count);
2012 let stops_vector = stops_slice.to_owned();
2013
2014 let gradient = state.frame_builder
2015 .dl_builder
2016 .create_gradient(start_point.into(),
2017 end_point.into(),
2018 stops_vector,
2019 extend_mode.into());
2020 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
2021 prim_info.is_backface_visible = is_backface_visible;
2022 prim_info.tag = state.current_tag;
2023 state.frame_builder
2024 .dl_builder
2025 .push_gradient(&prim_info,
2026 gradient,
2027 tile_size.into(),
2028 tile_spacing.into());
2029 }
2030
2031 #[no_mangle]
wr_dp_push_radial_gradient(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, center: LayoutPoint, radius: LayoutSize, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, tile_size: LayoutSize, tile_spacing: LayoutSize)2032 pub extern "C" fn wr_dp_push_radial_gradient(state: &mut WrState,
2033 rect: LayoutRect,
2034 clip: LayoutRect,
2035 is_backface_visible: bool,
2036 center: LayoutPoint,
2037 radius: LayoutSize,
2038 stops: *const GradientStop,
2039 stops_count: usize,
2040 extend_mode: ExtendMode,
2041 tile_size: LayoutSize,
2042 tile_spacing: LayoutSize) {
2043 debug_assert!(unsafe { is_in_main_thread() });
2044
2045 let stops_slice = make_slice(stops, stops_count);
2046 let stops_vector = stops_slice.to_owned();
2047
2048 let gradient = state.frame_builder
2049 .dl_builder
2050 .create_radial_gradient(center.into(),
2051 radius.into(),
2052 stops_vector,
2053 extend_mode.into());
2054 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
2055 prim_info.is_backface_visible = is_backface_visible;
2056 prim_info.tag = state.current_tag;
2057 state.frame_builder
2058 .dl_builder
2059 .push_radial_gradient(&prim_info,
2060 gradient,
2061 tile_size,
2062 tile_spacing);
2063 }
2064
2065 #[no_mangle]
wr_dp_push_box_shadow(state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, box_bounds: LayoutRect, offset: LayoutVector2D, color: ColorF, blur_radius: f32, spread_radius: f32, border_radius: BorderRadius, clip_mode: BoxShadowClipMode)2066 pub extern "C" fn wr_dp_push_box_shadow(state: &mut WrState,
2067 rect: LayoutRect,
2068 clip: LayoutRect,
2069 is_backface_visible: bool,
2070 box_bounds: LayoutRect,
2071 offset: LayoutVector2D,
2072 color: ColorF,
2073 blur_radius: f32,
2074 spread_radius: f32,
2075 border_radius: BorderRadius,
2076 clip_mode: BoxShadowClipMode) {
2077 debug_assert!(unsafe { is_in_main_thread() });
2078
2079 let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
2080 prim_info.is_backface_visible = is_backface_visible;
2081 prim_info.tag = state.current_tag;
2082 state.frame_builder
2083 .dl_builder
2084 .push_box_shadow(&prim_info,
2085 box_bounds,
2086 offset,
2087 color,
2088 blur_radius,
2089 spread_radius,
2090 border_radius,
2091 clip_mode);
2092 }
2093
2094 #[no_mangle]
wr_dump_display_list(state: &mut WrState)2095 pub extern "C" fn wr_dump_display_list(state: &mut WrState) {
2096 state.frame_builder
2097 .dl_builder
2098 .print_display_list();
2099 }
2100
2101 #[no_mangle]
wr_api_finalize_builder(state: &mut WrState, content_size: &mut LayoutSize, dl_descriptor: &mut BuiltDisplayListDescriptor, dl_data: &mut WrVecU8)2102 pub unsafe extern "C" fn wr_api_finalize_builder(state: &mut WrState,
2103 content_size: &mut LayoutSize,
2104 dl_descriptor: &mut BuiltDisplayListDescriptor,
2105 dl_data: &mut WrVecU8) {
2106 let frame_builder = mem::replace(&mut state.frame_builder,
2107 WebRenderFrameBuilder::new(state.pipeline_id,
2108 LayoutSize::zero()));
2109 let (_, size, dl) = frame_builder.dl_builder.finalize();
2110 *content_size = LayoutSize::new(size.width, size.height);
2111 let (data, descriptor) = dl.into_data();
2112 *dl_data = WrVecU8::from_vec(data);
2113 *dl_descriptor = descriptor;
2114 }
2115
2116 #[no_mangle]
wr_set_item_tag(state: &mut WrState, scroll_id: u64, hit_info: u16)2117 pub extern "C" fn wr_set_item_tag(state: &mut WrState,
2118 scroll_id: u64,
2119 hit_info: u16) {
2120 state.current_tag = Some((scroll_id, hit_info));
2121 }
2122
2123 #[no_mangle]
wr_clear_item_tag(state: &mut WrState)2124 pub extern "C" fn wr_clear_item_tag(state: &mut WrState) {
2125 state.current_tag = None;
2126 }
2127
2128 #[no_mangle]
wr_api_hit_test(dh: &mut DocumentHandle, point: WorldPoint, out_pipeline_id: &mut WrPipelineId, out_scroll_id: &mut u64, out_hit_info: &mut u16) -> bool2129 pub extern "C" fn wr_api_hit_test(dh: &mut DocumentHandle,
2130 point: WorldPoint,
2131 out_pipeline_id: &mut WrPipelineId,
2132 out_scroll_id: &mut u64,
2133 out_hit_info: &mut u16) -> bool {
2134 let result = dh.api.hit_test(dh.document_id, None, point, HitTestFlags::empty());
2135 for item in &result.items {
2136 // For now we should never be getting results back for which the tag is
2137 // 0 (== CompositorHitTestInfo::eInvisibleToHitTest). In the future if
2138 // we allow this, we'll want to |continue| on the loop in this scenario.
2139 debug_assert!(item.tag.1 != 0);
2140 *out_pipeline_id = item.pipeline;
2141 *out_scroll_id = item.tag.0;
2142 *out_hit_info = item.tag.1;
2143 return true;
2144 }
2145 return false;
2146 }
2147
2148 pub type VecU8 = Vec<u8>;
2149 pub type ArcVecU8 = Arc<VecU8>;
2150
2151 #[no_mangle]
wr_add_ref_arc(arc: &ArcVecU8) -> *const VecU82152 pub extern "C" fn wr_add_ref_arc(arc: &ArcVecU8) -> *const VecU8 {
2153 Arc::into_raw(arc.clone())
2154 }
2155
2156 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
2157 #[no_mangle]
wr_dec_ref_arc(arc: *const VecU8)2158 pub unsafe extern "C" fn wr_dec_ref_arc(arc: *const VecU8) {
2159 Arc::from_raw(arc);
2160 }
2161
2162 // TODO: nical
2163 // Update for the new blob image interface changes.
2164 //
2165 extern "C" {
2166 // TODO: figure out the API for tiled blob images.
wr_moz2d_render_cb(blob: ByteSlice, width: u32, height: u32, format: ImageFormat, tile_size: *const u16, tile_offset: *const TileOffset, output: MutByteSlice) -> bool2167 pub fn wr_moz2d_render_cb(blob: ByteSlice,
2168 width: u32,
2169 height: u32,
2170 format: ImageFormat,
2171 tile_size: *const u16,
2172 tile_offset: *const TileOffset,
2173 output: MutByteSlice)
2174 -> bool;
2175 }
2176
2177 type ExternalMessageHandler = unsafe extern "C" fn(msg: *const c_char);
2178
2179 struct WrExternalLogHandler {
2180 error_msg: ExternalMessageHandler,
2181 warn_msg: ExternalMessageHandler,
2182 info_msg: ExternalMessageHandler,
2183 debug_msg: ExternalMessageHandler,
2184 trace_msg: ExternalMessageHandler,
2185 log_level: log::Level,
2186 }
2187
2188 impl WrExternalLogHandler {
new(log_level: log::Level) -> WrExternalLogHandler2189 fn new(log_level: log::Level) -> WrExternalLogHandler {
2190 WrExternalLogHandler {
2191 error_msg: gfx_critical_note,
2192 warn_msg: gfx_critical_note,
2193 info_msg: gecko_printf_stderr_output,
2194 debug_msg: gecko_printf_stderr_output,
2195 trace_msg: gecko_printf_stderr_output,
2196 log_level: log_level,
2197 }
2198 }
2199 }
2200
2201 impl log::Log for WrExternalLogHandler {
enabled(&self, metadata : &log::Metadata) -> bool2202 fn enabled(&self, metadata : &log::Metadata) -> bool {
2203 metadata.level() <= self.log_level
2204 }
2205
log(&self, record: &log::Record)2206 fn log(&self, record: &log::Record) {
2207 if self.enabled(record.metadata()) {
2208 // For file path and line, please check the record.location().
2209 let msg = CString::new(format!("WR: {}",
2210 record.args())).unwrap();
2211 unsafe {
2212 match record.level() {
2213 log::Level::Error => (self.error_msg)(msg.as_ptr()),
2214 log::Level::Warn => (self.warn_msg)(msg.as_ptr()),
2215 log::Level::Info => (self.info_msg)(msg.as_ptr()),
2216 log::Level::Debug => (self.debug_msg)(msg.as_ptr()),
2217 log::Level::Trace => (self.trace_msg)(msg.as_ptr()),
2218 }
2219 }
2220 }
2221 }
2222
flush(&self)2223 fn flush(&self) {
2224 }
2225 }
2226
2227 #[no_mangle]
wr_init_external_log_handler(log_filter: WrLogLevelFilter)2228 pub extern "C" fn wr_init_external_log_handler(log_filter: WrLogLevelFilter) {
2229 log::set_max_level(log_filter);
2230 let logger = Box::new(WrExternalLogHandler::new(log_filter
2231 .to_level()
2232 .unwrap_or(log::Level::Error)));
2233 let _ = log::set_logger(unsafe { &*Box::into_raw(logger) });
2234 }
2235
2236 #[no_mangle]
wr_shutdown_external_log_handler()2237 pub extern "C" fn wr_shutdown_external_log_handler() {
2238 }
2239