Bug 1365972 - Add initial WebRender support for nsDisplayFilter. r=rhunt, r=mattwoodrow

This commit is contained in:
Martin Robinson 2017-06-06 06:28:00 -04:00
Родитель 1d80223f3d
Коммит 7d937678f4
16 изменённых файлов: 227 добавлений и 16 удалений

Просмотреть файл

@ -2250,6 +2250,12 @@ public:
return mEventRegionsOverride; return mEventRegionsOverride;
} }
void SetFilterChain(nsTArray<CSSFilter>&& aFilterChain) {
mFilterChain = aFilterChain;
}
nsTArray<CSSFilter>& GetFilterChain() { return mFilterChain; }
protected: protected:
friend class ReadbackProcessor; friend class ReadbackProcessor;
@ -2336,6 +2342,7 @@ protected:
// the intermediate surface. // the intermediate surface.
bool mChildrenChanged; bool mChildrenChanged;
EventRegionsOverride mEventRegionsOverride; EventRegionsOverride mEventRegionsOverride;
nsTArray<CSSFilter> mFilterChain;
}; };
/** /**

Просмотреть файл

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
#include "LayersTypes.h"
#include "nsStyleStruct.h" // for nsStyleFilter
namespace mozilla {
namespace layers {
CSSFilter ToCSSFilter(const nsStyleFilter& filter)
{
switch (filter.GetType()) {
case NS_STYLE_FILTER_BRIGHTNESS: {
return {
CSSFilterType::BRIGHTNESS,
filter.GetFilterParameter().GetFactorOrPercentValue(),
};
}
case NS_STYLE_FILTER_CONTRAST: {
return {
CSSFilterType::CONTRAST,
filter.GetFilterParameter().GetFactorOrPercentValue(),
};
}
// All other filter types should be prevented by the code which converts
// display items into layers.
default:
MOZ_ASSERT_UNREACHABLE("Tried to convert an unsupported filter");
return { CSSFilterType::CONTRAST, 0 };
}
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -35,6 +35,8 @@ namespace android {
class MOZ_EXPORT GraphicBuffer; class MOZ_EXPORT GraphicBuffer;
} // namespace android } // namespace android
struct nsStyleFilter;
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
@ -309,6 +311,25 @@ enum class ScrollDirection : uint32_t {
SENTINEL /* for IPC serialization */ SENTINEL /* for IPC serialization */
}; };
enum class CSSFilterType : int8_t {
BLUR,
BRIGHTNESS,
CONTRAST,
GRAYSCALE,
HUE_ROTATE,
INVERT,
OPACITY,
SATURATE,
SEPIA,
};
struct CSSFilter {
CSSFilterType type;
float argument;
};
CSSFilter ToCSSFilter(const nsStyleFilter& filter);
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -383,6 +383,7 @@ UNIFIED_SOURCES += [
'LayerScope.cpp', 'LayerScope.cpp',
'LayersLogging.cpp', 'LayersLogging.cpp',
'LayerSorter.cpp', 'LayerSorter.cpp',
'LayersTypes.cpp',
'opengl/CompositingRenderTargetOGL.cpp', 'opengl/CompositingRenderTargetOGL.cpp',
'opengl/CompositorOGL.cpp', 'opengl/CompositorOGL.cpp',
'opengl/GLBlitTextureImageHelper.cpp', 'opengl/GLBlitTextureImageHelper.cpp',

Просмотреть файл

@ -20,16 +20,19 @@ StackingContextHelper::StackingContextHelper()
StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC, StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC,
wr::DisplayListBuilder& aBuilder, wr::DisplayListBuilder& aBuilder,
WebRenderLayer* aLayer, WebRenderLayer* aLayer,
const Maybe<gfx::Matrix4x4>& aTransform) const Maybe<gfx::Matrix4x4>& aTransform,
const nsTArray<WrFilterOp>& aFilters)
: mBuilder(&aBuilder) : mBuilder(&aBuilder)
{ {
WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext()); WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext());
Layer* layer = aLayer->GetLayer(); Layer* layer = aLayer->GetLayer();
mTransform = aTransform.valueOr(layer->GetTransform()); mTransform = aTransform.valueOr(layer->GetTransform());
float opacity = 1.0f; float opacity = 1.0f;
mBuilder->PushStackingContext(scBounds, 0, &opacity, mBuilder->PushStackingContext(scBounds, 0, &opacity,
mTransform.IsIdentity() ? nullptr : &mTransform, mTransform.IsIdentity() ? nullptr : &mTransform,
wr::ToWrMixBlendMode(layer->GetMixBlendMode())); wr::ToWrMixBlendMode(layer->GetMixBlendMode()),
aFilters);
mOrigin = aLayer->Bounds().TopLeft(); mOrigin = aLayer->Bounds().TopLeft();
} }
@ -38,18 +41,21 @@ StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParen
WebRenderLayer* aLayer, WebRenderLayer* aLayer,
uint64_t aAnimationsId, uint64_t aAnimationsId,
float* aOpacityPtr, float* aOpacityPtr,
gfx::Matrix4x4* aTransformPtr) gfx::Matrix4x4* aTransformPtr,
const nsTArray<WrFilterOp>& aFilters)
: mBuilder(&aBuilder) : mBuilder(&aBuilder)
{ {
WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext()); WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext());
if (aTransformPtr) { if (aTransformPtr) {
mTransform = *aTransformPtr; mTransform = *aTransformPtr;
} }
mBuilder->PushStackingContext(scBounds, mBuilder->PushStackingContext(scBounds,
aAnimationsId, aAnimationsId,
aOpacityPtr, aOpacityPtr,
aTransformPtr, aTransformPtr,
wr::ToWrMixBlendMode(aLayer->GetLayer()->GetMixBlendMode())); wr::ToWrMixBlendMode(aLayer->GetLayer()->GetMixBlendMode()),
aFilters);
mOrigin = aLayer->Bounds().TopLeft(); mOrigin = aLayer->Bounds().TopLeft();
} }

Просмотреть файл

@ -31,7 +31,8 @@ public:
StackingContextHelper(const StackingContextHelper& aParentSC, StackingContextHelper(const StackingContextHelper& aParentSC,
wr::DisplayListBuilder& aBuilder, wr::DisplayListBuilder& aBuilder,
WebRenderLayer* aLayer, WebRenderLayer* aLayer,
const Maybe<gfx::Matrix4x4>& aTransform = Nothing()); const Maybe<gfx::Matrix4x4>& aTransform = Nothing(),
const nsTArray<WrFilterOp>& aFilters = nsTArray<WrFilterOp>());
// Alternate constructor which invokes the version of PushStackingContext // Alternate constructor which invokes the version of PushStackingContext
// for animations. // for animations.
StackingContextHelper(const StackingContextHelper& aParentSC, StackingContextHelper(const StackingContextHelper& aParentSC,
@ -39,7 +40,8 @@ public:
WebRenderLayer* aLayer, WebRenderLayer* aLayer,
uint64_t aAnimationsId, uint64_t aAnimationsId,
float* aOpacityPtr, float* aOpacityPtr,
gfx::Matrix4x4* aTransformPtr); gfx::Matrix4x4* aTransformPtr,
const nsTArray<WrFilterOp>& aFilters = nsTArray<WrFilterOp>());
// This version of the constructor should only be used at the root level // This version of the constructor should only be used at the root level
// of the tree, so that we have a StackingContextHelper to pass down into // of the tree, so that we have a StackingContextHelper to pass down into
// the RenderLayer traversal, but don't actually want it to push a stacking // the RenderLayer traversal, but don't actually want it to push a stacking

Просмотреть файл

@ -275,7 +275,8 @@ WebRenderCompositableHolder::ApplyAsyncImages(wr::WebRenderAPI* aApi)
0, 0,
&opacity, &opacity,
holder->mScTransform.IsIdentity() ? nullptr : &holder->mScTransform, holder->mScTransform.IsIdentity() ? nullptr : &holder->mScTransform,
holder->mMixBlendMode); holder->mMixBlendMode,
nsTArray<WrFilterOp>());
LayerRect rect(0, 0, holder->mCurrentTexture->GetSize().width, holder->mCurrentTexture->GetSize().height); LayerRect rect(0, 0, holder->mCurrentTexture->GetSize().width, holder->mCurrentTexture->GetSize().height);
if (holder->mScaleToSize.isSome()) { if (holder->mScaleToSize.isSome()) {

Просмотреть файл

@ -114,8 +114,13 @@ WebRenderContainerLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
transformForSC = nullptr; transformForSC = nullptr;
} }
nsTArray<WrFilterOp> filters;
for (const CSSFilter& filter : this->GetFilterChain()) {
filters.AppendElement(wr::ToWrFilterOp(filter));
}
ScrollingLayersHelper scroller(this, aBuilder, aSc); ScrollingLayersHelper scroller(this, aBuilder, aSc);
StackingContextHelper sc(aSc, aBuilder, this, animationsId, opacityForSC, transformForSC); StackingContextHelper sc(aSc, aBuilder, this, animationsId, opacityForSC, transformForSC, filters);
LayerRect rect = Bounds(); LayerRect rect = Bounds();
DumpLayerInfo("ContainerLayer", rect); DumpLayerInfo("ContainerLayer", rect);

Просмотреть файл

@ -504,6 +504,7 @@ private:
DECL_OVERRIDE_PREF(Live, "layers.advanced.caret-layers", LayersAllowCaretLayers, gfxPrefs::OverrideBase_WebRender()); DECL_OVERRIDE_PREF(Live, "layers.advanced.caret-layers", LayersAllowCaretLayers, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.columnRule-layers", LayersAllowColumnRuleLayers, gfxPrefs::OverrideBase_WebRender()); DECL_OVERRIDE_PREF(Live, "layers.advanced.columnRule-layers", LayersAllowColumnRuleLayers, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.displaybuttonborder-layers", LayersAllowDisplayButtonBorder, gfxPrefs::OverrideBase_WebRender()); DECL_OVERRIDE_PREF(Live, "layers.advanced.displaybuttonborder-layers", LayersAllowDisplayButtonBorder, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.filter-layers", LayersAllowFilterLayers, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.image-layers", LayersAllowImageLayers, gfxPrefs::OverrideBase_WebRendest()); DECL_OVERRIDE_PREF(Live, "layers.advanced.image-layers", LayersAllowImageLayers, gfxPrefs::OverrideBase_WebRendest());
DECL_OVERRIDE_PREF(Live, "layers.advanced.outline-layers", LayersAllowOutlineLayers, gfxPrefs::OverrideBase_WebRender()); DECL_OVERRIDE_PREF(Live, "layers.advanced.outline-layers", LayersAllowOutlineLayers, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.solid-color", LayersAllowSolidColorLayers, gfxPrefs::OverrideBase_WebRender()); DECL_OVERRIDE_PREF(Live, "layers.advanced.solid-color", LayersAllowSolidColorLayers, gfxPrefs::OverrideBase_WebRender());

Просмотреть файл

@ -556,7 +556,8 @@ DisplayListBuilder::PushStackingContext(const WrRect& aBounds,
const uint64_t& aAnimationId, const uint64_t& aAnimationId,
const float* aOpacity, const float* aOpacity,
const gfx::Matrix4x4* aTransform, const gfx::Matrix4x4* aTransform,
const WrMixBlendMode& aMixBlendMode) const WrMixBlendMode& aMixBlendMode,
const nsTArray<WrFilterOp>& aFilters)
{ {
WrMatrix matrix; WrMatrix matrix;
if (aTransform) { if (aTransform) {
@ -566,7 +567,8 @@ DisplayListBuilder::PushStackingContext(const WrRect& aBounds,
WRDL_LOG("PushStackingContext b=%s t=%s\n", Stringify(aBounds).c_str(), WRDL_LOG("PushStackingContext b=%s t=%s\n", Stringify(aBounds).c_str(),
aTransform ? Stringify(*aTransform).c_str() : "none"); aTransform ? Stringify(*aTransform).c_str() : "none");
wr_dp_push_stacking_context(mWrState, aBounds, aAnimationId, aOpacity, wr_dp_push_stacking_context(mWrState, aBounds, aAnimationId, aOpacity,
maybeTransform, aMixBlendMode); maybeTransform, aMixBlendMode,
aFilters.Elements(), aFilters.Length());
} }
void void

Просмотреть файл

@ -150,7 +150,8 @@ public:
const uint64_t& aAnimationId, const uint64_t& aAnimationId,
const float* aOpacity, const float* aOpacity,
const gfx::Matrix4x4* aTransform, const gfx::Matrix4x4* aTransform,
const WrMixBlendMode& aMixBlendMode); const WrMixBlendMode& aMixBlendMode,
const nsTArray<WrFilterOp>& aFilters);
void PopStackingContext(); void PopStackingContext();
void PushClip(const WrRect& aClipRect, void PushClip(const WrRect& aClipRect,

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/gfx/Matrix.h" #include "mozilla/gfx/Matrix.h"
#include "mozilla/gfx/Types.h" #include "mozilla/gfx/Types.h"
#include "mozilla/gfx/Tools.h" #include "mozilla/gfx/Tools.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/Range.h" #include "mozilla/Range.h"
#include "Units.h" #include "Units.h"
#include "nsStyleConsts.h" #include "nsStyleConsts.h"
@ -551,6 +552,38 @@ struct BuiltDisplayList {
WrBuiltDisplayListDescriptor dl_desc; WrBuiltDisplayListDescriptor dl_desc;
}; };
static inline WrFilterOpType ToWrFilterOpType(const layers::CSSFilterType type) {
switch (type) {
case layers::CSSFilterType::BLUR:
return WrFilterOpType::Blur;
case layers::CSSFilterType::BRIGHTNESS:
return WrFilterOpType::Brightness;
case layers::CSSFilterType::CONTRAST:
return WrFilterOpType::Contrast;
case layers::CSSFilterType::GRAYSCALE:
return WrFilterOpType::Grayscale;
case layers::CSSFilterType::HUE_ROTATE:
return WrFilterOpType::HueRotate;
case layers::CSSFilterType::INVERT:
return WrFilterOpType::Invert;
case layers::CSSFilterType::OPACITY:
return WrFilterOpType::Opacity;
case layers::CSSFilterType::SATURATE:
return WrFilterOpType::Saturate;
case layers::CSSFilterType::SEPIA:
return WrFilterOpType::Sepia;
}
MOZ_ASSERT_UNREACHABLE("Tried to convert unknown filter type.");
return WrFilterOpType::Grayscale;
}
static inline WrFilterOp ToWrFilterOp(const layers::CSSFilter& filter) {
return {
ToWrFilterOpType(filter.type),
filter.argument,
};
}
} // namespace wr } // namespace wr
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::ffi::CString; use std::ffi::CString;
use std::{mem, slice}; use std::{mem, slice};
use std::path::PathBuf; use std::path::PathBuf;
use std::os::raw::{c_void, c_char}; use std::os::raw::{c_void, c_char, c_float};
use std::collections::HashMap; use std::collections::HashMap;
use gleam::gl; use gleam::gl;
@ -59,6 +59,27 @@ type WrYuvColorSpace = YuvColorSpace;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct WrExternalImageId(pub u64); pub struct WrExternalImageId(pub u64);
#[repr(u32)]
#[derive(Copy, Clone)]
pub enum WrFilterOpType {
Blur = 0,
Brightness = 1,
Contrast = 2,
Grayscale = 3,
HueRotate = 4,
Invert = 5,
Opacity = 6,
Saturate = 7,
Sepia = 8,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct WrFilterOp {
filter_type: WrFilterOpType,
argument: c_float,
}
impl Into<ExternalImageId> for WrExternalImageId { impl Into<ExternalImageId> for WrExternalImageId {
fn into(self) -> ExternalImageId { fn into(self) -> ExternalImageId {
ExternalImageId(self.0) ExternalImageId(self.0)
@ -1245,12 +1266,28 @@ pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
animation_id: u64, animation_id: u64,
opacity: *const f32, opacity: *const f32,
transform: *const WrMatrix, transform: *const WrMatrix,
mix_blend_mode: WrMixBlendMode) { mix_blend_mode: WrMixBlendMode,
filters: *const WrFilterOp,
filter_count: usize) {
assert!(unsafe { !is_in_render_thread() }); assert!(unsafe { !is_in_render_thread() });
let bounds = bounds.into(); let bounds = bounds.into();
let mut filters: Vec<FilterOp> = Vec::new(); let c_filters = make_slice(filters, filter_count);
let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
match c_filter.filter_type {
WrFilterOpType::Blur => FilterOp::Blur(Au::from_f32_px(c_filter.argument)),
WrFilterOpType::Brightness => FilterOp::Brightness(c_filter.argument),
WrFilterOpType::Contrast => FilterOp::Contrast(c_filter.argument),
WrFilterOpType::Grayscale => FilterOp::Grayscale(c_filter.argument),
WrFilterOpType::HueRotate => FilterOp::HueRotate(c_filter.argument),
WrFilterOpType::Invert => FilterOp::Invert(c_filter.argument),
WrFilterOpType::Opacity => FilterOp::Opacity(PropertyBinding::Value(c_filter.argument)),
WrFilterOpType::Saturate => FilterOp::Saturate(c_filter.argument),
WrFilterOpType::Sepia => FilterOp::Sepia(c_filter.argument),
}
}).collect();
let opacity = unsafe { opacity.as_ref() }; let opacity = unsafe { opacity.as_ref() };
if let Some(opacity) = opacity { if let Some(opacity) = opacity {
if *opacity < 1.0 { if *opacity < 1.0 {

Просмотреть файл

@ -51,6 +51,20 @@ enum class WrExternalImageType : uint32_t {
Sentinel /* this must be last for serialization purposes. */ Sentinel /* this must be last for serialization purposes. */
}; };
enum class WrFilterOpType : uint32_t {
Blur = 0,
Brightness = 1,
Contrast = 2,
Grayscale = 3,
HueRotate = 4,
Invert = 5,
Opacity = 6,
Saturate = 7,
Sepia = 8,
Sentinel /* this must be last for serialization purposes. */
};
enum class WrGradientExtendMode : uint32_t { enum class WrGradientExtendMode : uint32_t {
Clamp = 0, Clamp = 0,
Repeat = 1, Repeat = 1,
@ -423,6 +437,16 @@ struct WrComplexClipRegion {
} }
}; };
struct WrFilterOp {
WrFilterOpType filter_type;
float argument;
bool operator==(const WrFilterOp& aOther) const {
return filter_type == aOther.filter_type &&
argument == aOther.argument;
}
};
struct WrGlyphInstance { struct WrGlyphInstance {
uint32_t index; uint32_t index;
WrPoint point; WrPoint point;
@ -784,7 +808,9 @@ void wr_dp_push_stacking_context(WrState *aState,
uint64_t aAnimationId, uint64_t aAnimationId,
const float *aOpacity, const float *aOpacity,
const WrMatrix *aTransform, const WrMatrix *aTransform,
WrMixBlendMode aMixBlendMode) WrMixBlendMode aMixBlendMode,
const WrFilterOp *aFilters,
size_t aFilterCount)
WR_FUNC; WR_FUNC;
WR_INLINE WR_INLINE

Просмотреть файл

@ -8635,6 +8635,17 @@ nsDisplayFilter::BuildLayer(nsDisplayListBuilder* aBuilder,
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
newContainerParameters, nullptr); newContainerParameters, nullptr);
LayerState state = this->GetLayerState(aBuilder, aManager, newContainerParameters);
if (container && state != LAYER_SVG_EFFECTS) {
const nsTArray<nsStyleFilter>& filters = mFrame->StyleEffects()->mFilters;
nsTArray<layers::CSSFilter> cssFilters = nsTArray<layers::CSSFilter>(filters.Length());
for (const nsStyleFilter& filter : filters) {
cssFilters.AppendElement(ToCSSFilter(filter));
}
container->SetFilterChain(Move(cssFilters));
}
return container.forget(); return container.forget();
} }
@ -8667,7 +8678,25 @@ nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager, LayerManager* aManager,
const ContainerLayerParameters& aParameters) const ContainerLayerParameters& aParameters)
{ {
return LAYER_SVG_EFFECTS; if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
return LAYER_SVG_EFFECTS;
}
if (!ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowFilterLayers)) {
return LAYER_SVG_EFFECTS;
}
// Due to differences in the way that WebRender filters operate
// only the brightness and contrast filters use that path. We
// can gradually enable more filters as WebRender bugs are fixed.
for (const nsStyleFilter& filter : mFrame->StyleEffects()->mFilters) {
if (filter.GetType() != NS_STYLE_FILTER_BRIGHTNESS &&
filter.GetType() != NS_STYLE_FILTER_CONTRAST) {
return LAYER_SVG_EFFECTS;
}
}
return LAYER_ACTIVE;
} }
bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder, bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,

Просмотреть файл

@ -5740,6 +5740,7 @@ pref("layers.advanced.outline-layers", 2);
pref("layers.advanced.solid-color", 2); pref("layers.advanced.solid-color", 2);
pref("layers.advanced.table", 2); pref("layers.advanced.table", 2);
pref("layers.advanced.text-layers", 2); pref("layers.advanced.text-layers", 2);
pref("layers.advanced.filter-layers", 2);
// Whether webrender should be used as much as possible. // Whether webrender should be used as much as possible.
pref("gfx.webrendest.enabled", false); pref("gfx.webrendest.enabled", false);