--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -608,17 +608,17 @@ void
BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
wr::ImageRendering aFilter,
const Range<wr::ImageKey>& aImageKeys)
{
if (GetFormat() != gfx::SurfaceFormat::YUV) {
MOZ_ASSERT(aImageKeys.length() == 1);
- aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
+ aBuilder.PushImage(aBounds, aClip, true, wr::CompositionOp::Over, aFilter, aImageKeys[0]);
} else {
MOZ_ASSERT(aImageKeys.length() == 3);
aBuilder.PushYCbCrPlanarImage(aBounds,
aClip,
true,
aImageKeys[0],
aImageKeys[1],
aImageKeys[2],
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -206,17 +206,17 @@ MacIOSurfaceTextureHostOGL::PushDisplayI
{
switch (GetFormat()) {
case gfx::SurfaceFormat::R8G8B8X8:
case gfx::SurfaceFormat::R8G8B8A8:
case gfx::SurfaceFormat::B8G8R8A8:
case gfx::SurfaceFormat::B8G8R8X8: {
MOZ_ASSERT(aImageKeys.length() == 1);
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
- aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
+ aBuilder.PushImage(aBounds, aClip, true, wr::CompositionOp::Over, aFilter, aImageKeys[0]);
break;
}
case gfx::SurfaceFormat::YUV422: {
MOZ_ASSERT(aImageKeys.length() == 1);
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
aBuilder.PushYCbCrInterleavedImage(aBounds,
aClip,
true,
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -307,16 +307,17 @@ AsyncImagePipelineManager::ApplyAsyncIma
pipeline->mFilter,
range_keys);
HoldExternalImage(pipelineId, epoch, pipeline->mCurrentTexture->AsWebRenderTextureHost());
} else {
MOZ_ASSERT(keys.Length() == 1);
builder.PushImage(wr::ToLayoutRect(rect),
wr::ToLayoutRect(rect),
true,
+ wr::CompositionOp::Over,
pipeline->mFilter,
keys[0]);
}
builder.PopStackingContext();
wr::BuiltDisplayList dl;
wr::LayoutSize builderContentSize;
builder.Finalize(builderContentSize, dl);
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -327,17 +327,18 @@ WebRenderCommandBuilder::PushImage(nsDis
return true;
}
if (!key) {
return false;
}
auto r = aSc.ToRelativeLayoutRect(aRect);
gfx::SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
- aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), wr::ToImageRendering(sampleFilter), key.value());
+ aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), wr::CompositionOp::Over,
+ wr::ToImageRendering(sampleFilter), key.value());
return true;
}
static void
PaintItemByDrawTarget(nsDisplayItem* aItem,
gfx::DrawTarget* aDT,
const LayerRect& aImageRect,
@@ -593,17 +594,17 @@ WebRenderCommandBuilder::PushItemAsImage
if (!fallbackData) {
return false;
}
wr::LayoutRect dest = aSc.ToRelativeLayoutRect(imageRect);
gfx::SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
aBuilder.PushImage(dest,
dest,
- !aItem->BackfaceIsHidden(),
+ !aItem->BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToImageRendering(sampleFilter),
fallbackData->GetKey().value());
return true;
}
void
WebRenderCommandBuilder::RemoveUnusedAndResetWebRenderUserData()
{
--- a/gfx/webrender/res/ps_rectangle.glsl
+++ b/gfx/webrender/res/ps_rectangle.glsl
@@ -44,11 +44,11 @@ void main(void) {
#ifdef WR_FEATURE_TRANSFORM
alpha = 0.0;
init_transform_fs(vLocalPos, alpha);
#endif
#ifdef WR_FEATURE_CLIP
alpha = min(alpha, do_clip());
#endif
- oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
+ oFragColor = vColor * vec4(alpha * vColor.a, alpha * vColor.a, alpha * vColor.a, alpha);
}
#endif
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -1,14 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::shader_source;
-use api::ImageFormat;
+use api::{CompositionOp, ImageFormat};
use api::{DeviceIntRect, DeviceUintSize};
use euclid::Transform3D;
use gleam::gl;
use internal_types::RenderTargetMode;
use std::fs::File;
use std::io::Read;
use std::iter::repeat;
use std::mem;
@@ -1867,18 +1867,53 @@ impl Device {
pub fn set_blend(&self, enable: bool) {
if enable {
self.gl.enable(gl::BLEND);
} else {
self.gl.disable(gl::BLEND);
}
}
- pub fn set_blend_mode_premultiplied_alpha(&self) {
- self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
+ pub fn set_blend_mode_premultiplied_alpha(&self, op: CompositionOp) {
+ match op {
+ CompositionOp::Over => {
+ self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
+ },
+ CompositionOp::Add => {
+ self.gl.blend_func(gl::ONE, gl::ONE);
+ },
+ CompositionOp::Atop => {
+ self.gl.blend_func(gl::DST_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
+ },
+ CompositionOp::Out => {
+ self.gl.blend_func(gl::ONE_MINUS_DST_ALPHA, gl::ZERO);
+ },
+ CompositionOp::In => {
+ self.gl.blend_func(gl::DST_ALPHA, gl::ZERO);
+ },
+ CompositionOp::Source => {
+ self.gl.blend_func(gl::ONE, gl::ZERO);
+ },
+ CompositionOp::DestIn => {
+ self.gl.blend_func(gl::ZERO, gl::SRC_ALPHA);
+ },
+ CompositionOp::DestOut => {
+ self.gl.blend_func(gl::ZERO, gl::ONE_MINUS_SRC_ALPHA);
+ },
+ CompositionOp::DestOver => {
+ self.gl.blend_func(gl::ONE_MINUS_DST_ALPHA, gl::ONE);
+ },
+ CompositionOp::DestAtop => {
+ self.gl.blend_func(gl::ONE_MINUS_DST_ALPHA, gl::SRC_ALPHA);
+ },
+ CompositionOp::Xor => {
+ self.gl.blend_func(gl::ONE_MINUS_DST_ALPHA,
+ gl::ONE_MINUS_SRC_ALPHA);
+ },
+ }
self.gl.blend_equation(gl::FUNC_ADD);
}
pub fn set_blend_mode_alpha(&self) {
self.gl.blend_func_separate(
gl::SRC_ALPHA,
gl::ONE_MINUS_SRC_ALPHA,
gl::ONE,
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -525,16 +525,17 @@ impl Frame {
);
}
}
SpecificDisplayItem::Line(ref info) => {
let prim_info = LayerPrimitiveInfo {
rect: LayerRect::zero(),
local_clip: *item.local_clip(),
is_backface_visible: prim_info.is_backface_visible,
+ composition_op: prim_info.composition_op,
tag: prim_info.tag,
};
context.builder.add_line(
clip_and_scroll,
&prim_info,
info.baseline,
info.start,
@@ -1168,16 +1169,17 @@ fn try_to_add_rectangle_splitting_on_cli
// less masking some cases.
let mut clipped_rects = Vec::new();
subtract_rect(&info.rect, &inner_unclipped_rect, &mut clipped_rects);
let prim_info = LayerPrimitiveInfo {
rect: inner_unclipped_rect,
local_clip: LocalClip::from(*info.local_clip.clip_rect()),
is_backface_visible: info.is_backface_visible,
+ composition_op: info.composition_op,
tag: None,
};
context.builder.add_solid_rectangle(
*clip_and_scroll,
&prim_info,
color,
PrimitiveFlags::None,
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -1,14 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{BorderDetails, BorderDisplayItem, BorderRadius, BoxShadowClipMode, BuiltDisplayList};
-use api::{ClipMode, ComplexClipRegion, ClipAndScrollInfo, ClipId, ColorF, LayoutSize};
+use api::{ClipMode, ComplexClipRegion, ClipAndScrollInfo, ClipId, CompositionOp, ColorF, LayoutSize};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
use api::{ExtendMode, FilterOp, FontInstance, FontRenderMode};
use api::{GlyphInstance, GlyphOptions, GradientStop, HitTestFlags, HitTestItem, HitTestResult};
use api::{ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect};
use api::{LayerPixel, LayerSize, LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation};
use api::{LineStyle, LocalClip, PipelineId, RepeatMode};
use api::{ScrollSensitivity, Shadow, TileOffset, TransformStyle};
use api::{WorldPixel, WorldPoint, YuvColorSpace, YuvData, device_length};
@@ -249,16 +249,17 @@ impl FrameBuilder {
));
}
let clip_sources = self.clip_store.insert(ClipSources::new(clip_sources));
let prim_index = self.prim_store.add_primitive(
&info.rect,
&info.local_clip.clip_rect(),
info.is_backface_visible,
+ info.composition_op,
clip_sources,
info.tag,
container,
);
prim_index
}
@@ -615,19 +616,20 @@ impl FrameBuilder {
&mut self,
clip_and_scroll: ClipAndScrollInfo,
info: &LayerPrimitiveInfo,
color: &ColorF,
flags: PrimitiveFlags,
) {
let prim = RectanglePrimitive { color: *color };
- // Don't add transparent rectangles to the draw list, but do consider them for hit
+ // When using the default operator (operator over), don't add
+ // transparent rectangles to the draw list, but do consider them for hit
// testing. This allows specifying invisible hit testing areas.
- if color.a == 0.0 {
+ if color.a == 0.0 && info.composition_op == CompositionOp::Over {
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
return;
}
let prim_index = self.add_primitive(
clip_and_scroll,
info,
Vec::new(),
@@ -2084,17 +2086,17 @@ impl FrameBuilder {
if stacking_context.isolation == ContextIsolation::Full && composite_count == 0
{
let mut prev_task = alpha_task_stack.pop().unwrap();
let screen_origin = current_task.as_alpha_batch().screen_origin;
let current_task_id = render_tasks.add(current_task);
let item = AlphaRenderItem::HardwareComposite(
stacking_context_index,
current_task_id,
- HardwareCompositeOp::PremultipliedAlpha,
+ HardwareCompositeOp::PremultipliedAlpha(CompositionOp::Over),
screen_origin,
next_z,
);
next_z += 1;
prev_task.as_alpha_batch_mut().items.push(item);
prev_task.children.push(current_task_id);
current_task = prev_task;
}
@@ -2115,17 +2117,17 @@ impl FrameBuilder {
RenderTargetKind::Color,
&[],
ClearMode::Transparent,
);
let blur_render_task_id = render_tasks.add(blur_render_task);
let item = AlphaRenderItem::HardwareComposite(
stacking_context_index,
blur_render_task_id,
- HardwareCompositeOp::PremultipliedAlpha,
+ HardwareCompositeOp::PremultipliedAlpha(CompositionOp::Over),
DeviceIntPoint::new(
screen_origin.x - blur_radius.0,
screen_origin.y - blur_radius.0,
),
next_z,
);
prev_task.as_alpha_batch_mut().items.push(item);
prev_task.children.push(blur_render_task_id);
@@ -2215,17 +2217,17 @@ impl FrameBuilder {
output_pipelines.contains(&stacking_context.pipeline_id)
{
let mut prev_task = alpha_task_stack.pop().unwrap();
let screen_origin = current_task.as_alpha_batch().screen_origin;
let current_task_id = render_tasks.add(current_task);
let item = AlphaRenderItem::HardwareComposite(
stacking_context_index,
current_task_id,
- HardwareCompositeOp::PremultipliedAlpha,
+ HardwareCompositeOp::PremultipliedAlpha(CompositionOp::Over),
screen_origin,
next_z,
);
next_z += 1;
prev_task.as_alpha_batch_mut().items.push(item);
prev_task.children.push(current_task_id);
current_task = prev_task;
}
--- a/gfx/webrender/src/internal_types.rs
+++ b/gfx/webrender/src/internal_types.rs
@@ -1,13 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use api::{ClipId, DevicePoint, DeviceUintRect, DocumentId, Epoch};
+use api::{CompositionOp, ClipId, DevicePoint, DeviceUintRect, DocumentId, Epoch};
use api::{ExternalImageData, ExternalImageId};
use api::{ImageFormat, PipelineId};
use api::DebugCommand;
use device::TextureFilter;
use fxhash::FxHasher;
use profiler::BackendProfileCounters;
use renderer::BlendMode;
use std::{usize, i32};
@@ -193,18 +193,18 @@ pub struct StackingContextIndex(pub usiz
#[derive(Clone, Copy, Debug)]
pub struct UvRect {
pub uv0: DevicePoint,
pub uv1: DevicePoint,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum HardwareCompositeOp {
- PremultipliedAlpha,
+ PremultipliedAlpha(CompositionOp),
}
impl HardwareCompositeOp {
pub fn to_blend_mode(&self) -> BlendMode {
match *self {
- HardwareCompositeOp::PremultipliedAlpha => BlendMode::PremultipliedAlpha,
+ HardwareCompositeOp::PremultipliedAlpha(op) => BlendMode::PremultipliedAlpha(op),
}
}
}
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -1,13 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use api::{BorderRadius, BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect};
+use api::{BorderRadius, BuiltDisplayList, CompositionOp, ColorF, ComplexClipRegion, DeviceIntRect};
use api::{DevicePoint, ExtendMode, FontInstance, FontRenderMode, GlyphInstance, GlyphKey};
use api::{GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerRect};
use api::{ClipMode, LayerSize, LayerVector2D, LineOrientation, LineStyle};
use api::{TileOffset, YuvColorSpace, YuvFormat};
use border::BorderCornerInstance;
use clip::{ClipSourcesHandle, ClipStore, Geometry};
use frame_builder::PrimitiveContext;
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
@@ -128,16 +128,17 @@ impl GpuCacheAddress {
self.v as i32 * MAX_VERTEX_TEXTURE_WIDTH as i32 + self.u as i32
}
}
// TODO(gw): Pack the fields here better!
#[derive(Debug)]
pub struct PrimitiveMetadata {
pub opacity: PrimitiveOpacity,
+ pub composition_op: CompositionOp,
pub clip_sources: ClipSourcesHandle,
pub prim_kind: PrimitiveKind,
pub cpu_prim_index: SpecificPrimitiveIndex,
pub gpu_location: GpuCacheHandle,
pub clip_task_id: Option<RenderTaskId>,
// TODO(gw): In the future, we should just pull these
// directly from the DL item, instead of
@@ -845,31 +846,33 @@ impl PrimitiveStore {
}
}
pub fn add_primitive(
&mut self,
local_rect: &LayerRect,
local_clip_rect: &LayerRect,
is_backface_visible: bool,
+ composition_op: CompositionOp,
clip_sources: ClipSourcesHandle,
tag: Option<ItemTag>,
container: PrimitiveContainer,
) -> PrimitiveIndex {
let prim_index = self.cpu_metadata.len();
let base_metadata = PrimitiveMetadata {
clip_sources,
gpu_location: GpuCacheHandle::new(),
clip_task_id: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
is_backface_visible: is_backface_visible,
screen_rect: None,
tag,
+ composition_op,
opacity: PrimitiveOpacity::translucent(),
prim_kind: PrimitiveKind::Rectangle,
cpu_prim_index: SpecificPrimitiveIndex(0),
};
let metadata = match container {
PrimitiveContainer::Rectangle(rect) => {
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -5,32 +5,32 @@
//! The webrender API.
//!
//! The `webrender::renderer` module provides the interface to webrender, which
//! is accessible through [`Renderer`][renderer]
//!
//! [renderer]: struct.Renderer.html
use api::{channel, BlobImageRenderer, FontRenderMode};
-use api::{ColorF, Epoch, PipelineId, RenderApiSender, RenderNotifier};
+use api::{ColorF, CompositionOp, Epoch, PipelineId, RenderApiSender, RenderNotifier};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
use api::{ExternalImageId, ExternalImageType, ImageFormat};
use api::{YUV_COLOR_SPACES, YUV_FORMATS};
use api::{YuvColorSpace, YuvFormat};
#[cfg(not(feature = "debugger"))]
use api::ApiMsg;
use api::DebugCommand;
#[cfg(not(feature = "debugger"))]
use api::channel::MsgSender;
use debug_colors;
use debug_render::DebugRenderer;
#[cfg(feature = "debugger")]
use debug_server::{self, DebugServer};
-use device::{DepthFunction, Device, FrameId, GpuMarker, GpuProfiler, Program, Texture,
- VertexDescriptor, PBO};
+use device::{DepthFunction, Device, FrameId, GpuMarker,
+ GpuProfiler, PBO, Program, Texture, VertexDescriptor};
use device::{get_gl_format_bgra, ExternalTexture, FBOId, TextureSlot, VertexAttribute,
VertexAttributeKind};
use device::{FileWatcherHandler, GpuTimer, ShaderError, TextureFilter, TextureTarget,
VertexUsageHint, VAO};
use euclid::{rect, Transform3D};
use frame_builder::FrameBuilderConfig;
use gleam::gl;
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
@@ -612,17 +612,17 @@ impl SourceTextureResolver {
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum BlendMode {
None,
Alpha,
- PremultipliedAlpha,
+ PremultipliedAlpha(CompositionOp),
Subpixel,
}
// Tracks the state of each row in the GPU cache texture.
struct CacheRow {
is_dirty: bool,
}
@@ -2362,17 +2362,17 @@ impl Renderer {
.bind(&mut self.device, projection, 0, &mut self.renderer_errors);
GPU_TAG_PRIM_BLEND
}
BatchKind::Transformable(transform_kind, batch_kind) => match batch_kind {
TransformBatchKind::Rectangle(needs_clipping) => {
debug_assert!(
!needs_clipping || match key.blend_mode {
BlendMode::Alpha |
- BlendMode::PremultipliedAlpha |
+ BlendMode::PremultipliedAlpha(_) |
BlendMode::Subpixel => true,
BlendMode::None => false,
}
);
if needs_clipping {
self.ps_rectangle_clip.bind(
&mut self.device,
@@ -2727,17 +2727,17 @@ impl Renderer {
self.device.disable_depth_write();
self.gpu_profile.add_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
for batch in &target.alpha_batcher.batch_list.alpha_batch_list.batches {
if self.debug_flags.contains(DebugFlags::ALPHA_PRIM_DBG) {
let color = match batch.key.blend_mode {
BlendMode::None => ColorF::new(0.3, 0.3, 0.3, 1.0),
BlendMode::Alpha => ColorF::new(0.0, 0.9, 0.1, 1.0),
- BlendMode::PremultipliedAlpha => ColorF::new(0.0, 0.3, 0.7, 1.0),
+ BlendMode::PremultipliedAlpha(_) => ColorF::new(0.0, 0.3, 0.7, 1.0),
BlendMode::Subpixel => ColorF::new(0.5, 0.0, 0.4, 1.0),
}.into();
for item_rect in &batch.item_rects {
self.debug.add_rect(item_rect, color);
}
}
match batch.key.kind {
@@ -2749,18 +2749,18 @@ impl Renderer {
// 1) Use dual source blending where available (almost all recent hardware).
// 2) Use frame buffer fetch where available (most modern hardware).
// 3) Consider the old constant color blend method where no clip is applied.
let _gm = self.gpu_profile.add_marker(GPU_TAG_PRIM_TEXT_RUN);
self.device.set_blend(true);
match batch.key.blend_mode {
- BlendMode::PremultipliedAlpha => {
- self.device.set_blend_mode_premultiplied_alpha();
+ BlendMode::PremultipliedAlpha(op) => {
+ self.device.set_blend_mode_premultiplied_alpha(op);
self.ps_text_run.bind(
&mut self.device,
transform_kind,
projection,
TextShaderMode::Alpha,
&mut self.renderer_errors,
);
@@ -2822,19 +2822,19 @@ impl Renderer {
match batch.key.blend_mode {
BlendMode::None => {
self.device.set_blend(false);
}
BlendMode::Alpha => {
self.device.set_blend(true);
self.device.set_blend_mode_alpha();
}
- BlendMode::PremultipliedAlpha => {
+ BlendMode::PremultipliedAlpha(op) => {
self.device.set_blend(true);
- self.device.set_blend_mode_premultiplied_alpha();
+ self.device.set_blend_mode_premultiplied_alpha(op);
}
BlendMode::Subpixel => {
unreachable!("bug: subpx text handled earlier");
}
}
prev_blend_mode = batch.key.blend_mode;
}
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -1,13 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use api::{ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint, ImageKey};
+use api::{ClipAndScrollInfo, ClipId, CompositionOp, ColorF, DeviceIntPoint, ImageKey};
use api::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize};
use api::{ExternalImageType, FilterOp, FontRenderMode, ImageRendering, LayerRect};
use api::{LayerToWorldTransform, MixBlendMode, PipelineId, PropertyBinding, TransformStyle};
use api::{LayerVector2D, TileOffset, WorldToLayerTransform, YuvColorSpace, YuvFormat};
use border::{BorderCornerInstance, BorderCornerSide};
use clip::{ClipSource, ClipStore};
use clip_scroll_tree::CoordinateSystemId;
use device::Texture;
@@ -44,35 +44,41 @@ trait AlphaBatchHelpers {
}
impl AlphaBatchHelpers for PrimitiveStore {
fn get_blend_mode(
&self,
metadata: &PrimitiveMetadata,
transform_kind: TransformedRectKind,
) -> BlendMode {
- let needs_blending = !metadata.opacity.is_opaque || metadata.clip_task_id.is_some() ||
+ let needs_blending = match metadata.composition_op {
+ CompositionOp::Source => false,
+ CompositionOp::Over => !metadata.opacity.is_opaque,
+ _ => true,
+ };
+ let needs_blending = needs_blending || metadata.clip_task_id.is_some() ||
transform_kind == TransformedRectKind::Complex;
match metadata.prim_kind {
PrimitiveKind::TextRun => {
let text_run_cpu = &self.cpu_text_runs[metadata.cpu_prim_index.0];
match text_run_cpu.font.render_mode {
FontRenderMode::Subpixel => BlendMode::Subpixel,
FontRenderMode::Alpha |
FontRenderMode::Mono |
- FontRenderMode::Bitmap => BlendMode::PremultipliedAlpha,
+ FontRenderMode::Bitmap => BlendMode::PremultipliedAlpha(CompositionOp::Over),
}
- }
+ },
+ PrimitiveKind::Rectangle |
PrimitiveKind::Image |
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient |
PrimitiveKind::RadialGradient |
PrimitiveKind::Picture => if needs_blending {
- BlendMode::PremultipliedAlpha
+ BlendMode::PremultipliedAlpha(metadata.composition_op)
} else {
BlendMode::None
},
_ => if needs_blending {
BlendMode::Alpha
} else {
BlendMode::None
},
@@ -248,17 +254,17 @@ impl BatchList {
fn get_suitable_batch(
&mut self,
key: BatchKey,
item_bounding_rect: &DeviceIntRect,
) -> &mut Vec<PrimitiveInstance> {
match key.blend_mode {
BlendMode::None => self.opaque_batch_list.get_suitable_batch(key),
- BlendMode::Alpha | BlendMode::PremultipliedAlpha | BlendMode::Subpixel => {
+ BlendMode::Alpha | BlendMode::PremultipliedAlpha(_) | BlendMode::Subpixel => {
self.alpha_batch_list
.get_suitable_batch(key, item_bounding_rect)
}
}
}
fn finalize(&mut self) {
self.opaque_batch_list.finalize()
@@ -284,17 +290,17 @@ impl AlphaRenderItem {
deferred_resolves: &mut Vec<DeferredResolve>,
glyph_fetch_buffer: &mut Vec<GlyphFetchResult>,
) {
match *self {
AlphaRenderItem::Blend(stacking_context_index, src_id, filter, z) => {
let stacking_context = &ctx.stacking_context_store[stacking_context_index.0];
let key = BatchKey::new(
BatchKind::Blend,
- BlendMode::PremultipliedAlpha,
+ BlendMode::PremultipliedAlpha(CompositionOp::Over),
BatchTextures::no_texture(),
);
let src_task_address = render_tasks.get_task_address(src_id);
let (filter_mode, amount) = match filter {
FilterOp::Blur(..) => (0, 0.0),
FilterOp::Contrast(amount) => (1, amount),
FilterOp::Grayscale(amount) => (2, amount),
@@ -700,17 +706,17 @@ impl AlphaRenderItem {
uv_rect_addresses[2],
));
}
}
}
AlphaRenderItem::SplitComposite(sc_index, task_id, gpu_handle, z) => {
let key = BatchKey::new(
BatchKind::SplitComposite,
- BlendMode::PremultipliedAlpha,
+ BlendMode::PremultipliedAlpha(CompositionOp::Over),
BatchTextures::no_texture(),
);
let stacking_context = &ctx.stacking_context_store[sc_index.0];
let batch = batch_list.get_suitable_batch(key, &stacking_context.screen_bounds);
let source_task_address = render_tasks.get_task_address(task_id);
let gpu_address = gpu_handle.as_int(gpu_cache);
let instance = CompositePrimitiveInstance::new(
--- a/gfx/webrender_api/src/api.rs
+++ b/gfx/webrender_api/src/api.rs
@@ -10,16 +10,32 @@ use {NativeFontHandle, WorldPoint};
use app_units::Au;
use channel::{self, MsgSender, Payload, PayloadSender, PayloadSenderHelperMethods};
use std::cell::Cell;
use std::fmt;
use std::marker::PhantomData;
pub type TileSize = u16;
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
+pub enum CompositionOp {
+ Over = 0,
+ Add = 1,
+ Atop = 2,
+ Out = 3,
+ In = 4,
+ Source = 5,
+ DestIn = 6,
+ DestOut = 7,
+ DestOver = 8,
+ DestAtop = 9,
+ Xor = 10,
+}
+
/// The resource updates for a given transaction (they must be applied in the same frame).
#[derive(Clone, Deserialize, Serialize)]
pub struct ResourceUpdates {
pub updates: Vec<ResourceUpdate>,
}
#[derive(Clone, Deserialize, Serialize)]
pub enum ResourceUpdate {
--- a/gfx/webrender_api/src/display_item.rs
+++ b/gfx/webrender_api/src/display_item.rs
@@ -1,14 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use {ColorF, FontInstanceKey, ImageKey, LayerPixel, LayoutPixel, LayoutPoint, LayoutRect,
- LayoutSize, LayoutTransform};
+use {CompositionOp, ColorF, FontInstanceKey, ImageKey, LayerPixel, LayoutPixel,
+ LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
use {GlyphOptions, LayoutVector2D, PipelineId, PropertyBinding};
use euclid::{SideOffsets2D, TypedRect, TypedSideOffsets2D};
use std::ops::Not;
// NOTE: some of these structs have an "IMPLICIT" comment.
// This indicates that the BuiltDisplayList will have serialized
// a list of values nearby that this item consumes. The traversal
// iterator should handle finding these.
@@ -53,16 +53,17 @@ pub struct DisplayItem {
pub info: LayoutPrimitiveInfo,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct PrimitiveInfo<T> {
pub rect: TypedRect<f32, T>,
pub local_clip: LocalClip,
pub is_backface_visible: bool,
+ pub composition_op: CompositionOp,
pub tag: Option<ItemTag>,
}
impl LayerPrimitiveInfo {
pub fn new(rect: TypedRect<f32, LayerPixel>) -> Self {
Self::with_clip_rect(rect, rect)
}
@@ -72,16 +73,17 @@ impl LayerPrimitiveInfo {
Self::with_clip(rect, LocalClip::from(clip_rect))
}
pub fn with_clip(rect: TypedRect<f32, LayerPixel>, clip: LocalClip) -> Self {
PrimitiveInfo {
rect: rect,
local_clip: clip,
is_backface_visible: true,
+ composition_op: CompositionOp::Over,
tag: None,
}
}
}
pub type LayoutPrimitiveInfo = PrimitiveInfo<LayoutPixel>;
pub type LayerPrimitiveInfo = PrimitiveInfo<LayerPixel>;
--- a/gfx/webrender_api/src/display_list.rs
+++ b/gfx/webrender_api/src/display_list.rs
@@ -1,15 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use {BorderDetails, BorderDisplayItem, BorderWidths, BoxShadowClipMode, BoxShadowDisplayItem};
-use {ClipAndScrollInfo, ClipDisplayItem, ClipId, ColorF, ComplexClipRegion, DisplayItem};
-use {ExtendMode, FilterOp, FontInstanceKey, GlyphInstance};
+use {ClipAndScrollInfo, ClipDisplayItem, ClipId, CompositionOp, ColorF, ComplexClipRegion};
+use {DisplayItem, ExtendMode, FilterOp, FontInstanceKey, GlyphInstance};
use {GlyphOptions, Gradient, GradientDisplayItem, GradientStop, IframeDisplayItem};
use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayerPrimitiveInfo, LayoutPoint};
use {LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
use {LineDisplayItem, LineOrientation, LineStyle, LocalClip, MixBlendMode, PipelineId};
use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity};
use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyFrameInfo};
use {BorderRadius, TextDisplayItem, Shadow, TransformStyle, YuvColorSpace, YuvData};
@@ -309,16 +309,17 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
}
pub fn get_layer_primitive_info(&self, offset: &LayoutVector2D) -> LayerPrimitiveInfo {
let info = self.iter.cur_item.info;
LayerPrimitiveInfo {
rect: info.rect.translate(&offset),
local_clip: info.local_clip.create_with_offset(offset),
is_backface_visible: info.is_backface_visible,
+ composition_op: info.composition_op,
tag: info.tag,
}
}
pub fn local_clip(&self) -> &LocalClip {
&self.iter.cur_item.info.local_clip
}
@@ -1159,16 +1160,17 @@ impl DisplayListBuilder {
image_mask: image_mask,
scroll_sensitivity,
});
let info = LayoutPrimitiveInfo {
rect: content_rect,
local_clip: LocalClip::from(clip_rect),
is_backface_visible: true,
+ composition_op: CompositionOp::Over,
tag: None,
};
let scrollinfo = ClipAndScrollInfo::simple(parent);
self.push_item_with_clip_scroll_info(item, &info, scrollinfo);
self.push_iter(complex_clips);
id
}
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -820,23 +820,24 @@ DisplayListBuilder::PopClipAndScrollInfo
mScrollIdStack.pop_back();
wr_dp_pop_clip_and_scroll_info(mWrState);
}
void
DisplayListBuilder::PushRect(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
+ wr::CompositionOp aCompositionOp,
const wr::ColorF& aColor)
{
WRDL_LOG("PushRect b=%s cl=%s c=%s\n", mWrState,
Stringify(aBounds).c_str(),
Stringify(aClip).c_str(),
Stringify(aColor).c_str());
- wr_dp_push_rect(mWrState, aBounds, aClip, aIsBackfaceVisible, aColor);
+ wr_dp_push_rect(mWrState, aBounds, aClip, aIsBackfaceVisible, aCompositionOp, aColor);
}
void
DisplayListBuilder::PushLinearGradient(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
const wr::LayoutPoint& aStartPoint,
const wr::LayoutPoint& aEndPoint,
@@ -871,39 +872,42 @@ DisplayListBuilder::PushRadialGradient(c
aExtendMode,
aTileSize, aTileSpacing);
}
void
DisplayListBuilder::PushImage(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
+ wr::CompositionOp aCompositionOp,
wr::ImageRendering aFilter,
wr::ImageKey aImage)
{
wr::LayoutSize size;
size.width = aBounds.size.width;
size.height = aBounds.size.height;
- PushImage(aBounds, aClip, aIsBackfaceVisible, size, size, aFilter, aImage);
+ PushImage(aBounds, aClip, aIsBackfaceVisible, aCompositionOp, size, size, aFilter, aImage);
}
void
DisplayListBuilder::PushImage(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
+ wr::CompositionOp aCompositionOp,
const wr::LayoutSize& aStretchSize,
const wr::LayoutSize& aTileSpacing,
wr::ImageRendering aFilter,
wr::ImageKey aImage)
{
WRDL_LOG("PushImage b=%s cl=%s s=%s t=%s\n", mWrState,
Stringify(aBounds).c_str(),
Stringify(aClip).c_str(), Stringify(aStretchSize).c_str(),
Stringify(aTileSpacing).c_str());
- wr_dp_push_image(mWrState, aBounds, aClip, aIsBackfaceVisible, aStretchSize, aTileSpacing, aFilter, aImage);
+ wr_dp_push_image(mWrState, aBounds, aClip, aIsBackfaceVisible, aCompositionOp,
+ aStretchSize, aTileSpacing, aFilter, aImage);
}
void
DisplayListBuilder::PushYCbCrPlanarImage(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
wr::ImageKey aImageChannel0,
wr::ImageKey aImageChannel1,
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -249,16 +249,17 @@ public:
void PushClipAndScrollInfo(const layers::FrameMetrics::ViewID& aScrollId,
const wr::WrClipId* aClipId);
void PopClipAndScrollInfo();
void PushRect(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
+ wr::CompositionOp aCompositionOp,
const wr::ColorF& aColor);
void PushLinearGradient(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
const wr::LayoutPoint& aStartPoint,
const wr::LayoutPoint& aEndPoint,
const nsTArray<wr::GradientStop>& aStops,
@@ -274,22 +275,24 @@ public:
const nsTArray<wr::GradientStop>& aStops,
wr::ExtendMode aExtendMode,
const wr::LayoutSize aTileSize,
const wr::LayoutSize aTileSpacing);
void PushImage(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
+ wr::CompositionOp aCompositionOp,
wr::ImageRendering aFilter,
wr::ImageKey aImage);
void PushImage(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
+ wr::CompositionOp aCompositionOp,
const wr::LayoutSize& aStretchSize,
const wr::LayoutSize& aTileSpacing,
wr::ImageRendering aFilter,
wr::ImageKey aImage);
void PushYCbCrPlanarImage(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1317,38 +1317,42 @@ pub extern "C" fn wr_dp_push_iframe(stat
state.frame_builder.dl_builder.push_iframe(&prim_info, pipeline_id);
}
#[no_mangle]
pub extern "C" fn wr_dp_push_rect(state: &mut WrState,
rect: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
+ composition_op: CompositionOp,
color: ColorF) {
debug_assert!(unsafe { !is_in_render_thread() });
let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
prim_info.is_backface_visible = is_backface_visible;
+ prim_info.composition_op = composition_op;
state.frame_builder.dl_builder.push_rect(&prim_info,
color);
}
#[no_mangle]
pub extern "C" fn wr_dp_push_image(state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
+ composition_op: CompositionOp,
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
image_rendering: ImageRendering,
key: WrImageKey) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
prim_info.is_backface_visible = is_backface_visible;
+ prim_info.composition_op = composition_op;
state.frame_builder
.dl_builder
.push_image(&prim_info,
stretch_size,
tile_spacing,
image_rendering,
key);
}
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -1,13 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-/* Generated with cbindgen:0.1.26 */
+/* Generated with cbindgen:0.1.25 */
/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
* 1. Get the latest cbindgen using `cargo install --force cbindgen`
* a. Alternatively, you can clone `https://github.com/rlhunt/cbindgen` and use a tagged release
* 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --crate webrender_bindings -o gfx/webrender_bindings/webrender_ffi_generated.h`
*/
@@ -43,16 +43,32 @@ enum class BoxShadowClipMode : uint32_t
enum class ClipMode {
Clip = 0,
ClipOut = 1,
Sentinel /* this must be last for serialization purposes. */
};
+enum class CompositionOp : uint32_t {
+ Over = 0,
+ Add = 1,
+ Atop = 2,
+ Out = 3,
+ In = 4,
+ Source = 5,
+ DestIn = 6,
+ DestOut = 7,
+ DestOver = 8,
+ DestAtop = 9,
+ Xor = 10,
+
+ Sentinel /* this must be last for serialization purposes. */
+};
+
enum class ExtendMode : uint32_t {
Clamp = 0,
Repeat = 1,
Sentinel /* this must be last for serialization purposes. */
};
enum class ExternalImageType : uint32_t {
@@ -274,17 +290,17 @@ struct TypedSize2D_f32__LayerPixel {
}
};
typedef TypedSize2D_f32__LayerPixel LayerSize;
typedef LayerSize LayoutSize;
// Describes the memory layout of a display list.
-//
+//
// A display list consists of some number of display list items, followed by a number of display
// items.
struct BuiltDisplayListDescriptor {
// The first IPC time stamp: before any work has been done
uint64_t builder_start_time;
// The second IPC time stamp: after serialization
uint64_t builder_finish_time;
// The third IPC time stamp: just before sending
@@ -314,27 +330,16 @@ struct WrOpacityProperty {
float opacity;
bool operator==(const WrOpacityProperty& aOther) const {
return id == aOther.id &&
opacity == aOther.opacity;
}
};
-// A 3d transform stored as a 4 by 4 matrix in row-major order in memory.
-//
-// Transforms can be parametrized over the source and destination units, to describe a
-// transformation from a space to another.
-// For example, `TypedTransform3D<f32, WordSpace, ScreenSpace>::transform_point3d`
-// takes a `TypedPoint3D<f32, WordSpace>` and returns a `TypedPoint3D<f32, ScreenSpace>`.
-//
-// Transforms expose a set of convenience methods for pre- and post-transformations.
-// A pre-transformation corresponds to adding an operation that is applied before
-// the rest of the transformation, while a post-transformation adds an operation
-// that is applied after.
struct TypedTransform3D_f32__LayoutPixel__LayoutPixel {
float m11;
float m12;
float m13;
float m14;
float m21;
float m22;
float m23;
@@ -390,34 +395,33 @@ struct IdNamespace {
bool operator<=(const IdNamespace& aOther) const {
return mHandle <= aOther.mHandle;
}
};
typedef IdNamespace WrIdNamespace;
// Represents RGBA screen colors with floating point numbers.
-//
+//
// All components must be between 0.0 and 1.0.
// An alpha value of 1.0 is opaque while 0.0 is fully transparent.
struct ColorF {
float r;
float g;
float b;
float a;
bool operator==(const ColorF& aOther) const {
return r == aOther.r &&
g == aOther.g &&
b == aOther.b &&
a == aOther.a;
}
};
-// A 2d Point tagged with a unit.
struct TypedPoint2D_f32__LayerPixel {
float x;
float y;
bool operator==(const TypedPoint2D_f32__LayerPixel& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
@@ -577,17 +581,16 @@ struct NinePatchDescriptor {
bool operator==(const NinePatchDescriptor& aOther) const {
return width == aOther.width &&
height == aOther.height &&
slice == aOther.slice;
}
};
-// A 2d Vector tagged with a unit.
struct TypedVector2D_f32__LayerPixel {
float x;
float y;
bool operator==(const TypedVector2D_f32__LayerPixel& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
@@ -658,17 +661,16 @@ struct ByteSlice {
size_t len;
bool operator==(const ByteSlice& aOther) const {
return buffer == aOther.buffer &&
len == aOther.len;
}
};
-// A 2d Point tagged with a unit.
struct TypedPoint2D_u16__Tiles {
uint16_t x;
uint16_t y;
bool operator==(const TypedPoint2D_u16__Tiles& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
@@ -1068,16 +1070,17 @@ void wr_dp_push_iframe(WrState *aState,
WrPipelineId aPipelineId)
WR_FUNC;
WR_INLINE
void wr_dp_push_image(WrState *aState,
LayoutRect aBounds,
LayoutRect aClip,
bool aIsBackfaceVisible,
+ CompositionOp aCompositionOp,
LayoutSize aStretchSize,
LayoutSize aTileSpacing,
ImageRendering aImageRendering,
WrImageKey aKey)
WR_FUNC;
WR_INLINE
void wr_dp_push_line(WrState *aState,
@@ -1120,16 +1123,17 @@ void wr_dp_push_radial_gradient(WrState
LayoutSize aTileSpacing)
WR_FUNC;
WR_INLINE
void wr_dp_push_rect(WrState *aState,
LayoutRect aRect,
LayoutRect aClip,
bool aIsBackfaceVisible,
+ CompositionOp aCompositionOp,
ColorF aColor)
WR_FUNC;
WR_INLINE
void wr_dp_push_scroll_layer(WrState *aState,
uint64_t aScrollId)
WR_FUNC;
--- a/layout/generic/TextDrawTarget.h
+++ b/layout/generic/TextDrawTarget.h
@@ -153,17 +153,18 @@ public:
}
}
void
AppendSelectionRect(const LayoutDeviceRect& aRect, const Color& aColor)
{
auto rect = wr::ToLayoutRect(aRect);
auto color = wr::ToColorF(aColor);
- mBuilder.PushRect(rect, mClipRect, mBackfaceVisible, color);
+ mBuilder.PushRect(rect, mClipRect, mBackfaceVisible,
+ wr::CompositionOp::Over, color);
}
void
AppendDecoration(const Point& aStart,
const Point& aEnd,
const float aThickness,
const bool aVertical,
const Color& aColor,
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -483,16 +483,17 @@ BulletRenderer::CreateWebRenderCommandsF
const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(mDest, appUnitsPerDevPixel);
wr::LayoutRect dest = aSc.ToRelativeLayoutRect(destRect);
aBuilder.PushImage(dest,
dest,
!aItem->BackfaceIsHidden(),
+ wr::CompositionOp::Over,
wr::ImageRendering::Auto,
key.value());
return true;
}
bool
BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -324,17 +324,17 @@ nsDisplayCanvasBackgroundColor::CreateWe
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(
bgClipRect, appUnitsPerDevPixel);
wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(rect);
aBuilder.PushRect(transformedRect,
transformedRect,
- !BackfaceIsHidden(),
+ !BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToColorF(ToDeviceColor(mColor)));
return true;
}
#ifdef MOZ_DUMP_PAINTING
void
nsDisplayCanvasBackgroundColor::WriteDebugInfo(std::stringstream& aStream)
{
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2947,17 +2947,17 @@ nsDisplaySolidColor::CreateWebRenderComm
nsDisplayListBuilder* aDisplayListBuilder)
{
LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
mVisibleRect, mFrame->PresContext()->AppUnitsPerDevPixel());
wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(bounds);
aBuilder.PushRect(transformedRect,
transformedRect,
- !BackfaceIsHidden(),
+ !BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToColorF(ToDeviceColor(mColor)));
return true;
}
nsRect
nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
@@ -2999,17 +2999,17 @@ nsDisplaySolidColorRegion::CreateWebRend
{
for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
nsRect rect = iter.Get();
LayoutDeviceRect layerRects = LayoutDeviceRect::FromAppUnits(
rect, mFrame->PresContext()->AppUnitsPerDevPixel());
wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(layerRects);
aBuilder.PushRect(transformedRect,
transformedRect,
- !BackfaceIsHidden(),
+ !BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToColorF(ToDeviceColor(mColor)));
}
return true;
}
static void
RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
@@ -4278,17 +4278,17 @@ nsDisplayBackgroundColor::CreateWebRende
}
LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel());
wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(bounds);
aBuilder.PushRect(transformedRect,
transformedRect,
- !BackfaceIsHidden(),
+ !BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToColorF(ToDeviceColor(mColor)));
return true;
}
void
nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx)
@@ -4410,16 +4410,36 @@ nsDisplayClearBackground::BuildLayer(nsD
bool snap;
nsRect bounds = GetBounds(aBuilder, &snap);
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
layer->SetBounds(bounds.ToNearestPixels(appUnitsPerDevPixel)); // XXX Do we need to respect the parent layer's scale here?
return layer.forget();
}
+bool
+nsDisplayClearBackground::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::WebRenderLayerManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder)
+{
+ LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
+ nsRect(ToReferenceFrame(), mFrame->GetSize()),
+ mFrame->PresContext()->AppUnitsPerDevPixel());
+ wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(bounds);
+
+ aBuilder.PushRect(transformedRect,
+ transformedRect,
+ true, wr::CompositionOp::Source,
+ wr::ColorF{ 0.0f, 0.0f, 0.0f, 0.0f });
+
+ return true;
+}
+
nsRect
nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const
{
*aSnap = false;
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
}
@@ -4789,23 +4809,23 @@ nsDisplayCaret::CreateWebRenderCommands(
hookRect + ToReferenceFrame(), appUnitsPerDevPixel);
wr::LayoutRect caret = aSc.ToRelativeLayoutRect(devCaretRect);
wr::LayoutRect hook = aSc.ToRelativeLayoutRect(devHookRect);
// Note, WR will pixel snap anything that is layout aligned.
aBuilder.PushRect(caret,
caret,
- !BackfaceIsHidden(),
+ !BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToColorF(color));
if (!devHookRect.IsEmpty()) {
aBuilder.PushRect(hook,
hook,
- !BackfaceIsHidden(),
+ !BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToColorF(color));
}
return true;
}
LayerState
nsDisplayCaret::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3680,16 +3680,22 @@ public:
{
return mozilla::LAYER_ACTIVE_FORCE;
}
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) override;
+ bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::WebRenderLayerManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
NS_DISPLAY_DECL_NAME("ClearBackground", TYPE_CLEAR_BACKGROUND)
};
/**
* The standard display item to paint the outer CSS box-shadows of a frame.
*/
class nsDisplayBoxShadowOuter final : public nsDisplayItem {
public:
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -659,17 +659,17 @@ nsImageRenderer::BuildWebRenderDisplayIt
wr::LayoutRect fill = aSc.ToRelativeLayoutRect(fillRect);
wr::LayoutRect clip = aSc.ToRelativeLayoutRect(
LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel));
LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits(
aRepeatSize - aDest.Size(), appUnitsPerDevPixel);
SamplingFilter samplingFilter = nsLayoutUtils::GetSamplingFilterForFrame(mForFrame);
- aBuilder.PushImage(fill, clip, !aItem->BackfaceIsHidden(),
+ aBuilder.PushImage(fill, clip, !aItem->BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToLayoutSize(destRect.Size()), wr::ToLayoutSize(gapSize),
wr::ToImageRendering(samplingFilter), key.value());
break;
}
default:
break;
}
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -456,17 +456,17 @@ nsImageBoxFrame::CreateWebRenderCommands
}
const int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(dest,
appUnitsPerDevPixel);
wr::LayoutRect fill = aSc.ToRelativeLayoutRect(fillRect);
LayoutDeviceSize gapSize(0, 0);
SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
- aBuilder.PushImage(fill, fill, !BackfaceIsHidden(),
+ aBuilder.PushImage(fill, fill, !BackfaceIsHidden(), wr::CompositionOp::Over,
wr::ToLayoutSize(fillRect.Size()), wr::ToLayoutSize(gapSize),
wr::ToImageRendering(sampleFilter), key.value());
return DrawResult::SUCCESS;
}
nsRect
nsImageBoxFrame::GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint)
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -632,18 +632,19 @@ protected:
// Compositor thread only
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mResizerImage;
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mCornerMaskImage;
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mTitlebarImage;
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mBasicCompositorImage;
// Main thread + webrender only
+ mozilla::Maybe<mozilla::wr::ImageKey> mCornerMaskImageKey;
+ LayoutDeviceIntSize mCornerMaskImageSize;
mozilla::Maybe<mozilla::wr::ImageKey> mTitlebarImageKey;
- mozilla::gfx::IntSize mTitlebarImageSize;
// The area of mTitlebarCGContext that has changed and needs to be
// uploaded to to mTitlebarImage. Main thread only.
nsIntRegion mDirtyTitlebarRegion;
mozilla::ViewRegion mNonDraggableRegion;
// Cached value of [mView backingScaleFactor], to avoid sending two obj-c
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2073,16 +2073,44 @@ nsChildView::PrepareWindowEffects()
void
nsChildView::CleanupWindowEffects()
{
mResizerImage = nullptr;
mCornerMaskImage = nullptr;
mTitlebarImage = nullptr;
}
+static CGContextRef
+CreateCGContext(const LayoutDeviceIntSize& aSize)
+{
+ CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
+ CGContextRef ctx =
+ CGBitmapContextCreate(NULL,
+ aSize.width,
+ aSize.height,
+ 8 /* bitsPerComponent */,
+ aSize.width * 4,
+ cs,
+ kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
+ CGColorSpaceRelease(cs);
+
+ CGContextTranslateCTM(ctx, 0, aSize.height);
+ CGContextScaleCTM(ctx, 1, -1);
+ CGContextSetInterpolationQuality(ctx, kCGInterpolationLow);
+
+ return ctx;
+}
+
+static void
+DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
+{
+ CGContextSetRGBFillColor(aCtx, 1.0, 1.0, 1.0, 1.0);
+ CGContextFillEllipseInRect(aCtx, CGRectMake(0, 0, aRadius * 2, aRadius * 2));
+}
+
void
nsChildView::AddWindowOverlayWebRenderCommands(layers::WebRenderBridgeChild* aWrBridge,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources)
{
PrepareWindowEffects();
bool needUpdate = mUpdatedTitlebarRegion.Intersects(mTitlebarRect);
@@ -2094,51 +2122,96 @@ nsChildView::AddWindowOverlayWebRenderCo
size_t stride = CGBitmapContextGetBytesPerRow(mTitlebarCGContext);
size_t titlebarCGContextDataLength = stride * size.height;
gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
Range<uint8_t> buffer(
static_cast<uint8_t *>(CGBitmapContextGetData(mTitlebarCGContext)),
titlebarCGContextDataLength
);
- if (mTitlebarImageKey &&
- mTitlebarImageSize != size) {
- // Delete wr::ImageKey. wr::ImageKey does not support size change.
- // TODO: that's not true anymore! (size change is now supported).
- CleanupWebRenderWindowOverlay(aWrBridge, aResources);
- MOZ_ASSERT(mTitlebarImageKey.isNothing());
- }
-
if (!mTitlebarImageKey) {
mTitlebarImageKey = Some(aWrBridge->GetNextImageKey());
wr::ImageDescriptor descriptor(size, stride, format);
aResources.AddImage(*mTitlebarImageKey, descriptor, buffer);
- mTitlebarImageSize = size;
needUpdate = false;
}
if (needUpdate) {
wr::ImageDescriptor descriptor(size, stride, format);
aResources.UpdateImageBuffer(*mTitlebarImageKey, descriptor, buffer);
}
wr::LayoutRect rect = wr::ToLayoutRect(mTitlebarRect);
aBuilder.PushImage(wr::LayoutRect{ rect.origin, { float(size.width), float(size.height) } },
- rect, true, wr::ImageRendering::Auto, *mTitlebarImageKey);
+ rect, true, wr::CompositionOp::Over, wr::ImageRendering::Auto, *mTitlebarImageKey);
+ }
+
+ LayoutDeviceIntSize cornerMaskSize(mDevPixelCornerRadius * 2, mDevPixelCornerRadius * 2);
+ size_t stride = 0;
+ CGContextRef cornerMaskContext = nullptr;
+ Maybe<Range<uint8_t>> buffer;
+ needUpdate = !mCornerMaskImageKey || (cornerMaskSize != mCornerMaskImageSize);
+ if (needUpdate) {
+ cornerMaskContext = CreateCGContext(cornerMaskSize);
+ DrawTopLeftCornerMask(cornerMaskContext, mDevPixelCornerRadius);
+ stride = CGBitmapContextGetBytesPerRow(cornerMaskContext);
+ size_t dataLength = stride * cornerMaskSize.height;
+ buffer.emplace(
+ static_cast<uint8_t *>(CGBitmapContextGetData(cornerMaskContext)),
+ dataLength
+ );
+ }
+ wr::ImageDescriptor descriptor(cornerMaskSize.ToUnknownSize(), stride, gfx::SurfaceFormat::B8G8R8A8);
+ if (!mCornerMaskImageKey) {
+ mCornerMaskImageKey = Some(aWrBridge->GetNextImageKey());
+ aResources.AddImage(*mCornerMaskImageKey, descriptor, *buffer);
+ needUpdate = false;
+ mCornerMaskImageSize = cornerMaskSize;
+ }
+ if (needUpdate) {
+ aResources.UpdateImageBuffer(*mCornerMaskImageKey, descriptor, *buffer);
+ }
+
+ if (mIsCoveringTitlebar && !mIsFullscreen) {
+ // Mask the top corners.
+ aBuilder.PushImage(wr::ToLayoutRect(LayoutDeviceIntRect(0, 0, cornerMaskSize.width, cornerMaskSize.height)),
+ wr::ToLayoutRect(LayoutDeviceIntRect(0, 0, mDevPixelCornerRadius, mDevPixelCornerRadius)),
+ true, wr::CompositionOp::DestIn,
+ wr::ImageRendering::Auto, *mCornerMaskImageKey);
+ aBuilder.PushImage(wr::ToLayoutRect(LayoutDeviceIntRect(mBounds.width - cornerMaskSize.width, 0, cornerMaskSize.width, cornerMaskSize.height)),
+ wr::ToLayoutRect(LayoutDeviceIntRect(mBounds.width - mDevPixelCornerRadius, 0, mDevPixelCornerRadius, mDevPixelCornerRadius)),
+ true, wr::CompositionOp::DestIn,
+ wr::ImageRendering::Auto, *mCornerMaskImageKey);
+ }
+
+ if (mHasRoundedBottomCorners && !mIsFullscreen) {
+ // Mask the bottom corners.
+ aBuilder.PushImage(wr::ToLayoutRect(LayoutDeviceIntRect(0, mBounds.height - cornerMaskSize.height, cornerMaskSize.width, cornerMaskSize.height)),
+ wr::ToLayoutRect(LayoutDeviceIntRect(0, mBounds.height - mDevPixelCornerRadius, mDevPixelCornerRadius, mDevPixelCornerRadius)),
+ true, wr::CompositionOp::DestIn,
+ wr::ImageRendering::Auto, *mCornerMaskImageKey);
+ aBuilder.PushImage(wr::ToLayoutRect(LayoutDeviceIntRect(mBounds.width - cornerMaskSize.width, mBounds.height - cornerMaskSize.height, cornerMaskSize.width, cornerMaskSize.height)),
+ wr::ToLayoutRect(LayoutDeviceIntRect(mBounds.width - mDevPixelCornerRadius, mBounds.height - mDevPixelCornerRadius, mDevPixelCornerRadius, mDevPixelCornerRadius)),
+ true, wr::CompositionOp::DestIn,
+ wr::ImageRendering::Auto, *mCornerMaskImageKey);
}
}
void
nsChildView::CleanupWebRenderWindowOverlay(layers::WebRenderBridgeChild* aWrBridge,
wr::IpcResourceUpdateQueue& aResources)
{
if (mTitlebarImageKey) {
aResources.DeleteImage(*mTitlebarImageKey);
mTitlebarImageKey = Nothing();
}
+ if (mCornerMaskImageKey) {
+ aResources.DeleteImage(*mCornerMaskImageKey);
+ mCornerMaskImageKey = Nothing();
+ }
}
bool
nsChildView::PreRender(WidgetRenderingContext* aContext)
{
UniquePtr<GLManager> manager(GLManager::CreateGLManager(aContext->mLayerManager));
gl::GLContext* gl = manager ? manager->gl() : aContext->mGL;
if (!gl) {
@@ -2252,37 +2325,16 @@ nsChildView::MaybeDrawResizeIndicator(GL
gfx::BorrowedCGContext borrow(drawTarget);
DrawResizer(borrow.cg);
borrow.Finish();
});
mResizerImage->Draw(aManager, mResizeIndicatorRect.TopLeft());
}
-static CGContextRef
-CreateCGContext(const LayoutDeviceIntSize& aSize)
-{
- CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
- CGContextRef ctx =
- CGBitmapContextCreate(NULL,
- aSize.width,
- aSize.height,
- 8 /* bitsPerComponent */,
- aSize.width * 4,
- cs,
- kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
- CGColorSpaceRelease(cs);
-
- CGContextTranslateCTM(ctx, 0, aSize.height);
- CGContextScaleCTM(ctx, 1, -1);
- CGContextSetInterpolationQuality(ctx, kCGInterpolationLow);
-
- return ctx;
-}
-
LayoutDeviceIntSize
TextureSizeForSize(const LayoutDeviceIntSize& aSize)
{
return LayoutDeviceIntSize(RoundUpPow2(aSize.width),
RoundUpPow2(aSize.height));
}
// When this method is entered, mEffectsLock is already being held.
@@ -2436,23 +2488,16 @@ nsChildView::MaybeDrawTitlebar(GLManager
mTitlebarImage->UpdateFromCGContext(mTitlebarRect.Size(),
updatedTitlebarRegion,
mTitlebarCGContext);
mTitlebarImage->Draw(aManager, mTitlebarRect.TopLeft());
}
-static void
-DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
-{
- CGContextSetRGBFillColor(aCtx, 1.0, 1.0, 1.0, 1.0);
- CGContextFillEllipseInRect(aCtx, CGRectMake(0, 0, aRadius * 2, aRadius * 2));
-}
-
void
nsChildView::MaybeDrawRoundedCorners(GLManager* aManager,
const LayoutDeviceIntRect& aRect)
{
MutexAutoLock lock(mEffectsLock);
if (!mCornerMaskImage) {
mCornerMaskImage = MakeUnique<RectTextureImage>();