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