summaryrefslogtreecommitdiffstats
path: root/gfx/webrender_bindings
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
commit8dd16259287f58f9273002717ec4d27e97127719 (patch)
tree3863e62a53829a84037444beab3abd4ed9dfc7d0 /gfx/webrender_bindings
parentReleasing progress-linux version 126.0.1-1~progress7.99u1. (diff)
downloadfirefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz
firefox-8dd16259287f58f9273002717ec4d27e97127719.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/webrender_bindings')
-rw-r--r--gfx/webrender_bindings/DCLayerTree.cpp47
-rw-r--r--gfx/webrender_bindings/DCLayerTree.h8
-rw-r--r--gfx/webrender_bindings/RenderCompositorANGLE.cpp19
-rw-r--r--gfx/webrender_bindings/RenderThread.cpp15
-rw-r--r--gfx/webrender_bindings/RenderThread.h5
-rw-r--r--gfx/webrender_bindings/WebRenderAPI.cpp38
-rw-r--r--gfx/webrender_bindings/WebRenderAPI.h3
-rw-r--r--gfx/webrender_bindings/WebRenderTypes.h7
-rw-r--r--gfx/webrender_bindings/src/bindings.rs98
9 files changed, 178 insertions, 62 deletions
diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp
index 49ca8ee77b..c867740ba5 100644
--- a/gfx/webrender_bindings/DCLayerTree.cpp
+++ b/gfx/webrender_bindings/DCLayerTree.cpp
@@ -751,9 +751,9 @@ DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage(
auto cprofileOut = mDCLayerTree->OutputColorProfile();
bool pretendSrgb = true;
if (pretendSrgb) {
- cprofileOut = color::ColorProfileDesc::From({
- color::Chromaticities::Srgb(),
- color::PiecewiseGammaDesc::Srgb(),
+ cprofileOut = color::ColorProfileDesc::From(color::ColorspaceDesc{
+ .chrom = color::Chromaticities::Srgb(),
+ .tf = color::PiecewiseGammaDesc::Srgb(),
});
}
const auto conversion = color::ColorProfileConversionDesc::From({
@@ -1355,7 +1355,7 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) {
MOZ_ASSERT(mDCLayerTree->GetVideoProcessor());
const UINT vendorId = GetVendorId(mDCLayerTree->GetVideoDevice());
- const bool driverSupportsTrueHDR =
+ const bool driverSupportsAutoHDR =
GetVpAutoHDRSupported(vendorId, mDCLayerTree->GetVideoContext(),
mDCLayerTree->GetVideoProcessor());
const bool contentIsHDR = false; // XXX for now, only non-HDR is supported.
@@ -1364,9 +1364,18 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) {
const bool powerIsCharging = RenderThread::Get()->GetPowerIsCharging();
bool useVpAutoHDR = gfx::gfxVars::WebRenderOverlayVpAutoHDR() &&
- !contentIsHDR && monitorIsHDR && driverSupportsTrueHDR &&
+ !contentIsHDR && monitorIsHDR && driverSupportsAutoHDR &&
powerIsCharging && !mVpAutoHDRFailed;
+ if (profiler_thread_is_being_profiled_for_markers()) {
+ nsPrintfCString str(
+ "useVpAutoHDR %d gfxVars %d contentIsHDR %d monitor %d driver %d "
+ "charging %d failed %d",
+ useVpAutoHDR, gfx::gfxVars::WebRenderOverlayVpAutoHDR(), contentIsHDR,
+ monitorIsHDR, driverSupportsAutoHDR, powerIsCharging, mVpAutoHDRFailed);
+ PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {}, str);
+ }
+
if (!mVideoSwapChain || mSwapChainSize != swapChainSize || mIsDRM != isDRM ||
mUseVpAutoHDR != useVpAutoHDR) {
needsToPresent = true;
@@ -1791,8 +1800,22 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() {
const UINT vendorId = GetVendorId(videoDevice);
const auto powerIsCharging = RenderThread::Get()->GetPowerIsCharging();
- if (gfx::gfxVars::WebRenderOverlayVpSuperResolution() &&
- !mVpSuperResolutionFailed && powerIsCharging) {
+ const bool useSuperResolution =
+ gfx::gfxVars::WebRenderOverlayVpSuperResolution() && powerIsCharging &&
+ !mVpSuperResolutionFailed;
+
+ if (profiler_thread_is_being_profiled_for_markers()) {
+ nsPrintfCString str(
+ "useSuperResolution %d gfxVars %d charging %d failed %d",
+ useSuperResolution, gfx::gfxVars::WebRenderOverlayVpSuperResolution(),
+ powerIsCharging, mVpSuperResolutionFailed);
+ PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {}, str);
+ }
+
+ if (useSuperResolution) {
+ PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {},
+ "SetVpSuperResolution"_ns);
+
hr = SetVpSuperResolution(vendorId, videoContext, videoProcessor, true);
if (FAILED(hr)) {
if (hr != E_NOTIMPL) {
@@ -1803,6 +1826,8 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() {
}
if (mUseVpAutoHDR) {
+ PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {}, "SetVpAutoHDR"_ns);
+
hr = SetVpAutoHDR(vendorId, videoContext, videoProcessor, true);
if (FAILED(hr)) {
gfxCriticalNoteOnce << "SetVpAutoHDR failed: " << gfx::hexa(hr);
@@ -2072,7 +2097,10 @@ void DCLayerTree::DestroyEGLSurface() {
// -
-color::ColorProfileDesc DCLayerTree::QueryOutputColorProfile() {
+} // namespace wr
+namespace gfx {
+
+color::ColorProfileDesc QueryOutputColorProfile() {
// GPU process can't simply init gfxPlatform, (and we don't need most of it)
// but we do need gfxPlatform::GetCMSOutputProfile().
// So we steal what we need through the window:
@@ -2126,6 +2154,9 @@ color::ColorProfileDesc DCLayerTree::QueryOutputColorProfile() {
return ret;
}
+} // namespace gfx
+namespace wr {
+
inline D2D1_MATRIX_5X4_F to_D2D1_MATRIX_5X4_F(const color::mat4& m) {
return D2D1_MATRIX_5X4_F{{{
m.rows[0][0],
diff --git a/gfx/webrender_bindings/DCLayerTree.h b/gfx/webrender_bindings/DCLayerTree.h
index d5ade5781e..8289eaf50d 100644
--- a/gfx/webrender_bindings/DCLayerTree.h
+++ b/gfx/webrender_bindings/DCLayerTree.h
@@ -44,6 +44,10 @@ struct IDCompositionVirtualSurface;
namespace mozilla {
+namespace gfx {
+color::ColorProfileDesc QueryOutputColorProfile();
+}
+
namespace gl {
class GLContext;
}
@@ -248,8 +252,6 @@ class DCLayerTree {
bool mPendingCommit;
- static color::ColorProfileDesc QueryOutputColorProfile();
-
mutable Maybe<color::ColorProfileDesc> mOutputColorProfile;
DCompOverlayTypes mUsedOverlayTypesInFrame = DCompOverlayTypes::NO_OVERLAY;
@@ -258,7 +260,7 @@ class DCLayerTree {
public:
const color::ColorProfileDesc& OutputColorProfile() const {
if (!mOutputColorProfile) {
- mOutputColorProfile = Some(QueryOutputColorProfile());
+ mOutputColorProfile = Some(gfx::QueryOutputColorProfile());
}
return *mOutputColorProfile;
}
diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
index e01ac6a187..ec102074cb 100644
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
@@ -36,8 +36,7 @@
#undef PW_RENDERFULLCONTENT
#define PW_RENDERFULLCONTENT 0x00000002
-namespace mozilla {
-namespace wr {
+namespace mozilla::wr {
extern LazyLogModule gRenderThreadLog;
#define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
@@ -440,11 +439,9 @@ RenderedFrameId RenderCompositorANGLE::EndFrame(
if (!UseCompositor()) {
auto start = TimeStamp::Now();
- if (mWidget->AsWindows()->HasFxrOutputHandler()) {
+ if (auto* fxrHandler = mWidget->AsWindows()->GetFxrOutputHandler()) {
// There is a Firefox Reality handler for this swapchain. Update this
// window's contents to the VR window.
- FxROutputHandler* fxrHandler =
- mWidget->AsWindows()->GetFxrOutputHandler();
if (fxrHandler->TryInitialize(mSwapChain, mDevice)) {
fxrHandler->UpdateOutput(mCtx);
}
@@ -926,12 +923,9 @@ void RenderCompositorANGLE::InitializeUsePartialPresent() {
// Even when mSwapChain1 is null, we could enable WR partial present, since
// when mSwapChain1 is null, SwapChain is blit model swap chain with one
// buffer.
- if (UseCompositor() || mWidget->AsWindows()->HasFxrOutputHandler() ||
- gfx::gfxVars::WebRenderMaxPartialPresentRects() <= 0) {
- mUsePartialPresent = false;
- } else {
- mUsePartialPresent = true;
- }
+ mUsePartialPresent = !UseCompositor() &&
+ !mWidget->AsWindows()->HasFxrOutputHandler() &&
+ gfx::gfxVars::WebRenderMaxPartialPresentRects() > 0;
}
bool RenderCompositorANGLE::UsePartialPresent() { return mUsePartialPresent; }
@@ -1021,5 +1015,4 @@ bool RenderCompositorANGLE::MaybeReadback(
return true;
}
-} // namespace wr
-} // namespace mozilla
+} // namespace mozilla::wr
diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp
index e1a41ee225..cb496c8fc5 100644
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -979,6 +979,21 @@ void RenderThread::RegisterExternalImage(
mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
}
mRenderTextures.emplace(aExternalImageId, texture);
+
+#ifdef DEBUG
+ int32_t maxAllowedIncrease =
+ StaticPrefs::gfx_testing_assert_render_textures_increase();
+
+ if (maxAllowedIncrease <= 0) {
+ mRenderTexturesLastTime = -1;
+ } else {
+ if (mRenderTexturesLastTime < 0) {
+ mRenderTexturesLastTime = static_cast<int32_t>(mRenderTextures.size());
+ }
+ MOZ_ASSERT((static_cast<int32_t>(mRenderTextures.size()) -
+ mRenderTexturesLastTime) < maxAllowedIncrease);
+ }
+#endif
}
void RenderThread::UnregisterExternalImage(
diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h
index f9ab1e742e..6191a28bcd 100644
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -489,6 +489,11 @@ class RenderThread final {
RefPtr<nsIRunnable> mRenderTextureOpsRunnable
MOZ_GUARDED_BY(mRenderTextureMapLock);
+#ifdef DEBUG
+ // used for tests only to ensure render textures don't increase
+ int32_t mRenderTexturesLastTime MOZ_GUARDED_BY(mRenderTextureMapLock) = -1;
+#endif
+
// Set from MainThread, read from either MainThread or RenderThread
bool mHasShutdown;
diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp
index 09a024a897..105c2dff98 100644
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -537,7 +537,25 @@ bool WebRenderAPI::CheckIsRemoteTextureReady(
layers::CompositorThread()->Dispatch(runnable.forget());
};
+ bool isReady = true;
+ while (!aList->mList.empty() && isReady) {
+ auto& front = aList->mList.front();
+ isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady(
+ front, callback);
+ if (isReady) {
+ aList->mList.pop();
+ }
+ }
+
+ if (isReady) {
+ return true;
+ }
+
+#ifndef DEBUG
const auto maxWaitDurationMs = 10000;
+#else
+ const auto maxWaitDurationMs = 30000;
+#endif
const auto now = TimeStamp::Now();
const auto waitDurationMs =
static_cast<uint32_t>((now - aTimeStamp).ToMilliseconds());
@@ -548,20 +566,7 @@ bool WebRenderAPI::CheckIsRemoteTextureReady(
gfxCriticalNote << "RemoteTexture ready timeout";
}
- bool isReady = true;
- while (!aList->mList.empty() && isReady) {
- auto& front = aList->mList.front();
- isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady(
- front, callback);
- if (isTimeout) {
- isReady = true;
- }
- if (isReady) {
- aList->mList.pop();
- }
- }
-
- return isReady;
+ return false;
}
void WebRenderAPI::WaitRemoteTextureReady(
@@ -1256,11 +1261,12 @@ wr::WrSpatialId DisplayListBuilder::DefineStickyFrame(
const float* aRightMargin, const float* aBottomMargin,
const float* aLeftMargin, const StickyOffsetBounds& aVerticalBounds,
const StickyOffsetBounds& aHorizontalBounds,
- const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey) {
+ const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey,
+ const WrAnimationProperty* aAnimation) {
auto spatialId = wr_dp_define_sticky_frame(
mWrState, mCurrentSpaceAndClipChain.space, aContentRect, aTopMargin,
aRightMargin, aBottomMargin, aLeftMargin, aVerticalBounds,
- aHorizontalBounds, aAppliedOffset, aKey);
+ aHorizontalBounds, aAppliedOffset, aKey, aAnimation);
WRDL_LOG("DefineSticky id=%zu c=%s t=%s r=%s b=%s l=%s v=%s h=%s a=%s\n",
mWrState, spatialId.id, ToString(aContentRect).c_str(),
diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h
index 16a9acc0ab..eff7b3039a 100644
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -600,7 +600,8 @@ class DisplayListBuilder final {
const float* aRightMargin, const float* aBottomMargin,
const float* aLeftMargin, const StickyOffsetBounds& aVerticalBounds,
const StickyOffsetBounds& aHorizontalBounds,
- const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey);
+ const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey,
+ const WrAnimationProperty* aAnimation);
Maybe<wr::WrSpatialId> GetScrollIdForDefinedScrollLayer(
layers::ScrollableLayerGuid::ViewID aViewId) const;
diff --git a/gfx/webrender_bindings/WebRenderTypes.h b/gfx/webrender_bindings/WebRenderTypes.h
index 3216a0afd6..84c9d5cf63 100644
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -667,6 +667,13 @@ struct Vec<uint8_t> final {
}
void SetEmpty() {
+ // We need to ensure that (data, capacity, length) always remain valid
+ // to be passed to Vec::from_raw_parts. In particular, this requires that
+ // inner.data is always non-null, even for zero-capacity Vecs.
+
+ // Set inner.data to the equivalent of ptr::NonNull::dangling().as_ptr(),
+ // i.e. a non-null value that is aligned with T's alignment, T being u8
+ // here.
inner.data = (uint8_t*)1;
inner.capacity = 0;
inner.length = 0;
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 }