tor-browser

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

SVGMarkerFrame.cpp (8658B)


      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 "SVGMarkerFrame.h"
      9 
     10 // Keep others in (case-insensitive) order:
     11 #include "gfxContext.h"
     12 #include "mozilla/PresShell.h"
     13 #include "mozilla/SVGContextPaint.h"
     14 #include "mozilla/SVGGeometryFrame.h"
     15 #include "mozilla/SVGObserverUtils.h"
     16 #include "mozilla/SVGUtils.h"
     17 #include "mozilla/dom/SVGGeometryElement.h"
     18 #include "mozilla/dom/SVGMarkerElement.h"
     19 
     20 using namespace mozilla::dom;
     21 using namespace mozilla::gfx;
     22 using namespace mozilla::image;
     23 
     24 nsContainerFrame* NS_NewSVGMarkerFrame(mozilla::PresShell* aPresShell,
     25                                       mozilla::ComputedStyle* aStyle) {
     26  return new (aPresShell)
     27      mozilla::SVGMarkerFrame(aStyle, aPresShell->GetPresContext());
     28 }
     29 
     30 namespace mozilla {
     31 
     32 NS_IMPL_FRAMEARENA_HELPERS(SVGMarkerFrame)
     33 
     34 //----------------------------------------------------------------------
     35 // nsIFrame methods:
     36 
     37 nsresult SVGMarkerFrame::AttributeChanged(int32_t aNameSpaceID,
     38                                          nsAtom* aAttribute,
     39                                          AttrModType aModType) {
     40  if (aNameSpaceID == kNameSpaceID_None &&
     41      (aAttribute == nsGkAtoms::markerUnits || aAttribute == nsGkAtoms::refX ||
     42       aAttribute == nsGkAtoms::refY || aAttribute == nsGkAtoms::markerWidth ||
     43       aAttribute == nsGkAtoms::markerHeight ||
     44       aAttribute == nsGkAtoms::orient ||
     45       aAttribute == nsGkAtoms::preserveAspectRatio ||
     46       aAttribute == nsGkAtoms::viewBox)) {
     47    SVGObserverUtils::InvalidateRenderingObservers(this);
     48  }
     49 
     50  return SVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
     51                                             aModType);
     52 }
     53 
     54 #ifdef DEBUG
     55 void SVGMarkerFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
     56                          nsIFrame* aPrevInFlow) {
     57  NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::marker),
     58               "Content is not an SVG marker");
     59 
     60  SVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
     61 }
     62 #endif /* DEBUG */
     63 
     64 //----------------------------------------------------------------------
     65 // SVGContainerFrame methods:
     66 
     67 gfxMatrix SVGMarkerFrame::GetCanvasTM() {
     68  NS_ASSERTION(mMarkedFrame, "null SVGGeometry frame");
     69 
     70  if (mInUse2) {
     71    // We're going to be bailing drawing the marker, so return an identity.
     72    return gfxMatrix();
     73  }
     74 
     75  SVGMarkerElement* content = static_cast<SVGMarkerElement*>(GetContent());
     76 
     77  mInUse2 = true;
     78  gfxMatrix markedTM = mMarkedFrame->GetCanvasTM();
     79  mInUse2 = false;
     80 
     81  Matrix viewBoxTM = content->GetViewBoxTransform();
     82 
     83  return ThebesMatrix(viewBoxTM * mMarkerTM) * markedTM;
     84 }
     85 
     86 static nsIFrame* GetAnonymousChildFrame(nsIFrame* aFrame) {
     87  nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
     88  MOZ_ASSERT(kid && kid->IsSVGMarkerAnonChildFrame(),
     89             "expected to find anonymous child of marker frame");
     90  return kid;
     91 }
     92 
     93 void SVGMarkerFrame::PaintMark(gfxContext& aContext,
     94                               const gfxMatrix& aToMarkedFrameUserSpace,
     95                               SVGGeometryFrame* aMarkedFrame,
     96                               const SVGMark& aMark, float aStrokeWidth,
     97                               imgDrawingParams& aImgParams) {
     98  // If the flag is set when we get here, it means this marker frame
     99  // has already been used painting the current mark, and the document
    100  // has a marker reference loop.
    101  if (mInUse) {
    102    return;
    103  }
    104 
    105  AutoMarkerReferencer markerRef(this, aMarkedFrame);
    106 
    107  SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(GetContent());
    108  if (!marker->HasValidDimensions()) {
    109    return;
    110  }
    111 
    112  const SVGViewBox viewBox = marker->GetViewBox();
    113 
    114  if (!viewBox.IsValid()) {
    115    // We must disable rendering if the viewBox width or height are zero.
    116    return;
    117  }
    118 
    119  Matrix viewBoxTM = marker->GetViewBoxTransform();
    120 
    121  mMarkerTM = marker->GetMarkerTransform(aStrokeWidth, aMark);
    122 
    123  gfxMatrix markTM = ThebesMatrix(viewBoxTM) * ThebesMatrix(mMarkerTM) *
    124                     aToMarkedFrameUserSpace;
    125 
    126  gfxClipAutoSaveRestore autoSaveClip(&aContext);
    127  if (StyleDisplay()->IsScrollableOverflow()) {
    128    gfxRect clipRect = SVGUtils::GetClipRectForFrame(
    129        this, viewBox.x, viewBox.y, viewBox.width, viewBox.height);
    130    autoSaveClip.TransformedClip(markTM, clipRect);
    131  }
    132 
    133  nsIFrame* kid = GetAnonymousChildFrame(this);
    134  ISVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
    135  // The CTM of each frame referencing us may be different.
    136  SVGFrame->NotifySVGChanged(
    137      ISVGDisplayableFrame::ChangeFlag::TransformChanged);
    138  auto contextPaint = MakeRefPtr<SVGContextPaintImpl>();
    139  contextPaint->Init(aContext.GetDrawTarget(),
    140                     aToMarkedFrameUserSpace * aContext.CurrentMatrixDouble(),
    141                     aMarkedFrame, SVGContextPaint::GetContextPaint(marker),
    142                     aImgParams);
    143  AutoSetRestoreSVGContextPaint autoSetRestore(contextPaint,
    144                                               marker->OwnerDoc());
    145  SVGUtils::PaintFrameWithEffects(kid, aContext, markTM, aImgParams);
    146 }
    147 
    148 SVGBBox SVGMarkerFrame::GetMarkBBoxContribution(const Matrix& aToBBoxUserspace,
    149                                                uint32_t aFlags,
    150                                                SVGGeometryFrame* aMarkedFrame,
    151                                                const SVGMark& aMark,
    152                                                float aStrokeWidth) {
    153  SVGBBox bbox;
    154 
    155  // If the flag is set when we get here, it means this marker frame
    156  // has already been used in calculating the current mark bbox, and
    157  // the document has a marker reference loop.
    158  if (mInUse) {
    159    return bbox;
    160  }
    161 
    162  AutoMarkerReferencer markerRef(this, aMarkedFrame);
    163 
    164  SVGMarkerElement* content = static_cast<SVGMarkerElement*>(GetContent());
    165  if (!content->HasValidDimensions()) {
    166    return bbox;
    167  }
    168 
    169  const SVGViewBox viewBox = content->GetViewBox();
    170 
    171  if (!viewBox.IsValid()) {
    172    return bbox;
    173  }
    174 
    175  mMarkerTM = content->GetMarkerTransform(aStrokeWidth, aMark);
    176  Matrix viewBoxTM = content->GetViewBoxTransform();
    177 
    178  Matrix tm = viewBoxTM * mMarkerTM * aToBBoxUserspace;
    179 
    180  ISVGDisplayableFrame* child = do_QueryFrame(GetAnonymousChildFrame(this));
    181  // When we're being called to obtain the invalidation area, we need to
    182  // pass down all the flags so that stroke is included. However, once DOM
    183  // getBBox() accepts flags, maybe we should strip some of those here?
    184 
    185  // We need to include zero width/height vertical/horizontal lines, so we have
    186  // to use UnionEdges.
    187  bbox.UnionEdges(child->GetBBoxContribution(tm, aFlags));
    188 
    189  return bbox;
    190 }
    191 
    192 void SVGMarkerFrame::SetParentCoordCtxProvider(SVGViewportElement* aContext) {
    193  SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(GetContent());
    194  marker->SetParentCoordCtxProvider(aContext);
    195 }
    196 
    197 void SVGMarkerFrame::AppendDirectlyOwnedAnonBoxes(
    198    nsTArray<OwnedAnonBox>& aResult) {
    199  aResult.AppendElement(OwnedAnonBox(GetAnonymousChildFrame(this)));
    200 }
    201 
    202 //----------------------------------------------------------------------
    203 // helper class
    204 
    205 SVGMarkerFrame::AutoMarkerReferencer::AutoMarkerReferencer(
    206    SVGMarkerFrame* aFrame, SVGGeometryFrame* aMarkedFrame)
    207    : mFrame(aFrame) {
    208  mFrame->mInUse = true;
    209  mFrame->mMarkedFrame = aMarkedFrame;
    210 
    211  SVGViewportElement* ctx =
    212      static_cast<SVGElement*>(aMarkedFrame->GetContent())->GetCtx();
    213  mFrame->SetParentCoordCtxProvider(ctx);
    214 }
    215 
    216 SVGMarkerFrame::AutoMarkerReferencer::~AutoMarkerReferencer() {
    217  mFrame->SetParentCoordCtxProvider(nullptr);
    218 
    219  mFrame->mMarkedFrame = nullptr;
    220  mFrame->mInUse = false;
    221 }
    222 
    223 }  // namespace mozilla
    224 
    225 //----------------------------------------------------------------------
    226 // Implementation of SVGMarkerAnonChildFrame
    227 
    228 nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(
    229    mozilla::PresShell* aPresShell, mozilla::ComputedStyle* aStyle) {
    230  return new (aPresShell)
    231      mozilla::SVGMarkerAnonChildFrame(aStyle, aPresShell->GetPresContext());
    232 }
    233 
    234 namespace mozilla {
    235 
    236 NS_IMPL_FRAMEARENA_HELPERS(SVGMarkerAnonChildFrame)
    237 
    238 #ifdef DEBUG
    239 void SVGMarkerAnonChildFrame::Init(nsIContent* aContent,
    240                                   nsContainerFrame* aParent,
    241                                   nsIFrame* aPrevInFlow) {
    242  MOZ_ASSERT(aParent->IsSVGMarkerFrame(), "Unexpected parent");
    243  SVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
    244 }
    245 #endif
    246 
    247 }  // namespace mozilla