summaryrefslogtreecommitdiffstats
path: root/layout/svg/SVGMarkerFrame.h
blob: e5b6f2f561c59363ad4b92d940e2a40174cbfe5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/* -*- 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/. */

#ifndef LAYOUT_SVG_SVGMARKERFRAME_H_
#define LAYOUT_SVG_SVGMARKERFRAME_H_

#include "mozilla/Attributes.h"
#include "mozilla/SVGContainerFrame.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "nsIFrame.h"
#include "nsLiteralString.h"
#include "nsQueryFrame.h"

class gfxContext;

namespace mozilla {

class PresShell;
class SVGGeometryFrame;

struct SVGMark;

namespace dom {
class SVGViewportElement;
}  // namespace dom
}  // namespace mozilla

nsContainerFrame* NS_NewSVGMarkerFrame(mozilla::PresShell* aPresShell,
                                       mozilla::ComputedStyle* aStyle);
nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(mozilla::PresShell* aPresShell,
                                                mozilla::ComputedStyle* aStyle);

namespace mozilla {

class SVGMarkerFrame final : public SVGContainerFrame {
  using imgDrawingParams = image::imgDrawingParams;

  friend class SVGMarkerAnonChildFrame;
  friend nsContainerFrame* ::NS_NewSVGMarkerFrame(
      mozilla::PresShell* aPresShell, ComputedStyle* aStyle);

 protected:
  explicit SVGMarkerFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
      : SVGContainerFrame(aStyle, aPresContext, kClassID),
        mMarkedFrame(nullptr),
        mInUse(false),
        mInUse2(false) {
    AddStateBits(NS_FRAME_IS_NONDISPLAY |
                 NS_STATE_SVG_RENDERING_OBSERVER_CONTAINER);
  }

 public:
  NS_DECL_FRAMEARENA_HELPERS(SVGMarkerFrame)

  // nsIFrame interface:
#ifdef DEBUG
  void Init(nsIContent* aContent, nsContainerFrame* aParent,
            nsIFrame* aPrevInFlow) override;
#endif

  void BuildDisplayList(nsDisplayListBuilder* aBuilder,
                        const nsDisplayListSet& aLists) override {}

  nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
                            int32_t aModType) override;

#ifdef DEBUG_FRAME_DUMP
  nsresult GetFrameName(nsAString& aResult) const override {
    return MakeFrameName(u"SVGMarker"_ns, aResult);
  }
#endif

  nsContainerFrame* GetContentInsertionFrame() override {
    // Any children must be added to our single anonymous inner frame kid.
    MOZ_ASSERT(
        PrincipalChildList().FirstChild() &&
            PrincipalChildList().FirstChild()->IsSVGMarkerAnonChildFrame(),
        "Where is our anonymous child?");
    return PrincipalChildList().FirstChild()->GetContentInsertionFrame();
  }

  // SVGMarkerFrame methods:
  void PaintMark(gfxContext& aContext, const gfxMatrix& aToMarkedFrameUserSpace,
                 SVGGeometryFrame* aMarkedFrame, const SVGMark& aMark,
                 float aStrokeWidth, imgDrawingParams& aImgParams);

  SVGBBox GetMarkBBoxContribution(const Matrix& aToBBoxUserspace,
                                  uint32_t aFlags,
                                  SVGGeometryFrame* aMarkedFrame,
                                  const SVGMark& aMark, float aStrokeWidth);

  // Return our anonymous box child.
  void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;

 private:
  // stuff needed for callback
  SVGGeometryFrame* mMarkedFrame;
  Matrix mMarkerTM;

  // SVGContainerFrame methods:
  gfxMatrix GetCanvasTM() override;

  // A helper class to allow us to paint markers safely. The helper
  // automatically sets and clears the mInUse flag on the marker frame (to
  // prevent nasty reference loops) as well as the reference to the marked
  // frame and its coordinate context. It's easy to mess this up
  // and break things, so this helper makes the code far more robust.
  class MOZ_RAII AutoMarkerReferencer {
   public:
    AutoMarkerReferencer(SVGMarkerFrame* aFrame,
                         SVGGeometryFrame* aMarkedFrame);
    ~AutoMarkerReferencer();

   private:
    SVGMarkerFrame* mFrame;
  };

  // SVGMarkerFrame methods:
  void SetParentCoordCtxProvider(dom::SVGViewportElement* aContext);

  // recursion prevention flag
  bool mInUse;

  // second recursion prevention flag, for GetCanvasTM()
  bool mInUse2;
};

////////////////////////////////////////////////////////////////////////
// nsMarkerAnonChildFrame class

class SVGMarkerAnonChildFrame final : public SVGDisplayContainerFrame {
  friend nsContainerFrame* ::NS_NewSVGMarkerAnonChildFrame(
      mozilla::PresShell* aPresShell, ComputedStyle* aStyle);

  explicit SVGMarkerAnonChildFrame(ComputedStyle* aStyle,
                                   nsPresContext* aPresContext)
      : SVGDisplayContainerFrame(aStyle, aPresContext, kClassID) {}

 public:
  NS_DECL_FRAMEARENA_HELPERS(SVGMarkerAnonChildFrame)

#ifdef DEBUG
  void Init(nsIContent* aContent, nsContainerFrame* aParent,
            nsIFrame* aPrevInFlow) override;
#endif

#ifdef DEBUG_FRAME_DUMP
  nsresult GetFrameName(nsAString& aResult) const override {
    return MakeFrameName(u"SVGMarkerAnonChild"_ns, aResult);
  }
#endif

  // SVGContainerFrame methods:
  gfxMatrix GetCanvasTM() override {
    return static_cast<SVGMarkerFrame*>(GetParent())->GetCanvasTM();
  }
};

}  // namespace mozilla

#endif  // LAYOUT_SVG_SVGMARKERFRAME_H_