1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "CSSFilterInstance.h"
10 // Keep others in (case-insensitive) order:
11 #include "FilterDescription.h"
12 #include "gfx2DGlue.h"
15 #include "nsStyleStruct.h"
18 using namespace mozilla::gfx
;
22 static float ClampFactor(float aFactor
) {
27 MOZ_ASSERT_UNREACHABLE("A negative value should not have been parsed.");
34 CSSFilterInstance::CSSFilterInstance(
35 const StyleFilter
& aFilter
, nscolor aShadowFallbackColor
,
36 const nsIntRect
& aTargetBoundsInFilterSpace
,
37 const gfxMatrix
& aFrameSpaceInCSSPxToFilterSpaceTransform
)
39 mShadowFallbackColor(aShadowFallbackColor
),
40 mTargetBoundsInFilterSpace(aTargetBoundsInFilterSpace
),
41 mFrameSpaceInCSSPxToFilterSpaceTransform(
42 aFrameSpaceInCSSPxToFilterSpaceTransform
) {}
44 nsresult
CSSFilterInstance::BuildPrimitives(
45 nsTArray
<FilterPrimitiveDescription
>& aPrimitiveDescrs
,
46 bool aInputIsTainted
) {
47 FilterPrimitiveDescription descr
=
48 CreatePrimitiveDescription(aPrimitiveDescrs
, aInputIsTainted
);
50 switch (mFilter
.tag
) {
51 case StyleFilter::Tag::Blur
:
52 result
= SetAttributesForBlur(descr
);
54 case StyleFilter::Tag::Brightness
:
55 result
= SetAttributesForBrightness(descr
);
57 case StyleFilter::Tag::Contrast
:
58 result
= SetAttributesForContrast(descr
);
60 case StyleFilter::Tag::DropShadow
:
61 result
= SetAttributesForDropShadow(descr
);
63 case StyleFilter::Tag::Grayscale
:
64 result
= SetAttributesForGrayscale(descr
);
66 case StyleFilter::Tag::HueRotate
:
67 result
= SetAttributesForHueRotate(descr
);
69 case StyleFilter::Tag::Invert
:
70 result
= SetAttributesForInvert(descr
);
72 case StyleFilter::Tag::Opacity
:
73 result
= SetAttributesForOpacity(descr
);
75 case StyleFilter::Tag::Saturate
:
76 result
= SetAttributesForSaturate(descr
);
78 case StyleFilter::Tag::Sepia
:
79 result
= SetAttributesForSepia(descr
);
82 MOZ_ASSERT_UNREACHABLE("not a valid CSS filter type");
83 return NS_ERROR_FAILURE
;
86 if (NS_FAILED(result
)) {
90 // Compute the primitive's bounds now that we've determined its attributes.
91 // Some attributes like blur radius can influence the bounds.
92 SetBounds(descr
, aPrimitiveDescrs
);
94 // Add this primitive to the filter chain.
95 aPrimitiveDescrs
.AppendElement(std::move(descr
));
99 FilterPrimitiveDescription
CSSFilterInstance::CreatePrimitiveDescription(
100 const nsTArray
<FilterPrimitiveDescription
>& aPrimitiveDescrs
,
101 bool aInputIsTainted
) {
102 FilterPrimitiveDescription descr
;
103 int32_t inputIndex
= GetLastResultIndex(aPrimitiveDescrs
);
104 descr
.SetInputPrimitive(0, inputIndex
);
105 descr
.SetIsTainted(inputIndex
< 0 ? aInputIsTainted
106 : aPrimitiveDescrs
[inputIndex
].IsTainted());
107 descr
.SetInputColorSpace(0, ColorSpace::SRGB
);
108 descr
.SetOutputColorSpace(ColorSpace::SRGB
);
112 nsresult
CSSFilterInstance::SetAttributesForBlur(
113 FilterPrimitiveDescription
& aDescr
) {
114 const Length
& radiusInFrameSpace
= mFilter
.AsBlur();
115 Size radiusInFilterSpace
=
116 BlurRadiusToFilterSpace(radiusInFrameSpace
.ToAppUnits());
117 GaussianBlurAttributes atts
;
118 atts
.mStdDeviation
= radiusInFilterSpace
;
119 aDescr
.Attributes() = AsVariant(atts
);
123 nsresult
CSSFilterInstance::SetAttributesForBrightness(
124 FilterPrimitiveDescription
& aDescr
) {
125 float value
= mFilter
.AsBrightness();
126 float intercept
= 0.0f
;
127 ComponentTransferAttributes atts
;
129 // Set transfer functions for RGB.
130 atts
.mTypes
[kChannelROrRGB
] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_LINEAR
;
131 atts
.mTypes
[kChannelG
] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R
;
132 atts
.mTypes
[kChannelB
] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R
;
133 float slopeIntercept
[2];
134 slopeIntercept
[kComponentTransferSlopeIndex
] = value
;
135 slopeIntercept
[kComponentTransferInterceptIndex
] = intercept
;
136 atts
.mValues
[kChannelROrRGB
].AppendElements(slopeIntercept
, 2);
138 atts
.mTypes
[kChannelA
] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
;
140 aDescr
.Attributes() = AsVariant(std::move(atts
));
144 nsresult
CSSFilterInstance::SetAttributesForContrast(
145 FilterPrimitiveDescription
& aDescr
) {
146 float value
= mFilter
.AsContrast();
147 float intercept
= -(0.5 * value
) + 0.5;
148 ComponentTransferAttributes atts
;
150 // Set transfer functions for RGB.
151 atts
.mTypes
[kChannelROrRGB
] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_LINEAR
;
152 atts
.mTypes
[kChannelG
] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R
;
153 atts
.mTypes
[kChannelB
] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R
;
154 float slopeIntercept
[2];
155 slopeIntercept
[kComponentTransferSlopeIndex
] = value
;
156 slopeIntercept
[kComponentTransferInterceptIndex
] = intercept
;
157 atts
.mValues
[kChannelROrRGB
].AppendElements(slopeIntercept
, 2);
159 atts
.mTypes
[kChannelA
] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
;
161 aDescr
.Attributes() = AsVariant(std::move(atts
));
165 nsresult
CSSFilterInstance::SetAttributesForDropShadow(
166 FilterPrimitiveDescription
& aDescr
) {
167 const auto& shadow
= mFilter
.AsDropShadow();
169 DropShadowAttributes atts
;
171 // Set drop shadow blur radius.
172 Size radiusInFilterSpace
= BlurRadiusToFilterSpace(shadow
.blur
.ToAppUnits());
173 atts
.mStdDeviation
= radiusInFilterSpace
;
176 IntPoint offsetInFilterSpace
= OffsetToFilterSpace(
177 shadow
.horizontal
.ToAppUnits(), shadow
.vertical
.ToAppUnits());
178 atts
.mOffset
= offsetInFilterSpace
;
180 // Set color. If unspecified, use the CSS color property.
181 nscolor shadowColor
= shadow
.color
.CalcColor(mShadowFallbackColor
);
182 atts
.mColor
= ToAttributeColor(shadowColor
);
184 aDescr
.Attributes() = AsVariant(std::move(atts
));
188 nsresult
CSSFilterInstance::SetAttributesForGrayscale(
189 FilterPrimitiveDescription
& aDescr
) {
190 ColorMatrixAttributes atts
;
191 // Set color matrix type.
192 atts
.mType
= (uint32_t)SVG_FECOLORMATRIX_TYPE_SATURATE
;
194 // Set color matrix values.
195 float value
= 1 - ClampFactor(mFilter
.AsGrayscale());
196 atts
.mValues
.AppendElements(&value
, 1);
198 aDescr
.Attributes() = AsVariant(std::move(atts
));
202 nsresult
CSSFilterInstance::SetAttributesForHueRotate(
203 FilterPrimitiveDescription
& aDescr
) {
204 ColorMatrixAttributes atts
;
205 // Set color matrix type.
206 atts
.mType
= (uint32_t)SVG_FECOLORMATRIX_TYPE_HUE_ROTATE
;
208 // Set color matrix values.
209 float value
= mFilter
.AsHueRotate().ToDegrees();
210 atts
.mValues
.AppendElements(&value
, 1);
212 aDescr
.Attributes() = AsVariant(std::move(atts
));
216 nsresult
CSSFilterInstance::SetAttributesForInvert(
217 FilterPrimitiveDescription
& aDescr
) {
218 ComponentTransferAttributes atts
;
219 float value
= ClampFactor(mFilter
.AsInvert());
221 // Set transfer functions for RGB.
222 float invertTableValues
[2];
223 invertTableValues
[0] = value
;
224 invertTableValues
[1] = 1 - value
;
226 // Set transfer functions for RGB.
227 atts
.mTypes
[kChannelROrRGB
] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_TABLE
;
228 atts
.mTypes
[kChannelG
] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R
;
229 atts
.mTypes
[kChannelB
] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R
;
230 atts
.mValues
[kChannelROrRGB
].AppendElements(invertTableValues
, 2);
232 atts
.mTypes
[kChannelA
] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
;
234 aDescr
.Attributes() = AsVariant(std::move(atts
));
238 nsresult
CSSFilterInstance::SetAttributesForOpacity(
239 FilterPrimitiveDescription
& aDescr
) {
240 OpacityAttributes atts
;
241 float value
= ClampFactor(mFilter
.AsOpacity());
243 atts
.mOpacity
= value
;
244 aDescr
.Attributes() = AsVariant(std::move(atts
));
248 nsresult
CSSFilterInstance::SetAttributesForSaturate(
249 FilterPrimitiveDescription
& aDescr
) {
250 ColorMatrixAttributes atts
;
251 // Set color matrix type.
252 atts
.mType
= (uint32_t)SVG_FECOLORMATRIX_TYPE_SATURATE
;
254 // Set color matrix values.
255 float value
= mFilter
.AsSaturate();
256 atts
.mValues
.AppendElements(&value
, 1);
258 aDescr
.Attributes() = AsVariant(std::move(atts
));
262 nsresult
CSSFilterInstance::SetAttributesForSepia(
263 FilterPrimitiveDescription
& aDescr
) {
264 ColorMatrixAttributes atts
;
265 // Set color matrix type.
266 atts
.mType
= (uint32_t)SVG_FECOLORMATRIX_TYPE_SEPIA
;
268 // Set color matrix values.
269 float value
= ClampFactor(mFilter
.AsSepia());
270 atts
.mValues
.AppendElements(&value
, 1);
272 aDescr
.Attributes() = AsVariant(std::move(atts
));
276 Size
CSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace
) {
277 float radiusInFrameSpaceInCSSPx
=
278 nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace
);
280 // Convert the radius to filter space.
281 Size
radiusInFilterSpace(radiusInFrameSpaceInCSSPx
,
282 radiusInFrameSpaceInCSSPx
);
283 // Narrow the scale factors. They will only be used with types containing
284 // floating point types.
285 auto frameSpaceInCSSPxToFilterSpaceScale
=
286 mFrameSpaceInCSSPxToFilterSpaceTransform
.ScaleFactors()
288 radiusInFilterSpace
=
289 radiusInFilterSpace
* frameSpaceInCSSPxToFilterSpaceScale
;
291 // Check the radius limits.
292 if (radiusInFilterSpace
.width
< 0 || radiusInFilterSpace
.height
< 0) {
293 MOZ_ASSERT_UNREACHABLE(
294 "we shouldn't have parsed a negative radius in the "
299 Float maxStdDeviation
= (Float
)kMaxStdDeviation
;
300 radiusInFilterSpace
.width
=
301 std::min(radiusInFilterSpace
.width
, maxStdDeviation
);
302 radiusInFilterSpace
.height
=
303 std::min(radiusInFilterSpace
.height
, maxStdDeviation
);
305 return radiusInFilterSpace
;
308 IntPoint
CSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace
,
309 nscoord aYOffsetInFrameSpace
) {
310 gfxPoint
offsetInFilterSpace(
311 nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace
),
312 nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace
));
314 // Convert the radius to filter space.
315 auto frameSpaceInCSSPxToFilterSpaceScale
=
316 mFrameSpaceInCSSPxToFilterSpaceTransform
.ScaleFactors();
317 offsetInFilterSpace
.x
*= frameSpaceInCSSPxToFilterSpaceScale
.xScale
;
318 offsetInFilterSpace
.y
*= frameSpaceInCSSPxToFilterSpaceScale
.yScale
;
320 return IntPoint(int32_t(offsetInFilterSpace
.x
),
321 int32_t(offsetInFilterSpace
.y
));
324 sRGBColor
CSSFilterInstance::ToAttributeColor(nscolor aColor
) {
325 return sRGBColor(NS_GET_R(aColor
) / 255.0, NS_GET_G(aColor
) / 255.0,
326 NS_GET_B(aColor
) / 255.0, NS_GET_A(aColor
) / 255.0);
329 int32_t CSSFilterInstance::GetLastResultIndex(
330 const nsTArray
<FilterPrimitiveDescription
>& aPrimitiveDescrs
) {
331 uint32_t numPrimitiveDescrs
= aPrimitiveDescrs
.Length();
332 return !numPrimitiveDescrs
333 ? FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic
334 : numPrimitiveDescrs
- 1;
337 void CSSFilterInstance::SetBounds(
338 FilterPrimitiveDescription
& aDescr
,
339 const nsTArray
<FilterPrimitiveDescription
>& aPrimitiveDescrs
) {
340 int32_t inputIndex
= GetLastResultIndex(aPrimitiveDescrs
);
341 nsIntRect inputBounds
=
342 (inputIndex
< 0) ? mTargetBoundsInFilterSpace
343 : aPrimitiveDescrs
[inputIndex
].PrimitiveSubregion();
345 AutoTArray
<nsIntRegion
, 8> inputExtents
;
346 inputExtents
.AppendElement(inputBounds
);
348 nsIntRegion outputExtents
=
349 FilterSupport::PostFilterExtentsForPrimitive(aDescr
, inputExtents
);
350 IntRect outputBounds
= outputExtents
.GetBounds();
352 aDescr
.SetPrimitiveSubregion(outputBounds
);
353 aDescr
.SetFilterSpaceBounds(outputBounds
);
356 } // namespace mozilla