Bug 1460861 - Update webrender to commit 9d20df4e76e3b19c569fd89965f70a2c278ff0c8. r=Gankro

MozReview-Commit-ID: C9hlaYMrM7W

--HG--
extra : rebase_source : 83eb50452bfa712dd011a90a1fc1ceeddbce758f
This commit is contained in:
Kartikaya Gupta 2018-05-14 10:25:05 -04:00
parent 95f8f2a563
commit d76b5fa54a
13 changed files with 338 additions and 269 deletions

View File

@ -43,14 +43,14 @@ impl Example for App {
let bounds = (0, 0).to(200, 200);
let filters = vec![
FilterOp::Opacity(PropertyBinding::Binding(self.opacity_key), self.opacity),
FilterOp::Opacity(PropertyBinding::Binding(self.opacity_key, self.opacity), self.opacity),
];
let info = LayoutPrimitiveInfo::new(bounds);
builder.push_stacking_context(
&info,
None,
Some(PropertyBinding::Binding(self.property_key)),
Some(PropertyBinding::Binding(self.property_key, LayoutTransform::identity())),
TransformStyle::Flat,
None,
MixBlendMode::Normal,

View File

@ -65,7 +65,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
Some(PropertyBinding::Binding(PropertyBindingKey::new(42))),
Some(PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity())),
TransformStyle::Flat,
None,
MixBlendMode::Normal,

View File

@ -20,8 +20,6 @@ uniform sampler2DArray sCacheRGBA8;
// An A8 target for standalone tasks that is available to all passes.
uniform sampler2DArray sSharedCacheA8;
uniform sampler2D sGradients;
vec2 clamp_rect(vec2 pt, RectWithSize rect) {
return clamp(pt, rect.p0, rect.p0 + rect.size);
}

View File

@ -21,7 +21,8 @@ use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentTaskId, CachedGradient, DeferredResolve};
use prim_store::{EdgeAaSegmentMask, ImageSource, PictureIndex, PrimitiveIndex, PrimitiveKind};
use prim_store::{PrimitiveMetadata, PrimitiveRun, PrimitiveStore};
use prim_store::{PrimitiveMetadata, PrimitiveRun, PrimitiveStore, VisibleGradientTile};
use prim_store::CachedGradientIndex;
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind};
use renderer::{BLOCKS_PER_UV_RECT, ShaderColorMode};
@ -615,6 +616,8 @@ impl AlphaBatchBuilder {
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
match brush.kind {
BrushKind::Image { ref visible_tiles, .. } => !visible_tiles.is_empty(),
BrushKind::LinearGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(),
BrushKind::RadialGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(),
_ => false,
}
}
@ -1018,6 +1021,40 @@ impl AlphaBatchBuilder {
}
}
}
BrushKind::LinearGradient { gradient_index, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
add_gradient_tiles(
visible_tiles,
gradient_index,
BrushBatchKind::LinearGradient,
specified_blend_mode,
&task_relative_bounding_rect,
clip_chain_rect_index,
scroll_id,
task_address,
clip_task_address,
z,
ctx,
gpu_cache,
&mut self.batch_list,
);
}
BrushKind::RadialGradient { gradient_index, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
add_gradient_tiles(
visible_tiles,
gradient_index,
BrushBatchKind::RadialGradient,
specified_blend_mode,
&task_relative_bounding_rect,
clip_chain_rect_index,
scroll_id,
task_address,
clip_task_address,
z,
ctx,
gpu_cache,
&mut self.batch_list,
);
}
_ => {
if let Some((batch_kind, textures, user_data)) = brush.get_batch_params(
ctx.resource_cache,
@ -1348,6 +1385,57 @@ impl AlphaBatchBuilder {
}
}
fn add_gradient_tiles(
visible_tiles: &[VisibleGradientTile],
gradient_index: CachedGradientIndex,
kind: BrushBatchKind,
blend_mode: BlendMode,
task_relative_bounding_rect: &DeviceIntRect,
clip_chain_rect_index: ClipChainRectIndex,
scroll_id: ClipScrollNodeIndex,
task_address: RenderTaskAddress,
clip_task_address: RenderTaskAddress,
z: ZBufferId,
ctx: &RenderTargetContext,
gpu_cache: &GpuCache,
batch_list: &mut BatchList,
) {
batch_list.add_bounding_rect(task_relative_bounding_rect);
let batch = batch_list.get_suitable_batch(
BatchKey {
blend_mode: blend_mode,
kind: BatchKind::Brush(kind),
textures: BatchTextures::no_texture(),
},
task_relative_bounding_rect
);
let stops_handle = &ctx.cached_gradients[gradient_index.0].handle;
let user_data = [stops_handle.as_int(gpu_cache), 0, 0];
let base_instance = BrushInstance {
picture_address: task_address,
prim_address: GpuCacheAddress::invalid(),
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
};
for tile in visible_tiles {
batch.push(PrimitiveInstance::from(
BrushInstance {
prim_address: gpu_cache.get_address(&tile.handle),
..base_instance
}
));
}
}
fn get_image_tile_params(
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,

View File

@ -1800,7 +1800,7 @@ impl<'a> DisplayListFlattener<'a> {
}
}
fn add_gradient_impl(
pub fn add_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
@ -1809,9 +1809,19 @@ impl<'a> DisplayListFlattener<'a> {
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: LayoutSize,
mut tile_spacing: LayoutSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());
let mut prim_rect = info.rect;
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
let info = LayoutPrimitiveInfo {
rect: prim_rect,
.. *info
};
// Try to ensure that if the gradient is specified in reverse, then so long as the stops
// are also supplied in reverse that the rendered result will be equivalent. To do this,
// a reference orientation for the gradient line must be chosen, somewhat arbitrarily, so
@ -1840,109 +1850,15 @@ impl<'a> DisplayListFlattener<'a> {
end_point: ep,
gradient_index,
stretch_size,
tile_spacing,
visible_tiles: Vec::new(),
},
None,
);
let prim = PrimitiveContainer::Brush(prim);
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
}
pub fn add_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
start_point: LayoutPoint,
end_point: LayoutPoint,
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
stretch_size: LayoutSize,
mut tile_spacing: LayoutSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());
let mut prim_rect = info.rect;
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
let info = LayoutPrimitiveInfo {
rect: prim_rect,
.. *info
};
if tile_spacing != LayoutSize::zero() {
let prim_infos = info.decompose(
stretch_size,
tile_spacing,
64 * 64,
);
if !prim_infos.is_empty() {
for prim_info in prim_infos {
self.add_gradient_impl(
clip_and_scroll,
&prim_info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
prim_info.rect.size,
);
}
return;
}
}
self.add_gradient_impl(
clip_and_scroll,
&info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
stretch_size,
);
}
fn add_radial_gradient_impl(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
center: LayoutPoint,
start_radius: f32,
end_radius: f32,
ratio_xy: f32,
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: LayoutSize,
) {
let prim = BrushPrimitive::new(
BrushKind::RadialGradient {
stops_range: stops,
extend_mode,
center,
start_radius,
end_radius,
ratio_xy,
gradient_index,
stretch_size,
},
None,
);
self.add_primitive(
clip_and_scroll,
info,
Vec::new(),
PrimitiveContainer::Brush(prim),
);
self.add_primitive(clip_and_scroll, &info, Vec::new(), prim);
}
pub fn add_radial_gradient(
@ -1968,44 +1884,27 @@ impl<'a> DisplayListFlattener<'a> {
.. *info
};
if tile_spacing != LayoutSize::zero() {
let prim_infos = info.decompose(
let prim = BrushPrimitive::new(
BrushKind::RadialGradient {
stops_range: stops,
extend_mode,
center,
start_radius,
end_radius,
ratio_xy,
gradient_index,
stretch_size,
tile_spacing,
64 * 64,
);
visible_tiles: Vec::new(),
},
None,
);
if !prim_infos.is_empty() {
for prim_info in prim_infos {
self.add_radial_gradient_impl(
clip_and_scroll,
&prim_info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
stretch_size,
);
}
return;
}
}
self.add_radial_gradient_impl(
self.add_primitive(
clip_and_scroll,
&info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
stretch_size,
Vec::new(),
PrimitiveContainer::Brush(prim),
);
}
@ -2208,72 +2107,6 @@ pub fn build_scene(config: &FrameBuilderConfig, request: SceneRequest) -> BuiltS
}
}
trait PrimitiveInfoTiler {
fn decompose(
&self,
tile_size: LayoutSize,
tile_spacing: LayoutSize,
max_prims: usize,
) -> Vec<LayoutPrimitiveInfo>;
}
impl PrimitiveInfoTiler for LayoutPrimitiveInfo {
fn decompose(
&self,
tile_size: LayoutSize,
tile_spacing: LayoutSize,
max_prims: usize,
) -> Vec<LayoutPrimitiveInfo> {
let mut prims = Vec::new();
let tile_repeat = tile_size + tile_spacing;
if tile_repeat.width <= 0.0 ||
tile_repeat.height <= 0.0 {
return prims;
}
if tile_repeat.width < self.rect.size.width ||
tile_repeat.height < self.rect.size.height {
let clip_rect = self.clip_rect
.intersection(&self.rect)
.unwrap_or_else(LayoutRect::zero);
let rect_p0 = self.rect.origin;
let rect_p1 = self.rect.bottom_right();
let mut y0 = rect_p0.y;
while y0 < rect_p1.y {
let mut x0 = rect_p0.x;
while x0 < rect_p1.x {
prims.push(LayoutPrimitiveInfo {
rect: LayoutRect::new(
LayoutPoint::new(x0, y0),
tile_size,
),
clip_rect,
is_backface_visible: self.is_backface_visible,
tag: self.tag,
});
// Mostly a safety against a crazy number of primitives
// being generated. If we exceed that amount, just bail
// out and only draw the maximum amount.
if prims.len() > max_prims {
warn!("too many prims found due to repeat/tile. dropping extra prims!");
return prims;
}
x0 += tile_repeat.width;
}
y0 += tile_repeat.height;
}
}
prims
}
}
/// Properties of a stacking context that are maintained
/// during creation of the scene. These structures are
/// not persisted after the initial scene build.

View File

@ -163,7 +163,7 @@ impl PicturePrimitive {
Some(PictureCompositeMode::Filter(ref mut filter)) => {
match *filter {
FilterOp::Opacity(ref binding, ref mut value) => {
*value = properties.resolve_float(binding, *value);
*value = properties.resolve_float(binding);
}
_ => {}
}

View File

@ -231,7 +231,7 @@ impl OpacityBinding {
let mut new_opacity = 1.0;
for binding in &self.bindings {
let opacity = scene_properties.resolve_float(binding, 1.0);
let opacity = scene_properties.resolve_float(binding);
new_opacity = new_opacity * opacity;
}
@ -249,6 +249,11 @@ pub struct VisibleImageTile {
pub edge_flags: EdgeAaSegmentMask,
}
#[derive(Debug)]
pub struct VisibleGradientTile {
pub handle: GpuCacheHandle,
}
#[derive(Debug)]
pub enum BrushKind {
Solid {
@ -285,6 +290,8 @@ pub enum BrushKind {
end_radius: f32,
ratio_xy: f32,
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
visible_tiles: Vec<VisibleGradientTile>,
},
LinearGradient {
gradient_index: CachedGradientIndex,
@ -295,6 +302,8 @@ pub enum BrushKind {
start_point: LayoutPoint,
end_point: LayoutPoint,
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
visible_tiles: Vec<VisibleGradientTile>,
},
Border {
request: ImageRequest,
@ -1423,7 +1432,7 @@ impl PrimitiveStore {
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
let mut is_tiled_image = false;
let mut is_tiled = false;
let metadata = &mut self.cpu_metadata[prim_index.0];
#[cfg(debug_assertions)]
{
@ -1467,7 +1476,7 @@ impl PrimitiveStore {
// Set if we need to request the source image from the cache this frame.
if let Some(image_properties) = image_properties {
*current_epoch = image_properties.epoch;
is_tiled_image = image_properties.tiling.is_some();
is_tiled = image_properties.tiling.is_some();
// If the opacity changed, invalidate the GPU cache so that
// the new color for this primitive gets uploaded.
@ -1481,7 +1490,7 @@ impl PrimitiveStore {
image_properties.descriptor.is_opaque &&
opacity_binding.current == 1.0;
if *tile_spacing != LayoutSize::zero() && !is_tiled_image {
if *tile_spacing != LayoutSize::zero() && !is_tiled {
*source = ImageSource::Cache {
// Size in device-pixels we need to allocate in render task cache.
size: DeviceIntSize::new(
@ -1496,7 +1505,7 @@ impl PrimitiveStore {
// we need to pre-render it to the render task cache.
if let Some(rect) = sub_rect {
// We don't properly support this right now.
debug_assert!(!is_tiled_image);
debug_assert!(!is_tiled);
*source = ImageSource::Cache {
// Size in device-pixels we need to allocate in render task cache.
size: rect.size,
@ -1698,29 +1707,107 @@ impl PrimitiveStore {
);
}
}
BrushKind::RadialGradient { gradient_index, stops_range, .. } => {
let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle;
if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
let gradient_builder = GradientGpuBlockBuilder::new(
stops_range,
pic_context.display_list,
);
gradient_builder.build(
false,
&mut request,
BrushKind::RadialGradient {
gradient_index,
stops_range,
center,
start_radius,
end_radius,
ratio_xy,
extend_mode,
stretch_size,
tile_spacing,
ref mut visible_tiles,
..
} => {
build_gradient_stops_request(
gradient_index,
stops_range,
false,
frame_state,
pic_context,
);
if tile_spacing != LayoutSize::zero() {
is_tiled = true;
decompose_repeated_primitive(
visible_tiles,
metadata,
&stretch_size,
&tile_spacing,
prim_run_context,
frame_context,
frame_state,
&mut |rect, clip_rect, mut request| {
request.push(*rect);
request.push(*clip_rect);
request.push([
center.x,
center.y,
start_radius,
end_radius,
]);
request.push([
ratio_xy,
pack_as_float(extend_mode as u32),
stretch_size.width,
stretch_size.height,
]);
request.write_segment(*rect, [0.0; 4]);
},
);
}
}
BrushKind::LinearGradient { gradient_index, stops_range, reverse_stops, .. } => {
let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle;
if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
let gradient_builder = GradientGpuBlockBuilder::new(
stops_range,
pic_context.display_list,
);
gradient_builder.build(
reverse_stops,
&mut request,
BrushKind::LinearGradient {
gradient_index,
stops_range,
reverse_stops,
start_point,
end_point,
extend_mode,
stretch_size,
tile_spacing,
ref mut visible_tiles,
..
} => {
build_gradient_stops_request(
gradient_index,
stops_range,
reverse_stops,
frame_state,
pic_context,
);
if tile_spacing != LayoutSize::zero() {
is_tiled = true;
decompose_repeated_primitive(
visible_tiles,
metadata,
&stretch_size,
&tile_spacing,
prim_run_context,
frame_context,
frame_state,
&mut |rect, clip_rect, mut request| {
request.push(*rect);
request.push(*clip_rect);
request.push([
start_point.x,
start_point.y,
end_point.x,
end_point.y,
]);
request.push([
pack_as_float(extend_mode as u32),
stretch_size.width,
stretch_size.height,
0.0,
]);
request.write_segment(*rect, [0.0; 4]);
}
);
}
}
@ -1751,7 +1838,7 @@ impl PrimitiveStore {
}
}
if is_tiled_image {
if is_tiled {
// we already requested each tile's gpu data.
return;
}
@ -2480,6 +2567,80 @@ impl PrimitiveStore {
}
}
fn build_gradient_stops_request(
gradient_index: CachedGradientIndex,
stops_range: ItemRange<GradientStop>,
reverse_stops: bool,
frame_state: &mut FrameBuildingState,
pic_context: &PictureContext
) {
let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle;
if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
let gradient_builder = GradientGpuBlockBuilder::new(
stops_range,
pic_context.display_list,
);
gradient_builder.build(
reverse_stops,
&mut request,
);
}
}
fn decompose_repeated_primitive(
visible_tiles: &mut Vec<VisibleGradientTile>,
metadata: &mut PrimitiveMetadata,
stretch_size: &LayoutSize,
tile_spacing: &LayoutSize,
prim_run_context: &PrimitiveRunContext,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
callback: &mut FnMut(&LayoutRect, &LayoutRect, GpuDataRequest),
) {
visible_tiles.clear();
// Tighten the clip rect because decomposing the repeated image can
// produce primitives that are partially covering the original image
// rect and we want to clip these extra parts out.
let tight_clip_rect = metadata.local_clip_rect.intersection(&metadata.local_rect).unwrap();
let visible_rect = compute_conservative_visible_rect(
prim_run_context,
frame_context,
&tight_clip_rect
);
let stride = *stretch_size + *tile_spacing;
for_each_repetition(
&metadata.local_rect,
&visible_rect,
&stride,
&mut |origin, _| {
let mut handle = GpuCacheHandle::new();
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
let rect = LayoutRect {
origin: *origin,
size: *stretch_size,
};
callback(&rect, &tight_clip_rect, request);
}
visible_tiles.push(VisibleGradientTile { handle });
}
);
if visible_tiles.is_empty() {
// At this point if we don't have tiles to show it means we could probably
// have done a better a job at culling during an earlier stage.
// Clearing the screen rect has the effect of "culling out" the primitive
// from the point of view of the batch builder, and ensures we don't hit
// assertions later on because we didn't request any image.
metadata.screen_rect = None;
}
}
fn compute_conservative_visible_rect(
prim_run_context: &PrimitiveRunContext,
frame_context: &FrameBuildingContext,

View File

@ -54,15 +54,11 @@ impl SceneProperties {
) -> LayoutTransform {
match *property {
PropertyBinding::Value(value) => value,
PropertyBinding::Binding(ref key) => {
PropertyBinding::Binding(ref key, v) => {
self.transform_properties
.get(&key.id)
.cloned()
.unwrap_or_else(|| {
warn!("Property binding has an invalid value.");
debug!("key={:?}", key);
LayoutTransform::identity()
})
.unwrap_or(v)
}
}
}
@ -70,20 +66,15 @@ impl SceneProperties {
/// Get the current value for a float property.
pub fn resolve_float(
&self,
property: &PropertyBinding<f32>,
default_value: f32
property: &PropertyBinding<f32>
) -> f32 {
match *property {
PropertyBinding::Value(value) => value,
PropertyBinding::Binding(ref key) => {
PropertyBinding::Binding(ref key, v) => {
self.float_properties
.get(&key.id)
.cloned()
.unwrap_or_else(|| {
warn!("Property binding has an invalid value.");
debug!("key={:?}", key);
default_value
})
.unwrap_or(v)
}
}
}

View File

@ -1078,10 +1078,13 @@ impl<T> PropertyBindingKey<T> {
/// A binding property can either be a specific value
/// (the normal, non-animated case) or point to a binding location
/// to fetch the current value from.
/// Note that Binding has also a non-animated value, the value is
/// used for the case where the animation is still in-delay phase
/// (i.e. the animation doesn't produce any animation values).
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum PropertyBinding<T> {
Value(T),
Binding(PropertyBindingKey<T>),
Binding(PropertyBindingKey<T>, T),
}
impl<T> From<T> for PropertyBinding<T> {
@ -1090,12 +1093,6 @@ impl<T> From<T> for PropertyBinding<T> {
}
}
impl<T> From<PropertyBindingKey<T>> for PropertyBinding<T> {
fn from(key: PropertyBindingKey<T>) -> PropertyBinding<T> {
PropertyBinding::Binding(key)
}
}
/// The current value of an animated property. This is
/// supplied by the calling code.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]

View File

@ -1 +1 @@
4811a6e7c06f9dd1b4056e5f5e66983842983ba0
9d20df4e76e3b19c569fd89965f70a2c278ff0c8

View File

@ -25,6 +25,12 @@ fn deserialize_blob(blob: &[u8]) -> Result<ColorU, ()> {
};
}
// perform floor((x * a) / 255. + 0.5) see "Three wrongs make a right" for deriviation
fn premul(x: u8, a: u8) -> u8 {
let t = (x as u32) * (a as u32) + 128;
((t + (t >> 8)) >> 8) as u8
}
// This is the function that applies the deserialized drawing commands and generates
// actual image data.
fn render_blob(
@ -73,10 +79,11 @@ fn render_blob(
match descriptor.format {
ImageFormat::BGRA8 => {
texels[((y * descriptor.width + x) * 4 + 0) as usize] = color.b * checker + tc;
texels[((y * descriptor.width + x) * 4 + 1) as usize] = color.g * checker + tc;
texels[((y * descriptor.width + x) * 4 + 2) as usize] = color.r * checker + tc;
texels[((y * descriptor.width + x) * 4 + 3) as usize] = color.a * checker + tc;
let a = color.a * checker + tc;
texels[((y * descriptor.width + x) * 4 + 0) as usize] = premul(color.b * checker + tc, a);
texels[((y * descriptor.width + x) * 4 + 1) as usize] = premul(color.g * checker + tc, a);
texels[((y * descriptor.width + x) * 4 + 2) as usize] = premul(color.r * checker + tc, a);
texels[((y * descriptor.width + x) * 4 + 3) as usize] = a;
}
ImageFormat::R8 => {
texels[(y * descriptor.width + x) as usize] = color.a * checker + tc;

View File

@ -45,27 +45,21 @@ impl SceneProperties {
match property {
PropertyBinding::Value(matrix) => matrix,
PropertyBinding::Binding(ref key) => self.transform_properties
PropertyBinding::Binding(ref key, v) => self.transform_properties
.get(&key.id)
.cloned()
.unwrap_or_else(|| {
println!("Property binding {:?} has an invalid value.", key);
LayoutTransform::identity()
}),
.unwrap_or(v),
}
}
/// Get the current value for a float property.
pub fn resolve_float(&self, property: &PropertyBinding<f32>, default_value: f32) -> f32 {
pub fn resolve_float(&self, property: &PropertyBinding<f32>) -> f32 {
match *property {
PropertyBinding::Value(value) => value,
PropertyBinding::Binding(ref key) => self.float_properties
PropertyBinding::Binding(ref key, v) => self.float_properties
.get(&key.id)
.cloned()
.unwrap_or_else(|| {
println!("Property binding {:?} has an invalid value.", key);
default_value
}),
.unwrap_or(v),
}
}
}

View File

@ -223,7 +223,7 @@ fn write_stacking_context(
FilterOp::Invert(x) => { filters.push(Yaml::String(format!("invert({})", x))) }
FilterOp::Opacity(x, _) => {
filters.push(Yaml::String(format!("opacity({})",
properties.resolve_float(&x, 1.0))))
properties.resolve_float(&x))))
}
FilterOp::Saturate(x) => { filters.push(Yaml::String(format!("saturate({})", x))) }
FilterOp::Sepia(x) => { filters.push(Yaml::String(format!("sepia({})", x))) }