summaryrefslogtreecommitdiffstats
path: root/gfx/webrender_bindings/src/bindings.rs
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/webrender_bindings/src/bindings.rs')
-rw-r--r--gfx/webrender_bindings/src/bindings.rs98
1 files changed, 77 insertions, 21 deletions
diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs
index 3fc93fdf13..579453a165 100644
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -36,11 +36,11 @@ use tracy_rs::register_thread_with_profiler;
use webrender::sw_compositor::SwCompositor;
use webrender::{
api::units::*, api::*, create_webrender_instance, render_api::*, set_profiler_hooks, AsyncPropertySampler,
- AsyncScreenshotHandle, Compositor, CompositorCapabilities, CompositorConfig, CompositorSurfaceTransform,
- Device, MappableCompositor, MappedTileInfo, NativeSurfaceId, NativeSurfaceInfo, NativeTileId,
- PartialPresentCompositor, PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererStats,
- SWGLCompositeSurfaceInfo, SceneBuilderHooks, ShaderPrecacheFlags, Shaders, SharedShaders, TextureCacheConfig,
- UploadMethod, WebRenderOptions, WindowVisibility, ONE_TIME_USAGE_HINT,
+ AsyncScreenshotHandle, Compositor, CompositorCapabilities, CompositorConfig, CompositorSurfaceTransform, Device,
+ MappableCompositor, MappedTileInfo, NativeSurfaceId, NativeSurfaceInfo, NativeTileId, PartialPresentCompositor,
+ PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererStats, SWGLCompositeSurfaceInfo,
+ SceneBuilderHooks, ShaderPrecacheFlags, Shaders, SharedShaders, TextureCacheConfig, UploadMethod, WebRenderOptions,
+ WindowVisibility, ONE_TIME_USAGE_HINT,
};
use wr_malloc_size_of::MallocSizeOfOps;
@@ -212,36 +212,68 @@ impl DocumentHandle {
#[repr(C)]
pub struct WrVecU8 {
+ /// `data` must always be valid for passing to Vec::from_raw_parts.
+ /// In particular, it must be non-null even if capacity is zero.
data: *mut u8,
length: usize,
capacity: usize,
}
impl WrVecU8 {
- fn into_vec(self) -> Vec<u8> {
- unsafe { Vec::from_raw_parts(self.data, self.length, self.capacity) }
+ fn into_vec(mut self) -> Vec<u8> {
+ // Clear self and then drop self.
+ self.flush_into_vec()
}
- // Equivalent to `into_vec` but clears self instead of consuming the value.
+ // Clears self without consuming self.
fn flush_into_vec(&mut self) -> Vec<u8> {
- self.convert_into_vec::<u8>()
- }
-
- // Like flush_into_vec, but also does an unsafe conversion to the desired type.
- fn convert_into_vec<T>(&mut self) -> Vec<T> {
+ // Create a Vec using Vec::from_raw_parts.
+ //
+ // Here are the safety requirements, verbatim from the documentation of `from_raw_parts`:
+ //
+ // > * `ptr` must have been allocated using the global allocator, such as via
+ // > the [`alloc::alloc`] function.
+ // > * `T` needs to have the same alignment as what `ptr` was allocated with.
+ // > (`T` having a less strict alignment is not sufficient, the alignment really
+ // > needs to be equal to satisfy the [`dealloc`] requirement that memory must be
+ // > allocated and deallocated with the same layout.)
+ // > * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
+ // > to be the same size as the pointer was allocated with. (Because similar to
+ // > alignment, [`dealloc`] must be called with the same layout `size`.)
+ // > * `length` needs to be less than or equal to `capacity`.
+ // > * The first `length` values must be properly initialized values of type `T`.
+ // > * `capacity` needs to be the capacity that the pointer was allocated with.
+ // > * The allocated size in bytes must be no larger than `isize::MAX`.
+ // > See the safety documentation of [`pointer::offset`].
+ //
+ // These comments don't say what to do for zero-capacity vecs which don't have
+ // an allocation. In particular, the requirement "`ptr` must have been allocated"
+ // is not met for such vecs.
+ //
+ // However, the safety requirements of `slice::from_raw_parts` are more explicit
+ // about the empty case:
+ //
+ // > * `data` must be non-null and aligned even for zero-length slices. One
+ // > reason for this is that enum layout optimizations may rely on references
+ // > (including slices of any length) being aligned and non-null to distinguish
+ // > them from other data. You can obtain a pointer that is usable as `data`
+ // > for zero-length slices using [`NonNull::dangling()`].
+ //
+ // For the empty case we follow this requirement rather than the more stringent
+ // requirement from the `Vec::from_raw_parts` docs.
let vec = unsafe {
- Vec::from_raw_parts(
- self.data as *mut T,
- self.length / mem::size_of::<T>(),
- self.capacity / mem::size_of::<T>(),
- )
+ Vec::from_raw_parts(self.data, self.length, self.capacity)
};
- self.data = ptr::null_mut();
+ self.data = ptr::NonNull::dangling().as_ptr();
self.length = 0;
self.capacity = 0;
vec
}
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe { core::slice::from_raw_parts(self.data, self.length) }
+ }
+
fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
let w = WrVecU8 {
data: v.as_mut_ptr(),
@@ -2317,7 +2349,8 @@ pub extern "C" fn wr_api_stop_capture_sequence(dh: &mut DocumentHandle) {
#[cfg(target_os = "windows")]
fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle {
- let wchars = bytes.convert_into_vec::<u16>();
+ let wchars: Vec<u16> =
+ bytes.as_slice().chunks_exact(2).map(|c| u16::from_ne_bytes([c[0], c[1]])).collect();
NativeFontHandle {
path: PathBuf::from(OsString::from_wide(&wchars)),
index,
@@ -2373,13 +2406,24 @@ pub extern "C" fn wr_resource_updates_add_font_instance(
platform_options: *const FontInstancePlatformOptions,
variations: &mut WrVecU8,
) {
+ // Deserialize a sequence of FontVariation objects from the raw bytes.
+ // Every FontVariation is 8 bytes: one u32 and one f32.
+ // The code below would look better with slice::chunk_arrays:
+ // https://github.com/rust-lang/rust/issues/74985
+ let variations: Vec<FontVariation> =
+ variations.as_slice().chunks_exact(8).map(|c| {
+ assert_eq!(c.len(), 8);
+ let tag = u32::from_ne_bytes([c[0], c[1], c[2], c[3]]);
+ let value = f32::from_ne_bytes([c[4], c[5], c[6], c[7]]);
+ FontVariation { tag, value }
+ }).collect();
txn.add_font_instance(
key,
font_key,
glyph_size,
unsafe { options.as_ref().cloned() },
unsafe { platform_options.as_ref().cloned() },
- variations.convert_into_vec::<FontVariation>(),
+ variations,
);
}
@@ -2756,8 +2800,19 @@ pub extern "C" fn wr_dp_define_sticky_frame(
horizontal_bounds: StickyOffsetBounds,
applied_offset: LayoutVector2D,
key: SpatialTreeItemKey,
+ animation: *const WrAnimationProperty
) -> WrSpatialId {
assert!(unsafe { is_in_main_thread() });
+ let anim = unsafe { animation.as_ref() };
+ let transform = anim.map(|anim| {
+ debug_assert!(anim.id > 0);
+ match anim.effect_type {
+ WrAnimationType::Transform => {
+ PropertyBinding::Binding(PropertyBindingKey::new(anim.id), LayoutTransform::identity())
+ },
+ _ => unreachable!("sticky elements can only have a transform animated")
+ }
+ });
let spatial_id = state.frame_builder.dl_builder.define_sticky_frame(
parent_spatial_id.to_webrender(state.pipeline_id),
content_rect,
@@ -2771,6 +2826,7 @@ pub extern "C" fn wr_dp_define_sticky_frame(
horizontal_bounds,
applied_offset,
key,
+ transform
);
WrSpatialId { id: spatial_id.0 }