summaryrefslogtreecommitdiffstats
path: root/layout/svg/CSSFilterInstance.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /layout/svg/CSSFilterInstance.cpp
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'layout/svg/CSSFilterInstance.cpp')
-rw-r--r--layout/svg/CSSFilterInstance.cpp356
1 files changed, 356 insertions, 0 deletions
diff --git a/layout/svg/CSSFilterInstance.cpp b/layout/svg/CSSFilterInstance.cpp
new file mode 100644
index 0000000000..06bb92f334
--- /dev/null
+++ b/layout/svg/CSSFilterInstance.cpp
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+// Main header first:
+#include "CSSFilterInstance.h"
+
+// Keep others in (case-insensitive) order:
+#include "FilterDescription.h"
+#include "gfx2DGlue.h"
+#include "gfxUtils.h"
+#include "nsIFrame.h"
+#include "nsStyleStruct.h"
+#include "nsTArray.h"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+
+static float ClampFactor(float aFactor) {
+ if (aFactor > 1) {
+ return 1;
+ }
+ if (aFactor < 0) {
+ MOZ_ASSERT_UNREACHABLE("A negative value should not have been parsed.");
+ return 0;
+ }
+
+ return aFactor;
+}
+
+CSSFilterInstance::CSSFilterInstance(
+ const StyleFilter& aFilter, nscolor aShadowFallbackColor,
+ const nsIntRect& aTargetBoundsInFilterSpace,
+ const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
+ : mFilter(aFilter),
+ mShadowFallbackColor(aShadowFallbackColor),
+ mTargetBoundsInFilterSpace(aTargetBoundsInFilterSpace),
+ mFrameSpaceInCSSPxToFilterSpaceTransform(
+ aFrameSpaceInCSSPxToFilterSpaceTransform) {}
+
+nsresult CSSFilterInstance::BuildPrimitives(
+ nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
+ bool aInputIsTainted) {
+ FilterPrimitiveDescription descr =
+ CreatePrimitiveDescription(aPrimitiveDescrs, aInputIsTainted);
+ nsresult result;
+ switch (mFilter.tag) {
+ case StyleFilter::Tag::Blur:
+ result = SetAttributesForBlur(descr);
+ break;
+ case StyleFilter::Tag::Brightness:
+ result = SetAttributesForBrightness(descr);
+ break;
+ case StyleFilter::Tag::Contrast:
+ result = SetAttributesForContrast(descr);
+ break;
+ case StyleFilter::Tag::DropShadow:
+ result = SetAttributesForDropShadow(descr);
+ break;
+ case StyleFilter::Tag::Grayscale:
+ result = SetAttributesForGrayscale(descr);
+ break;
+ case StyleFilter::Tag::HueRotate:
+ result = SetAttributesForHueRotate(descr);
+ break;
+ case StyleFilter::Tag::Invert:
+ result = SetAttributesForInvert(descr);
+ break;
+ case StyleFilter::Tag::Opacity:
+ result = SetAttributesForOpacity(descr);
+ break;
+ case StyleFilter::Tag::Saturate:
+ result = SetAttributesForSaturate(descr);
+ break;
+ case StyleFilter::Tag::Sepia:
+ result = SetAttributesForSepia(descr);
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("not a valid CSS filter type");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (NS_FAILED(result)) {
+ return result;
+ }
+
+ // Compute the primitive's bounds now that we've determined its attributes.
+ // Some attributes like blur radius can influence the bounds.
+ SetBounds(descr, aPrimitiveDescrs);
+
+ // Add this primitive to the filter chain.
+ aPrimitiveDescrs.AppendElement(std::move(descr));
+ return NS_OK;
+}
+
+FilterPrimitiveDescription CSSFilterInstance::CreatePrimitiveDescription(
+ const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
+ bool aInputIsTainted) {
+ FilterPrimitiveDescription descr;
+ int32_t inputIndex = GetLastResultIndex(aPrimitiveDescrs);
+ descr.SetInputPrimitive(0, inputIndex);
+ descr.SetIsTainted(inputIndex < 0 ? aInputIsTainted
+ : aPrimitiveDescrs[inputIndex].IsTainted());
+ descr.SetInputColorSpace(0, ColorSpace::SRGB);
+ descr.SetOutputColorSpace(ColorSpace::SRGB);
+ return descr;
+}
+
+nsresult CSSFilterInstance::SetAttributesForBlur(
+ FilterPrimitiveDescription& aDescr) {
+ const Length& radiusInFrameSpace = mFilter.AsBlur();
+ Size radiusInFilterSpace =
+ BlurRadiusToFilterSpace(radiusInFrameSpace.ToAppUnits());
+ GaussianBlurAttributes atts;
+ atts.mStdDeviation = radiusInFilterSpace;
+ aDescr.Attributes() = AsVariant(atts);
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForBrightness(
+ FilterPrimitiveDescription& aDescr) {
+ float value = mFilter.AsBrightness();
+ float intercept = 0.0f;
+ ComponentTransferAttributes atts;
+
+ // Set transfer functions for RGB.
+ atts.mTypes[kChannelROrRGB] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_LINEAR;
+ atts.mTypes[kChannelG] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
+ atts.mTypes[kChannelB] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
+ float slopeIntercept[2];
+ slopeIntercept[kComponentTransferSlopeIndex] = value;
+ slopeIntercept[kComponentTransferInterceptIndex] = intercept;
+ atts.mValues[kChannelROrRGB].AppendElements(slopeIntercept, 2);
+
+ atts.mTypes[kChannelA] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY;
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForContrast(
+ FilterPrimitiveDescription& aDescr) {
+ float value = mFilter.AsContrast();
+ float intercept = -(0.5 * value) + 0.5;
+ ComponentTransferAttributes atts;
+
+ // Set transfer functions for RGB.
+ atts.mTypes[kChannelROrRGB] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_LINEAR;
+ atts.mTypes[kChannelG] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
+ atts.mTypes[kChannelB] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
+ float slopeIntercept[2];
+ slopeIntercept[kComponentTransferSlopeIndex] = value;
+ slopeIntercept[kComponentTransferInterceptIndex] = intercept;
+ atts.mValues[kChannelROrRGB].AppendElements(slopeIntercept, 2);
+
+ atts.mTypes[kChannelA] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY;
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForDropShadow(
+ FilterPrimitiveDescription& aDescr) {
+ const auto& shadow = mFilter.AsDropShadow();
+
+ DropShadowAttributes atts;
+
+ // Set drop shadow blur radius.
+ Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow.blur.ToAppUnits());
+ atts.mStdDeviation = radiusInFilterSpace;
+
+ // Set offset.
+ IntPoint offsetInFilterSpace = OffsetToFilterSpace(
+ shadow.horizontal.ToAppUnits(), shadow.vertical.ToAppUnits());
+ atts.mOffset = offsetInFilterSpace;
+
+ // Set color. If unspecified, use the CSS color property.
+ nscolor shadowColor = shadow.color.CalcColor(mShadowFallbackColor);
+ atts.mColor = ToAttributeColor(shadowColor);
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForGrayscale(
+ FilterPrimitiveDescription& aDescr) {
+ ColorMatrixAttributes atts;
+ // Set color matrix type.
+ atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_SATURATE;
+
+ // Set color matrix values.
+ float value = 1 - ClampFactor(mFilter.AsGrayscale());
+ atts.mValues.AppendElements(&value, 1);
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForHueRotate(
+ FilterPrimitiveDescription& aDescr) {
+ ColorMatrixAttributes atts;
+ // Set color matrix type.
+ atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_HUE_ROTATE;
+
+ // Set color matrix values.
+ float value = mFilter.AsHueRotate().ToDegrees();
+ atts.mValues.AppendElements(&value, 1);
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForInvert(
+ FilterPrimitiveDescription& aDescr) {
+ ComponentTransferAttributes atts;
+ float value = ClampFactor(mFilter.AsInvert());
+
+ // Set transfer functions for RGB.
+ float invertTableValues[2];
+ invertTableValues[0] = value;
+ invertTableValues[1] = 1 - value;
+
+ // Set transfer functions for RGB.
+ atts.mTypes[kChannelROrRGB] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_TABLE;
+ atts.mTypes[kChannelG] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
+ atts.mTypes[kChannelB] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
+ atts.mValues[kChannelROrRGB].AppendElements(invertTableValues, 2);
+
+ atts.mTypes[kChannelA] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY;
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForOpacity(
+ FilterPrimitiveDescription& aDescr) {
+ OpacityAttributes atts;
+ float value = ClampFactor(mFilter.AsOpacity());
+
+ atts.mOpacity = value;
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForSaturate(
+ FilterPrimitiveDescription& aDescr) {
+ ColorMatrixAttributes atts;
+ // Set color matrix type.
+ atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_SATURATE;
+
+ // Set color matrix values.
+ float value = mFilter.AsSaturate();
+ atts.mValues.AppendElements(&value, 1);
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+nsresult CSSFilterInstance::SetAttributesForSepia(
+ FilterPrimitiveDescription& aDescr) {
+ ColorMatrixAttributes atts;
+ // Set color matrix type.
+ atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_SEPIA;
+
+ // Set color matrix values.
+ float value = ClampFactor(mFilter.AsSepia());
+ atts.mValues.AppendElements(&value, 1);
+
+ aDescr.Attributes() = AsVariant(std::move(atts));
+ return NS_OK;
+}
+
+Size CSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace) {
+ float radiusInFrameSpaceInCSSPx =
+ nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace);
+
+ // Convert the radius to filter space.
+ Size radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
+ radiusInFrameSpaceInCSSPx);
+ // Narrow the scale factors. They will only be used with types containing
+ // floating point types.
+ auto frameSpaceInCSSPxToFilterSpaceScale =
+ mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors()
+ .ConvertTo<float>();
+ radiusInFilterSpace =
+ radiusInFilterSpace * frameSpaceInCSSPxToFilterSpaceScale;
+
+ // Check the radius limits.
+ if (radiusInFilterSpace.width < 0 || radiusInFilterSpace.height < 0) {
+ MOZ_ASSERT_UNREACHABLE(
+ "we shouldn't have parsed a negative radius in the "
+ "style");
+ return Size();
+ }
+
+ Float maxStdDeviation = (Float)kMaxStdDeviation;
+ radiusInFilterSpace.width =
+ std::min(radiusInFilterSpace.width, maxStdDeviation);
+ radiusInFilterSpace.height =
+ std::min(radiusInFilterSpace.height, maxStdDeviation);
+
+ return radiusInFilterSpace;
+}
+
+IntPoint CSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
+ nscoord aYOffsetInFrameSpace) {
+ gfxPoint offsetInFilterSpace(
+ nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace),
+ nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace));
+
+ // Convert the radius to filter space.
+ auto frameSpaceInCSSPxToFilterSpaceScale =
+ mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors();
+ offsetInFilterSpace.x *= frameSpaceInCSSPxToFilterSpaceScale.xScale;
+ offsetInFilterSpace.y *= frameSpaceInCSSPxToFilterSpaceScale.yScale;
+
+ return IntPoint(int32_t(offsetInFilterSpace.x),
+ int32_t(offsetInFilterSpace.y));
+}
+
+sRGBColor CSSFilterInstance::ToAttributeColor(nscolor aColor) {
+ return sRGBColor(NS_GET_R(aColor) / 255.0, NS_GET_G(aColor) / 255.0,
+ NS_GET_B(aColor) / 255.0, NS_GET_A(aColor) / 255.0);
+}
+
+int32_t CSSFilterInstance::GetLastResultIndex(
+ const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs) {
+ uint32_t numPrimitiveDescrs = aPrimitiveDescrs.Length();
+ return !numPrimitiveDescrs
+ ? FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic
+ : numPrimitiveDescrs - 1;
+}
+
+void CSSFilterInstance::SetBounds(
+ FilterPrimitiveDescription& aDescr,
+ const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs) {
+ int32_t inputIndex = GetLastResultIndex(aPrimitiveDescrs);
+ nsIntRect inputBounds =
+ (inputIndex < 0) ? mTargetBoundsInFilterSpace
+ : aPrimitiveDescrs[inputIndex].PrimitiveSubregion();
+
+ AutoTArray<nsIntRegion, 8> inputExtents;
+ inputExtents.AppendElement(inputBounds);
+
+ nsIntRegion outputExtents =
+ FilterSupport::PostFilterExtentsForPrimitive(aDescr, inputExtents);
+ IntRect outputBounds = outputExtents.GetBounds();
+
+ aDescr.SetPrimitiveSubregion(outputBounds);
+ aDescr.SetFilterSpaceBounds(outputBounds);
+}
+
+} // namespace mozilla