summaryrefslogtreecommitdiffstats
path: root/layout/svg/SVGClipPathFrame.h
blob: 771feb898e2d025ac5907a324425dcc2c64edb95 (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
166
167
168
169
170
171
172
173
174
175
176
177
/* -*- 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_SVGCLIPPATHFRAME_H_
#define LAYOUT_SVG_SVGCLIPPATHFRAME_H_

#include "gfxMatrix.h"
#include "mozilla/Attributes.h"
#include "mozilla/SVGContainerFrame.h"

class gfxContext;

namespace mozilla {
class ISVGDisplayableFrame;
class PresShell;
}  // namespace mozilla

nsIFrame* NS_NewSVGClipPathFrame(mozilla::PresShell* aPresShell,
                                 mozilla::ComputedStyle* aStyle);

namespace mozilla {

class SVGClipPathFrame final : public SVGContainerFrame {
  friend nsIFrame* ::NS_NewSVGClipPathFrame(mozilla::PresShell* aPresShell,
                                            ComputedStyle* aStyle);

  using Matrix = gfx::Matrix;
  using SourceSurface = gfx::SourceSurface;
  using imgDrawingParams = image::imgDrawingParams;

 protected:
  explicit SVGClipPathFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
      : SVGContainerFrame(aStyle, aPresContext, kClassID),
        mIsBeingProcessed(false) {
    AddStateBits(NS_FRAME_IS_NONDISPLAY | NS_STATE_SVG_CLIPPATH_CHILD |
                 NS_FRAME_MAY_BE_TRANSFORMED |
                 NS_STATE_SVG_RENDERING_OBSERVER_CONTAINER);
  }

 public:
  NS_DECL_FRAMEARENA_HELPERS(SVGClipPathFrame)

  // nsIFrame methods:
  void BuildDisplayList(nsDisplayListBuilder* aBuilder,
                        const nsDisplayListSet& aLists) override {}

  bool IsSVGTransformed(Matrix* aOwnTransforms,
                        Matrix* aFromParentTransforms) const override;

  // SVGClipPathFrame methods:

  /**
   * Applies the clipPath by pushing a clip path onto the DrawTarget.
   *
   * This method must only be used if IsTrivial() returns true, otherwise use
   * GetClipMask.
   *
   * @param aContext The context that the clip path is to be applied to.
   * @param aClippedFrame The/an nsIFrame of the element that references this
   *   clipPath that is currently being processed.
   * @param aMatrix The transform from aClippedFrame's user space to aContext's
   *   current transform.
   */
  void ApplyClipPath(gfxContext& aContext, nsIFrame* aClippedFrame,
                     const gfxMatrix& aMatrix);

  /**
   * Returns an alpha mask surface containing the clipping geometry.
   *
   * This method must only be used if IsTrivial() returns false, otherwise use
   * ApplyClipPath.
   *
   * @param aReferenceContext Used to determine the backend for and size of the
   *   returned SourceSurface, the size being limited to the device space clip
   *   extents on the context.
   * @param aClippedFrame The/an nsIFrame of the element that references this
   *   clipPath that is currently being processed.
   * @param aMatrix The transform from aClippedFrame's user space to aContext's
   *   current transform.
   * @param [in, optional] aExtraMask An extra surface that the returned
   *   surface should be masked with.
   */
  already_AddRefed<SourceSurface> GetClipMask(
      gfxContext& aReferenceContext, nsIFrame* aClippedFrame,
      const gfxMatrix& aMatrix, SourceSurface* aExtraMask = nullptr);

  /**
   * Paint mask directly onto a given context(aMaskContext).
   *
   * @param aMaskContext The target of mask been painting on.
   * @param aClippedFrame The/an nsIFrame of the element that references this
   *   clipPath that is currently being processed.
   * @param aMatrix The transform from aClippedFrame's user space to
   *   current transform.
   * @param [in, optional] aExtraMask An extra surface that the returned
   *   surface should be masked with.
   */
  void PaintClipMask(gfxContext& aMaskContext, nsIFrame* aClippedFrame,
                     const gfxMatrix& aMatrix, SourceSurface* aExtraMask);

  /**
   * aPoint is expected to be in aClippedFrame's SVG user space.
   */
  bool PointIsInsideClipPath(nsIFrame* aClippedFrame, const gfxPoint& aPoint);

  // Check if this clipPath is made up of more than one geometry object.
  // If so, the clipping API in cairo isn't enough and we need to use
  // mask based clipping.
  bool IsTrivial(ISVGDisplayableFrame** aSingleChild = nullptr);

  // nsIFrame interface:
  nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
                            int32_t aModType) override;

#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"SVGClipPath"_ns, aResult);
  }
#endif

  SVGBBox GetBBoxForClipPathFrame(const SVGBBox& aBBox,
                                  const gfxMatrix& aMatrix, uint32_t aFlags);

  /**
   * If the clipPath element transforms its children due to
   * clipPathUnits="objectBoundingBox" being set on it and/or due to the
   * 'transform' attribute being set on it, this function returns the resulting
   * transform.
   */
  gfxMatrix GetClipPathTransform(nsIFrame* aClippedFrame);

 private:
  // SVGContainerFrame methods:
  gfxMatrix GetCanvasTM() override;

  already_AddRefed<DrawTarget> CreateClipMask(gfxContext& aReferenceContext,
                                              gfx::IntPoint& aOffset);

  void PaintFrameIntoMask(nsIFrame* aFrame, nsIFrame* aClippedFrame,
                          gfxContext& aTarget);

  void PaintChildren(gfxContext& aMaskContext, nsIFrame* aClippedFrame,
                     const gfxMatrix& aMatrix);

  bool IsValid();

  // Set, during a GetClipMask() call, to the transform that still needs to be
  // concatenated to the transform of the DrawTarget that was passed to
  // GetClipMask in order to establish the coordinate space that the clipPath
  // establishes for its contents (i.e. including applying 'clipPathUnits' and
  // any 'transform' attribute set on the clipPath) specifically for clipping
  // the frame that was passed to GetClipMask at that moment in time.  This is
  // set so that if our GetCanvasTM method is called while GetClipMask is
  // painting its children, the returned matrix will include the transforms
  // that should be used when creating the mask for the frame passed to
  // GetClipMask.
  //
  // Note: The removal of GetCanvasTM is nearly complete, so our GetCanvasTM
  // may not even be called soon/any more.
  gfxMatrix mMatrixForChildren;

  // Flag used to indicate whether a methods that may reenter due to
  // following a reference to another instance is currently executing.
  bool mIsBeingProcessed;
};

}  // namespace mozilla

#endif  // LAYOUT_SVG_SVGCLIPPATHFRAME_H_