tor-browser

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

SVGMaskFrame.cpp (6614B)


      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 "SVGMaskFrame.h"
      9 
     10 // Keep others in (case-insensitive) order:
     11 #include "AutoReferenceChainGuard.h"
     12 #include "gfx2DGlue.h"
     13 #include "gfxContext.h"
     14 #include "mozilla/PresShell.h"
     15 #include "mozilla/RefPtr.h"
     16 #include "mozilla/SVGObserverUtils.h"
     17 #include "mozilla/SVGUtils.h"
     18 #include "mozilla/dom/SVGMaskElement.h"
     19 #include "mozilla/dom/SVGUnitTypesBinding.h"
     20 #include "mozilla/gfx/2D.h"
     21 
     22 using namespace mozilla::dom;
     23 using namespace mozilla::dom::SVGUnitTypes_Binding;
     24 using namespace mozilla::gfx;
     25 using namespace mozilla::image;
     26 
     27 nsIFrame* NS_NewSVGMaskFrame(mozilla::PresShell* aPresShell,
     28                             mozilla::ComputedStyle* aStyle) {
     29  return new (aPresShell)
     30      mozilla::SVGMaskFrame(aStyle, aPresShell->GetPresContext());
     31 }
     32 
     33 namespace mozilla {
     34 
     35 NS_IMPL_FRAMEARENA_HELPERS(SVGMaskFrame)
     36 
     37 already_AddRefed<SourceSurface> SVGMaskFrame::GetMaskForMaskedFrame(
     38    MaskParams& aParams) {
     39  // Make sure we break reference loops and over long reference chains:
     40  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     41  AutoReferenceChainGuard refChainGuard(this, &mInUse, &sRefChainLengthCounter);
     42  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     43    // Break reference chain
     44    return nullptr;
     45  }
     46 
     47  gfxRect maskArea = GetMaskArea(aParams.maskedFrame);
     48  if (maskArea.IsEmpty()) {
     49    return nullptr;
     50  }
     51  // Get the clip extents in device space:
     52  // Minimizing the mask surface extents (using both the current clip extents
     53  // and maskArea) is important for performance.
     54  //
     55  gfxRect maskSurfaceRectDouble = aParams.toUserSpace.TransformBounds(maskArea);
     56  Rect maskSurfaceRect = ToRect(maskSurfaceRectDouble);
     57  maskSurfaceRect.RoundOut();
     58 
     59  StyleMaskType maskType;
     60  if (aParams.maskMode == StyleMaskMode::MatchSource) {
     61    maskType = StyleSVGReset()->mMaskType;
     62  } else {
     63    maskType = aParams.maskMode == StyleMaskMode::Luminance
     64                   ? StyleMaskType::Luminance
     65                   : StyleMaskType::Alpha;
     66  }
     67 
     68  RefPtr<DrawTarget> maskDT;
     69  if (maskType == StyleMaskType::Luminance) {
     70    maskDT = aParams.dt->CreateClippedDrawTarget(maskSurfaceRect,
     71                                                 SurfaceFormat::B8G8R8A8);
     72  } else {
     73    maskDT =
     74        aParams.dt->CreateClippedDrawTarget(maskSurfaceRect, SurfaceFormat::A8);
     75  }
     76 
     77  if (!maskDT || !maskDT->IsValid()) {
     78    return nullptr;
     79  }
     80 
     81  gfxContext tmpCtx(maskDT, /* aPreserveTransform */ true);
     82 
     83  mMatrixForChildren =
     84      GetMaskTransform(aParams.maskedFrame) * aParams.toUserSpace;
     85 
     86  for (auto* kid : mFrames) {
     87    gfxMatrix m = mMatrixForChildren;
     88 
     89    // The CTM of each frame referencing us can be different
     90    ISVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
     91    if (SVGFrame) {
     92      SVGFrame->NotifySVGChanged(
     93          ISVGDisplayableFrame::ChangeFlag::TransformChanged);
     94      m = SVGUtils::GetTransformMatrixInUserSpace(kid) * m;
     95    }
     96 
     97    SVGUtils::PaintFrameWithEffects(kid, tmpCtx, m, aParams.imgParams);
     98  }
     99 
    100  RefPtr<SourceSurface> surface;
    101  if (maskType == StyleMaskType::Luminance) {
    102    auto luminanceType = LuminanceType::LUMINANCE;
    103    if (StyleSVG()->mColorInterpolation == StyleColorInterpolation::Linearrgb) {
    104      luminanceType = LuminanceType::LINEARRGB;
    105    }
    106 
    107    RefPtr<SourceSurface> maskSnapshot =
    108        maskDT->IntoLuminanceSource(luminanceType, aParams.opacity);
    109    if (!maskSnapshot) {
    110      return nullptr;
    111    }
    112    surface = std::move(maskSnapshot);
    113  } else {
    114    maskDT->FillRect(maskSurfaceRect,
    115                     ColorPattern(DeviceColor::MaskWhite(aParams.opacity)),
    116                     DrawOptions(1, CompositionOp::OP_IN));
    117    RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
    118    if (!maskSnapshot) {
    119      return nullptr;
    120    }
    121    surface = std::move(maskSnapshot);
    122  }
    123 
    124  return surface.forget();
    125 }
    126 
    127 gfxRect SVGMaskFrame::GetMaskArea(nsIFrame* aMaskedFrame) {
    128  SVGMaskElement* maskElem = static_cast<SVGMaskElement*>(GetContent());
    129 
    130  uint16_t units =
    131      maskElem->mEnumAttributes[SVGMaskElement::MASKUNITS].GetAnimValue();
    132  gfxRect bbox;
    133  if (units == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    134    bbox =
    135        SVGUtils::GetBBox(aMaskedFrame, SVGUtils::eUseFrameBoundsForOuterSVG |
    136                                            SVGUtils::eBBoxIncludeFillGeometry);
    137  }
    138 
    139  // Bounds in the user space of aMaskedFrame
    140  gfxRect maskArea = SVGUtils::GetRelativeRect(
    141      units, &maskElem->mLengthAttributes[SVGMaskElement::ATTR_X], bbox,
    142      aMaskedFrame);
    143 
    144  return maskArea;
    145 }
    146 
    147 nsresult SVGMaskFrame::AttributeChanged(int32_t aNameSpaceID,
    148                                        nsAtom* aAttribute,
    149                                        AttrModType aModType) {
    150  if (aNameSpaceID == kNameSpaceID_None &&
    151      (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y ||
    152       aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height ||
    153       aAttribute == nsGkAtoms::maskUnits ||
    154       aAttribute == nsGkAtoms::maskContentUnits)) {
    155    SVGObserverUtils::InvalidateRenderingObservers(this);
    156  }
    157 
    158  return SVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
    159                                             aModType);
    160 }
    161 
    162 #ifdef DEBUG
    163 void SVGMaskFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
    164                        nsIFrame* aPrevInFlow) {
    165  NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::mask),
    166               "Content is not an SVG mask");
    167 
    168  SVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
    169 }
    170 #endif /* DEBUG */
    171 
    172 gfxMatrix SVGMaskFrame::GetCanvasTM() { return mMatrixForChildren; }
    173 
    174 gfxMatrix SVGMaskFrame::GetMaskTransform(nsIFrame* aMaskedFrame) {
    175  SVGMaskElement* content = static_cast<SVGMaskElement*>(GetContent());
    176 
    177  SVGAnimatedEnumeration* maskContentUnits =
    178      &content->mEnumAttributes[SVGMaskElement::MASKCONTENTUNITS];
    179 
    180  uint32_t flags = SVGUtils::eBBoxIncludeFillGeometry |
    181                   (aMaskedFrame->StyleBorder()->mBoxDecorationBreak ==
    182                            StyleBoxDecorationBreak::Clone
    183                        ? SVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
    184                        : 0);
    185 
    186  return SVGUtils::AdjustMatrixForUnits(gfxMatrix(), maskContentUnits,
    187                                        aMaskedFrame, flags);
    188 }
    189 
    190 }  // namespace mozilla