no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / layout / svg / CSSFilterInstance.cpp
blob06bb92f334d5bac304a7e0bfe70870038e498056
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/. */
7 // Main header first:
8 #include "CSSFilterInstance.h"
10 // Keep others in (case-insensitive) order:
11 #include "FilterDescription.h"
12 #include "gfx2DGlue.h"
13 #include "gfxUtils.h"
14 #include "nsIFrame.h"
15 #include "nsStyleStruct.h"
16 #include "nsTArray.h"
18 using namespace mozilla::gfx;
20 namespace mozilla {
22 static float ClampFactor(float aFactor) {
23 if (aFactor > 1) {
24 return 1;
26 if (aFactor < 0) {
27 MOZ_ASSERT_UNREACHABLE("A negative value should not have been parsed.");
28 return 0;
31 return aFactor;
34 CSSFilterInstance::CSSFilterInstance(
35 const StyleFilter& aFilter, nscolor aShadowFallbackColor,
36 const nsIntRect& aTargetBoundsInFilterSpace,
37 const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
38 : mFilter(aFilter),
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);
49 nsresult result;
50 switch (mFilter.tag) {
51 case StyleFilter::Tag::Blur:
52 result = SetAttributesForBlur(descr);
53 break;
54 case StyleFilter::Tag::Brightness:
55 result = SetAttributesForBrightness(descr);
56 break;
57 case StyleFilter::Tag::Contrast:
58 result = SetAttributesForContrast(descr);
59 break;
60 case StyleFilter::Tag::DropShadow:
61 result = SetAttributesForDropShadow(descr);
62 break;
63 case StyleFilter::Tag::Grayscale:
64 result = SetAttributesForGrayscale(descr);
65 break;
66 case StyleFilter::Tag::HueRotate:
67 result = SetAttributesForHueRotate(descr);
68 break;
69 case StyleFilter::Tag::Invert:
70 result = SetAttributesForInvert(descr);
71 break;
72 case StyleFilter::Tag::Opacity:
73 result = SetAttributesForOpacity(descr);
74 break;
75 case StyleFilter::Tag::Saturate:
76 result = SetAttributesForSaturate(descr);
77 break;
78 case StyleFilter::Tag::Sepia:
79 result = SetAttributesForSepia(descr);
80 break;
81 default:
82 MOZ_ASSERT_UNREACHABLE("not a valid CSS filter type");
83 return NS_ERROR_FAILURE;
86 if (NS_FAILED(result)) {
87 return 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));
96 return NS_OK;
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);
109 return descr;
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);
120 return NS_OK;
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));
141 return NS_OK;
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));
162 return NS_OK;
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;
175 // Set offset.
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));
185 return NS_OK;
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));
199 return NS_OK;
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));
213 return NS_OK;
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));
235 return NS_OK;
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));
245 return NS_OK;
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));
259 return NS_OK;
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));
273 return NS_OK;
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()
287 .ConvertTo<float>();
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 "
295 "style");
296 return Size();
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