зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset b134d587690d (bug 1787623) for causing reftest failures on filter-basic-01.svg. CLOSED TREE
This commit is contained in:
Родитель
9f8436d1ca
Коммит
5907792df1
|
@ -8246,20 +8246,25 @@ bool nsDisplayBackdropFilters::CreateWebRenderCommands(
|
|||
const StackingContextHelper& aSc, RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
WrFiltersHolder wrFilters;
|
||||
Maybe<nsRect> filterClip;
|
||||
const ComputedStyle& style = mStyle ? *mStyle : *mFrame->Style();
|
||||
auto filterChain = style.StyleEffects()->mBackdropFilters.AsSpan();
|
||||
bool initialized = true;
|
||||
if (!SVGIntegrationUtils::CreateWebRenderCSSFilters(filterChain, mFrame,
|
||||
wrFilters) &&
|
||||
!SVGIntegrationUtils::BuildWebRenderFilters(mFrame, filterChain,
|
||||
wrFilters, initialized)) {
|
||||
// TODO: If painting backdrop-filters on the content side is implemented,
|
||||
// consider returning false to fall back to that.
|
||||
wrFilters = {};
|
||||
!SVGIntegrationUtils::BuildWebRenderFilters(
|
||||
mFrame, filterChain, wrFilters, filterClip, initialized)) {
|
||||
if (mStyle) {
|
||||
// TODO(bug 1769223): Support fallback backdrop-filters in the root
|
||||
// code-path.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
wrFilters = {};
|
||||
// draw nothing
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCSSRendering::ImageLayerClipState clip;
|
||||
|
@ -8359,41 +8364,33 @@ bool nsDisplayFilters::CreateWebRenderCommands(
|
|||
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc, RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
WrFiltersHolder wrFilters;
|
||||
const ComputedStyle& style = mStyle ? *mStyle : *mFrame->Style();
|
||||
auto filterChain = style.StyleEffects()->mFilters.AsSpan();
|
||||
Maybe<nsRect> filterClip;
|
||||
bool initialized = true;
|
||||
auto filterChain = mStyle ? mStyle->StyleEffects()->mFilters.AsSpan()
|
||||
: mFrame->StyleEffects()->mFilters.AsSpan();
|
||||
if (!SVGIntegrationUtils::CreateWebRenderCSSFilters(filterChain, mFrame,
|
||||
wrFilters) &&
|
||||
!SVGIntegrationUtils::BuildWebRenderFilters(mFrame, filterChain,
|
||||
wrFilters, initialized)) {
|
||||
!SVGIntegrationUtils::BuildWebRenderFilters(
|
||||
mFrame, filterChain, wrFilters, filterClip, initialized)) {
|
||||
if (mStyle) {
|
||||
// TODO(bug 1769223): Support fallback filters in the root code-path,
|
||||
// perhaps. For now treat it the same way as invalid filters.
|
||||
wrFilters = {};
|
||||
} else {
|
||||
// Draw using fallback.
|
||||
return false;
|
||||
// TODO(bug 1769223): Support fallback filters in the root code-path.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
// https://drafts.fxtf.org/filter-effects/#typedef-filter-url:
|
||||
//
|
||||
// If the filter references a non-existent object or the referenced object
|
||||
// is not a filter element, then the whole filter chain is ignored. No
|
||||
// filter is applied to the object.
|
||||
//
|
||||
// Note that other engines have a weird discrepancy between SVG and HTML
|
||||
// content here, but the spec is clear.
|
||||
wrFilters = {};
|
||||
// draw nothing
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t clipChainId;
|
||||
if (wrFilters.post_filters_clip) {
|
||||
if (filterClip) {
|
||||
auto devPxRect = LayoutDeviceRect::FromAppUnits(
|
||||
wrFilters.post_filters_clip.value() + ToReferenceFrame(),
|
||||
mFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
filterClip.value() + ToReferenceFrame(), auPerDevPixel);
|
||||
auto clipId =
|
||||
aBuilder.DefineRectClip(Nothing(), wr::ToLayoutRect(devPxRect));
|
||||
clipChainId = aBuilder.DefineClipChain({clipId}, true).id;
|
||||
|
|
|
@ -8,5 +8,6 @@
|
|||
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=407463 -->
|
||||
|
||||
<rect x="0%" y="0%" width="100%" height="100%" fill="lime" filter="url(#null)"/>
|
||||
<rect x="0%" y="0%" width="100%" height="100%" fill="lime"/>
|
||||
<rect x="0%" y="0%" width="100%" height="100%" fill="red" filter="url(#null)"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 363 B После Ширина: | Высота: | Размер: 426 B |
|
@ -120,9 +120,10 @@ static mozilla::wr::ComponentTransferFuncType FuncTypeToWr(uint8_t aFuncType) {
|
|||
bool FilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
|
||||
Span<const StyleFilter> aFilters,
|
||||
WrFiltersHolder& aWrFilters,
|
||||
Maybe<nsRect>& aPostFilterClip,
|
||||
bool& aInitialized) {
|
||||
bool status = BuildWebRenderFiltersImpl(aFilteredFrame, aFilters, aWrFilters,
|
||||
aInitialized);
|
||||
aPostFilterClip, aInitialized);
|
||||
if (!status) {
|
||||
aFilteredFrame->PresContext()->Document()->SetUseCounter(
|
||||
eUseCounter_custom_WrFilterFallback);
|
||||
|
@ -134,6 +135,7 @@ bool FilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
|
|||
bool FilterInstance::BuildWebRenderFiltersImpl(nsIFrame* aFilteredFrame,
|
||||
Span<const StyleFilter> aFilters,
|
||||
WrFiltersHolder& aWrFilters,
|
||||
Maybe<nsRect>& aPostFilterClip,
|
||||
bool& aInitialized) {
|
||||
aWrFilters.filters.Clear();
|
||||
aWrFilters.filter_datas.Clear();
|
||||
|
@ -366,12 +368,36 @@ bool FilterInstance::BuildWebRenderFiltersImpl(nsIFrame* aFilteredFrame,
|
|||
}
|
||||
|
||||
if (finalClip) {
|
||||
aWrFilters.post_filters_clip =
|
||||
Some(instance.FilterSpaceToFrameSpace(finalClip.value()));
|
||||
aPostFilterClip = Some(instance.FilterSpaceToFrameSpace(finalClip.value()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRegion FilterInstance::GetPostFilterDirtyArea(
|
||||
nsIFrame* aFilteredFrame, const nsRegion& aPreFilterDirtyRegion) {
|
||||
if (aPreFilterDirtyRegion.IsEmpty()) {
|
||||
return nsRegion();
|
||||
}
|
||||
|
||||
gfxMatrix tm = SVGUtils::GetCanvasTM(aFilteredFrame);
|
||||
auto filterChain = aFilteredFrame->StyleEffects()->mFilters.AsSpan();
|
||||
UniquePtr<UserSpaceMetrics> metrics =
|
||||
UserSpaceMetricsForFrame(aFilteredFrame);
|
||||
// Hardcode InputIsTainted to true because we don't want JS to be able to
|
||||
// read the rendered contents of aFilteredFrame.
|
||||
FilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
|
||||
*metrics, filterChain, /* InputIsTainted */ true,
|
||||
nullptr, tm, nullptr, &aPreFilterDirtyRegion);
|
||||
if (!instance.IsInitialized()) {
|
||||
return nsRegion();
|
||||
}
|
||||
|
||||
// We've passed in the source's dirty area so the instance knows about it.
|
||||
// Now we can ask the instance to compute the area of the filter output
|
||||
// that's dirty.
|
||||
return instance.ComputePostFilterDirtyRegion();
|
||||
}
|
||||
|
||||
nsRegion FilterInstance::GetPreFilterNeededArea(
|
||||
nsIFrame* aFilteredFrame, const nsRegion& aPostFilterDirtyRegion) {
|
||||
gfxMatrix tm = SVGUtils::GetCanvasTM(aFilteredFrame);
|
||||
|
@ -392,8 +418,8 @@ nsRegion FilterInstance::GetPreFilterNeededArea(
|
|||
return instance.ComputeSourceNeededRect();
|
||||
}
|
||||
|
||||
Maybe<nsRect> FilterInstance::GetPostFilterBounds(
|
||||
nsIFrame* aFilteredFrame, const gfxRect* aOverrideBBox,
|
||||
nsRect FilterInstance::GetPostFilterBounds(nsIFrame* aFilteredFrame,
|
||||
const gfxRect* aOverrideBBox,
|
||||
const nsRect* aPreFilterBounds) {
|
||||
MOZ_ASSERT(!aFilteredFrame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) ||
|
||||
!aFilteredFrame->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY),
|
||||
|
@ -417,10 +443,10 @@ Maybe<nsRect> FilterInstance::GetPostFilterBounds(
|
|||
nullptr, tm, nullptr, preFilterRegionPtr,
|
||||
aPreFilterBounds, aOverrideBBox);
|
||||
if (!instance.IsInitialized()) {
|
||||
return Nothing();
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
return Some(instance.ComputePostFilterExtents());
|
||||
return instance.ComputePostFilterExtents();
|
||||
}
|
||||
|
||||
FilterInstance::FilterInstance(
|
||||
|
|
|
@ -123,8 +123,8 @@ class FilterInstance {
|
|||
* @param aPreFilterBounds The pre-filter ink overflow rect of
|
||||
* aFilteredFrame, if non-null.
|
||||
*/
|
||||
static Maybe<nsRect> GetPostFilterBounds(
|
||||
nsIFrame* aFilteredFrame, const gfxRect* aOverrideBBox = nullptr,
|
||||
static nsRect GetPostFilterBounds(nsIFrame* aFilteredFrame,
|
||||
const gfxRect* aOverrideBBox = nullptr,
|
||||
const nsRect* aPreFilterBounds = nullptr);
|
||||
|
||||
/**
|
||||
|
@ -136,7 +136,8 @@ class FilterInstance {
|
|||
static bool BuildWebRenderFilters(
|
||||
nsIFrame* aFilteredFrame,
|
||||
mozilla::Span<const mozilla::StyleFilter> aFilters,
|
||||
WrFiltersHolder& aWrFilters, bool& aInitialized);
|
||||
WrFiltersHolder& aWrFilters, mozilla::Maybe<nsRect>& aPostFilterClip,
|
||||
bool& aInitialized);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -177,7 +178,8 @@ class FilterInstance {
|
|||
static bool BuildWebRenderFiltersImpl(
|
||||
nsIFrame* aFilteredFrame,
|
||||
mozilla::Span<const mozilla::StyleFilter> aFilters,
|
||||
WrFiltersHolder& aWrFilters, bool& aInitialized);
|
||||
WrFiltersHolder& aWrFilters, mozilla::Maybe<nsRect>& aPostFilterClip,
|
||||
bool& aInitialized);
|
||||
|
||||
/**
|
||||
* Returns true if the filter instance was created successfully.
|
||||
|
|
|
@ -391,17 +391,54 @@ nsRect SVGIntegrationUtils::ComputePostEffectsInkOverflowRect(
|
|||
AppUnitsPerCSSPixel());
|
||||
overrideBBox.RoundOut();
|
||||
|
||||
Maybe<nsRect> overflowRect =
|
||||
nsRect overflowRect =
|
||||
FilterInstance::GetPostFilterBounds(firstFrame, &overrideBBox);
|
||||
if (!overflowRect) {
|
||||
return aPreEffectsOverflowRect;
|
||||
}
|
||||
|
||||
// Return overflowRect relative to aFrame, rather than "user space":
|
||||
return overflowRect.value() -
|
||||
return overflowRect -
|
||||
(aFrame->GetOffsetTo(firstFrame) + firstFrameToBoundingBox);
|
||||
}
|
||||
|
||||
nsIntRegion SVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(
|
||||
nsIFrame* aFrame, const nsPoint& aToReferenceFrame,
|
||||
const nsIntRegion& aInvalidRegion) {
|
||||
if (aInvalidRegion.IsEmpty()) {
|
||||
return nsIntRect();
|
||||
}
|
||||
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
|
||||
|
||||
// If we have any filters to observe then we should have started doing that
|
||||
// during reflow/ComputeFrameEffectsRect, so we use GetFiltersIfObserving
|
||||
// here to avoid needless work (or masking bugs by setting up observers at
|
||||
// the wrong time).
|
||||
if (!aFrame->StyleEffects()->HasFilters() ||
|
||||
SVGObserverUtils::GetFiltersIfObserving(firstFrame, nullptr) ==
|
||||
SVGObserverUtils::eHasRefsSomeInvalid) {
|
||||
return aInvalidRegion;
|
||||
}
|
||||
|
||||
int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
// Convert aInvalidRegion into bounding box frame space in app units:
|
||||
nsPoint toBoundingBox =
|
||||
aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame);
|
||||
// The initial rect was relative to the reference frame, so we need to
|
||||
// remove that offset to get a rect relative to the current frame.
|
||||
toBoundingBox -= aToReferenceFrame;
|
||||
nsRegion preEffectsRegion =
|
||||
aInvalidRegion.ToAppUnits(appUnitsPerDevPixel).MovedBy(toBoundingBox);
|
||||
|
||||
// Adjust the dirty area for effects, and shift it back to being relative to
|
||||
// the reference frame.
|
||||
nsRegion result =
|
||||
FilterInstance::GetPostFilterDirtyArea(firstFrame, preEffectsRegion)
|
||||
.MovedBy(-toBoundingBox);
|
||||
// Return the result, in pixels relative to the reference frame.
|
||||
return result.ToOutsidePixels(appUnitsPerDevPixel);
|
||||
}
|
||||
|
||||
nsRect SVGIntegrationUtils::GetRequiredSourceForInvalidArea(
|
||||
nsIFrame* aFrame, const nsRect& aDirtyRect) {
|
||||
nsIFrame* firstFrame =
|
||||
|
@ -1084,17 +1121,20 @@ bool SVGIntegrationUtils::CreateWebRenderCSSFilters(
|
|||
|
||||
bool SVGIntegrationUtils::BuildWebRenderFilters(
|
||||
nsIFrame* aFilteredFrame, Span<const StyleFilter> aFilters,
|
||||
WrFiltersHolder& aWrFilters, bool& aInitialized) {
|
||||
return FilterInstance::BuildWebRenderFilters(aFilteredFrame, aFilters,
|
||||
aWrFilters, aInitialized);
|
||||
WrFiltersHolder& aWrFilters, Maybe<nsRect>& aPostFilterClip,
|
||||
bool& aInitialized) {
|
||||
return FilterInstance::BuildWebRenderFilters(
|
||||
aFilteredFrame, aFilters, aWrFilters, aPostFilterClip, aInitialized);
|
||||
}
|
||||
|
||||
bool SVGIntegrationUtils::CanCreateWebRenderFiltersForFrame(nsIFrame* aFrame) {
|
||||
WrFiltersHolder wrFilters;
|
||||
Maybe<nsRect> filterClip;
|
||||
auto filterChain = aFrame->StyleEffects()->mFilters.AsSpan();
|
||||
bool initialized = true;
|
||||
return CreateWebRenderCSSFilters(filterChain, aFrame, wrFilters) ||
|
||||
BuildWebRenderFilters(aFrame, filterChain, wrFilters, initialized);
|
||||
BuildWebRenderFilters(aFrame, filterChain, wrFilters, filterClip,
|
||||
initialized);
|
||||
}
|
||||
|
||||
bool SVGIntegrationUtils::UsesSVGEffectsNotSupportedInCompositor(
|
||||
|
|
|
@ -25,7 +25,6 @@ struct nsSize;
|
|||
struct WrFiltersHolder {
|
||||
nsTArray<mozilla::wr::FilterOp> filters;
|
||||
nsTArray<mozilla::wr::WrFilterData> filter_datas;
|
||||
mozilla::Maybe<nsRect> post_filters_clip;
|
||||
// This exists just to own the values long enough for them to be copied into
|
||||
// rust.
|
||||
nsTArray<nsTArray<float>> values;
|
||||
|
@ -116,6 +115,22 @@ class SVGIntegrationUtils final {
|
|||
static nsRect ComputePostEffectsInkOverflowRect(
|
||||
nsIFrame* aFrame, const nsRect& aPreEffectsOverflowRect);
|
||||
|
||||
/**
|
||||
* Used to adjust the area of a frame that needs to be invalidated to take
|
||||
* account of SVG effects.
|
||||
*
|
||||
* @param aFrame The effects frame.
|
||||
* @param aToReferenceFrame The offset (in app units) from aFrame to its
|
||||
* reference display item.
|
||||
* @param aInvalidRegion The pre-effects invalid region in pixels relative to
|
||||
* the reference display item.
|
||||
* @return The post-effects invalid rect in pixels relative to the reference
|
||||
* display item.
|
||||
*/
|
||||
static nsIntRegion AdjustInvalidAreaForSVGEffects(
|
||||
nsIFrame* aFrame, const nsPoint& aToReferenceFrame,
|
||||
const nsIntRegion& aInvalidRegion);
|
||||
|
||||
/**
|
||||
* Figure out which area of the source is needed given an area to
|
||||
* repaint
|
||||
|
@ -208,6 +223,7 @@ class SVGIntegrationUtils final {
|
|||
static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
|
||||
Span<const StyleFilter> aFilters,
|
||||
WrFiltersHolder& aWrFilters,
|
||||
Maybe<nsRect>& aPostFilterClip,
|
||||
bool& aInitialized);
|
||||
|
||||
/**
|
||||
|
|
|
@ -127,8 +127,7 @@ nsRect SVGUtils::GetPostFilterInkOverflowRect(nsIFrame* aFrame,
|
|||
return aPreFilterRect;
|
||||
}
|
||||
|
||||
return FilterInstance::GetPostFilterBounds(aFrame, nullptr, &aPreFilterRect)
|
||||
.valueOr(aPreFilterRect);
|
||||
return FilterInstance::GetPostFilterBounds(aFrame, nullptr, &aPreFilterRect);
|
||||
}
|
||||
|
||||
bool SVGUtils::OuterSVGIsCallingReflowSVG(nsIFrame* aFrame) {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[effect-reference-delete.html]
|
||||
expected: FAIL
|
|
@ -1,25 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Invalid backdrop-filter doesn't cause element to disappear</title>
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="help" href="https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty">
|
||||
<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#typedef-filter-value-list">
|
||||
<link rel="match" href="filter-invalid-ref.html">
|
||||
<style>
|
||||
div, rect {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
backdrop-filter: url(#not-found);
|
||||
}
|
||||
div {
|
||||
background-color: blue;
|
||||
}
|
||||
rect {
|
||||
fill: purple;
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
<svg>
|
||||
<rect></rect>
|
||||
</svg>
|
|
@ -1,27 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Maybe-unsupported backdrop-filter doesn't cause element to disappear</title>
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="help" href="https://drafts.fxtf.org/filter-effects/#BackdropFilterProperty">
|
||||
<link rel="mismatch" href="/css/reference/blank.html">
|
||||
<style>
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 5px solid green;
|
||||
backdrop-filter: url(#from-svg);
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
<svg>
|
||||
<defs>
|
||||
<filter id="from-svg">
|
||||
<feGaussianBlur in="BackgroundImage" stdDeviation="20" result="blur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
<feMergeNode in="blur" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
|
@ -1,19 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test Reference</title>
|
||||
<style>
|
||||
div, rect {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
div {
|
||||
background-color: blue;
|
||||
}
|
||||
rect {
|
||||
fill: purple;
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
<svg>
|
||||
<rect></rect>
|
||||
</svg>
|
|
@ -1,24 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Invalid filter draws unfiltered frame</title>
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="help" href="https://drafts.fxtf.org/filter-effects/#typedef-filter-url">
|
||||
<link rel="match" href="filter-invalid-ref.html">
|
||||
<style>
|
||||
div, rect {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
filter: url(#not-found);
|
||||
}
|
||||
div {
|
||||
background-color: blue;
|
||||
}
|
||||
rect {
|
||||
fill: purple;
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
<svg>
|
||||
<rect></rect>
|
||||
</svg>
|
|
@ -1,27 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Unsupported filter draws unfiltered frame</title>
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="help" href="https://drafts.fxtf.org/filter-effects/#FilterProperty">
|
||||
<link rel="mismatch" href="/css/reference/blank.html">
|
||||
<style>
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 5px solid green;
|
||||
filter: url(#from-svg);
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
<svg>
|
||||
<defs>
|
||||
<filter id="from-svg">
|
||||
<feGaussianBlur in="BackgroundImage" stdDeviation="20" result="blur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
<feMergeNode in="blur" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
Загрузка…
Ссылка в новой задаче