tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CSSFilterInstance.cpp (11845B)


      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/. */
      6 
      7 // Main header first:
      8 #include "CSSFilterInstance.h"
      9 
     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"
     17 
     18 using namespace mozilla::gfx;
     19 
     20 namespace mozilla {
     21 
     22 static float ClampFactor(float aFactor) {
     23  if (aFactor > 1) {
     24    return 1;
     25  }
     26  if (aFactor < 0) {
     27    MOZ_ASSERT_UNREACHABLE("A negative value should not have been parsed.");
     28    return 0;
     29  }
     30 
     31  return aFactor;
     32 }
     33 
     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) {}
     43 
     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;
     84  }
     85 
     86  if (NS_FAILED(result)) {
     87    return result;
     88  }
     89 
     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);
     93 
     94  // Add this primitive to the filter chain.
     95  aPrimitiveDescrs.AppendElement(std::move(descr));
     96  return NS_OK;
     97 }
     98 
     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;
    110 }
    111 
    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;
    121 }
    122 
    123 nsresult CSSFilterInstance::SetAttributesForBrightness(
    124    FilterPrimitiveDescription& aDescr) {
    125  float value = mFilter.AsBrightness();
    126  float intercept = 0.0f;
    127  ComponentTransferAttributes atts;
    128 
    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  std::array<float, 2> slopeIntercept;
    134  slopeIntercept[kComponentTransferSlopeIndex] = value;
    135  slopeIntercept[kComponentTransferInterceptIndex] = intercept;
    136  atts.mValues[kChannelROrRGB].AppendElements(Span(slopeIntercept));
    137 
    138  atts.mTypes[kChannelA] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY;
    139 
    140  aDescr.Attributes() = AsVariant(std::move(atts));
    141  return NS_OK;
    142 }
    143 
    144 nsresult CSSFilterInstance::SetAttributesForContrast(
    145    FilterPrimitiveDescription& aDescr) {
    146  float value = mFilter.AsContrast();
    147  float intercept = -(0.5 * value) + 0.5;
    148  ComponentTransferAttributes atts;
    149 
    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  std::array<float, 2> slopeIntercept;
    155  slopeIntercept[kComponentTransferSlopeIndex] = value;
    156  slopeIntercept[kComponentTransferInterceptIndex] = intercept;
    157  atts.mValues[kChannelROrRGB].AppendElements(Span(slopeIntercept));
    158 
    159  atts.mTypes[kChannelA] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY;
    160 
    161  aDescr.Attributes() = AsVariant(std::move(atts));
    162  return NS_OK;
    163 }
    164 
    165 nsresult CSSFilterInstance::SetAttributesForDropShadow(
    166    FilterPrimitiveDescription& aDescr) {
    167  const auto& shadow = mFilter.AsDropShadow();
    168 
    169  DropShadowAttributes atts;
    170 
    171  // Set drop shadow blur radius.
    172  Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow.blur.ToAppUnits());
    173  atts.mStdDeviation = radiusInFilterSpace;
    174 
    175  // Set offset.
    176  IntPoint offsetInFilterSpace = OffsetToFilterSpace(
    177      shadow.horizontal.ToAppUnits(), shadow.vertical.ToAppUnits());
    178  atts.mOffset = offsetInFilterSpace;
    179 
    180  // Set color. If unspecified, use the CSS color property.
    181  nscolor shadowColor = shadow.color.CalcColor(mShadowFallbackColor);
    182  atts.mColor = sRGBColor::FromABGR(shadowColor);
    183 
    184  aDescr.Attributes() = AsVariant(std::move(atts));
    185  return NS_OK;
    186 }
    187 
    188 nsresult CSSFilterInstance::SetAttributesForGrayscale(
    189    FilterPrimitiveDescription& aDescr) {
    190  ColorMatrixAttributes atts;
    191  // Set color matrix type.
    192  atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_SATURATE;
    193 
    194  // Set color matrix value.
    195  atts.mValues.AppendElement(1 - ClampFactor(mFilter.AsGrayscale()));
    196 
    197  aDescr.Attributes() = AsVariant(std::move(atts));
    198  return NS_OK;
    199 }
    200 
    201 nsresult CSSFilterInstance::SetAttributesForHueRotate(
    202    FilterPrimitiveDescription& aDescr) {
    203  ColorMatrixAttributes atts;
    204  // Set color matrix type.
    205  atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_HUE_ROTATE;
    206 
    207  // Set color matrix value.
    208  atts.mValues.AppendElement(mFilter.AsHueRotate().ToDegrees());
    209 
    210  aDescr.Attributes() = AsVariant(std::move(atts));
    211  return NS_OK;
    212 }
    213 
    214 nsresult CSSFilterInstance::SetAttributesForInvert(
    215    FilterPrimitiveDescription& aDescr) {
    216  ComponentTransferAttributes atts;
    217  float value = ClampFactor(mFilter.AsInvert());
    218 
    219  // Set transfer functions for RGB.
    220  std::array<float, 2> invertTableValues = {value, 1 - value};
    221 
    222  // Set transfer functions for RGB.
    223  atts.mTypes[kChannelROrRGB] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_TABLE;
    224  atts.mTypes[kChannelG] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
    225  atts.mTypes[kChannelB] = (uint8_t)SVG_FECOMPONENTTRANSFER_SAME_AS_R;
    226  atts.mValues[kChannelROrRGB].AppendElements(Span(invertTableValues));
    227 
    228  atts.mTypes[kChannelA] = (uint8_t)SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY;
    229 
    230  aDescr.Attributes() = AsVariant(std::move(atts));
    231  return NS_OK;
    232 }
    233 
    234 nsresult CSSFilterInstance::SetAttributesForOpacity(
    235    FilterPrimitiveDescription& aDescr) {
    236  OpacityAttributes atts;
    237  float value = ClampFactor(mFilter.AsOpacity());
    238 
    239  atts.mOpacity = value;
    240  aDescr.Attributes() = AsVariant(std::move(atts));
    241  return NS_OK;
    242 }
    243 
    244 nsresult CSSFilterInstance::SetAttributesForSaturate(
    245    FilterPrimitiveDescription& aDescr) {
    246  ColorMatrixAttributes atts;
    247  // Set color matrix type.
    248  atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_SATURATE;
    249 
    250  // Set color matrix value.
    251  atts.mValues.AppendElement(mFilter.AsSaturate());
    252 
    253  aDescr.Attributes() = AsVariant(std::move(atts));
    254  return NS_OK;
    255 }
    256 
    257 nsresult CSSFilterInstance::SetAttributesForSepia(
    258    FilterPrimitiveDescription& aDescr) {
    259  ColorMatrixAttributes atts;
    260  // Set color matrix type.
    261  atts.mType = (uint32_t)SVG_FECOLORMATRIX_TYPE_SEPIA;
    262 
    263  // Set color matrix value.
    264  atts.mValues.AppendElement(ClampFactor(mFilter.AsSepia()));
    265 
    266  aDescr.Attributes() = AsVariant(std::move(atts));
    267  return NS_OK;
    268 }
    269 
    270 Size CSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace) {
    271  float radiusInFrameSpaceInCSSPx =
    272      nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace);
    273 
    274  // Convert the radius to filter space.
    275  Size radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
    276                           radiusInFrameSpaceInCSSPx);
    277  // Narrow the scale factors. They will only be used with types containing
    278  // floating point types.
    279  auto frameSpaceInCSSPxToFilterSpaceScale =
    280      mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors()
    281          .ConvertTo<float>();
    282  radiusInFilterSpace =
    283      radiusInFilterSpace * frameSpaceInCSSPxToFilterSpaceScale;
    284 
    285  // Check the radius limits.
    286  if (radiusInFilterSpace.width < 0 || radiusInFilterSpace.height < 0) {
    287    MOZ_ASSERT_UNREACHABLE(
    288        "we shouldn't have parsed a negative radius in the "
    289        "style");
    290    return Size();
    291  }
    292 
    293  Float maxStdDeviation = (Float)kMaxStdDeviation;
    294  radiusInFilterSpace.width =
    295      std::min(radiusInFilterSpace.width, maxStdDeviation);
    296  radiusInFilterSpace.height =
    297      std::min(radiusInFilterSpace.height, maxStdDeviation);
    298 
    299  return radiusInFilterSpace;
    300 }
    301 
    302 IntPoint CSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
    303                                                nscoord aYOffsetInFrameSpace) {
    304  gfxPoint offsetInFilterSpace(
    305      nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace),
    306      nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace));
    307 
    308  // Convert the radius to filter space.
    309  auto frameSpaceInCSSPxToFilterSpaceScale =
    310      mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors();
    311  offsetInFilterSpace.x *= frameSpaceInCSSPxToFilterSpaceScale.xScale;
    312  offsetInFilterSpace.y *= frameSpaceInCSSPxToFilterSpaceScale.yScale;
    313 
    314  return IntPoint(int32_t(offsetInFilterSpace.x),
    315                  int32_t(offsetInFilterSpace.y));
    316 }
    317 
    318 int32_t CSSFilterInstance::GetLastResultIndex(
    319    const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs) {
    320  uint32_t numPrimitiveDescrs = aPrimitiveDescrs.Length();
    321  return !numPrimitiveDescrs
    322             ? FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic
    323             : numPrimitiveDescrs - 1;
    324 }
    325 
    326 void CSSFilterInstance::SetBounds(
    327    FilterPrimitiveDescription& aDescr,
    328    const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs) {
    329  int32_t inputIndex = GetLastResultIndex(aPrimitiveDescrs);
    330  nsIntRect inputBounds =
    331      (inputIndex < 0) ? mTargetBoundsInFilterSpace
    332                       : aPrimitiveDescrs[inputIndex].PrimitiveSubregion();
    333 
    334  AutoTArray<nsIntRegion, 8> inputExtents;
    335  inputExtents.AppendElement(inputBounds);
    336 
    337  nsIntRegion outputExtents =
    338      FilterSupport::PostFilterExtentsForPrimitive(aDescr, inputExtents);
    339  IntRect outputBounds = outputExtents.GetBounds();
    340 
    341  aDescr.SetPrimitiveSubregion(outputBounds);
    342  aDescr.SetFilterSpaceBounds(outputBounds);
    343 }
    344 
    345 }  // namespace mozilla