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 #ifndef LAYOUT_SVG_SVGCLIPPATHFRAME_H_
8 #define LAYOUT_SVG_SVGCLIPPATHFRAME_H_
9 
10 #include "gfxMatrix.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/SVGContainerFrame.h"
13 
14 class gfxContext;
15 
16 namespace mozilla {
17 class ISVGDisplayableFrame;
18 class PresShell;
19 }  // namespace mozilla
20 
21 nsIFrame* NS_NewSVGClipPathFrame(mozilla::PresShell* aPresShell,
22                                  mozilla::ComputedStyle* aStyle);
23 
24 namespace mozilla {
25 
26 class SVGClipPathFrame final : public SVGContainerFrame {
27   friend nsIFrame* ::NS_NewSVGClipPathFrame(mozilla::PresShell* aPresShell,
28                                             ComputedStyle* aStyle);
29 
30   using Matrix = gfx::Matrix;
31   using SourceSurface = gfx::SourceSurface;
32   using imgDrawingParams = image::imgDrawingParams;
33 
34  protected:
SVGClipPathFrame(ComputedStyle * aStyle,nsPresContext * aPresContext)35   explicit SVGClipPathFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
36       : SVGContainerFrame(aStyle, aPresContext, kClassID),
37         mIsBeingProcessed(false) {
38     AddStateBits(NS_FRAME_IS_NONDISPLAY);
39   }
40 
41  public:
NS_DECL_FRAMEARENA_HELPERS(SVGClipPathFrame)42   NS_DECL_FRAMEARENA_HELPERS(SVGClipPathFrame)
43 
44   // nsIFrame methods:
45   virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
46                                 const nsDisplayListSet& aLists) override {}
47 
48   virtual bool IsSVGTransformed(Matrix* aOwnTransforms,
49                                 Matrix* aFromParentTransforms) const override;
50 
51   // SVGClipPathFrame methods:
52 
53   /**
54    * Applies the clipPath by pushing a clip path onto the DrawTarget.
55    *
56    * This method must only be used if IsTrivial() returns true, otherwise use
57    * GetClipMask.
58    *
59    * @param aContext The context that the clip path is to be applied to.
60    * @param aClippedFrame The/an nsIFrame of the element that references this
61    *   clipPath that is currently being processed.
62    * @param aMatrix The transform from aClippedFrame's user space to aContext's
63    *   current transform.
64    */
65   void ApplyClipPath(gfxContext& aContext, nsIFrame* aClippedFrame,
66                      const gfxMatrix& aMatrix);
67 
68   /**
69    * Returns an alpha mask surface containing the clipping geometry.
70    *
71    * This method must only be used if IsTrivial() returns false, otherwise use
72    * ApplyClipPath.
73    *
74    * @param aReferenceContext Used to determine the backend for and size of the
75    *   returned SourceSurface, the size being limited to the device space clip
76    *   extents on the context.
77    * @param aClippedFrame The/an nsIFrame of the element that references this
78    *   clipPath that is currently being processed.
79    * @param aMatrix The transform from aClippedFrame's user space to aContext's
80    *   current transform.
81    * @param [in, optional] aExtraMask An extra surface that the returned
82    *   surface should be masked with.
83    */
84   already_AddRefed<SourceSurface> GetClipMask(
85       gfxContext& aReferenceContext, nsIFrame* aClippedFrame,
86       const gfxMatrix& aMatrix, SourceSurface* aExtraMask = nullptr);
87 
88   /**
89    * Paint mask directly onto a given context(aMaskContext).
90    *
91    * @param aMaskContext The target of mask been painting on.
92    * @param aClippedFrame The/an nsIFrame of the element that references this
93    *   clipPath that is currently being processed.
94    * @param aMatrix The transform from aClippedFrame's user space to
95    *   current transform.
96    * @param [in, optional] aExtraMask An extra surface that the returned
97    *   surface should be masked with.
98    */
99   void PaintClipMask(gfxContext& aMaskContext, nsIFrame* aClippedFrame,
100                      const gfxMatrix& aMatrix, SourceSurface* aExtraMask);
101 
102   /**
103    * aPoint is expected to be in aClippedFrame's SVG user space.
104    */
105   bool PointIsInsideClipPath(nsIFrame* aClippedFrame, const gfxPoint& aPoint);
106 
107   // Check if this clipPath is made up of more than one geometry object.
108   // If so, the clipping API in cairo isn't enough and we need to use
109   // mask based clipping.
110   bool IsTrivial(ISVGDisplayableFrame** aSingleChild = nullptr);
111 
112   bool IsValid();
113 
114   // nsIFrame interface:
115   virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
116                                     int32_t aModType) override;
117 
118   virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
119                     nsIFrame* aPrevInFlow) override;
120 
121 #ifdef DEBUG_FRAME_DUMP
GetFrameName(nsAString & aResult)122   virtual nsresult GetFrameName(nsAString& aResult) const override {
123     return MakeFrameName(u"SVGClipPath"_ns, aResult);
124   }
125 #endif
126 
127   SVGBBox GetBBoxForClipPathFrame(const SVGBBox& aBBox,
128                                   const gfxMatrix& aMatrix, uint32_t aFlags);
129 
130   /**
131    * If the clipPath element transforms its children due to
132    * clipPathUnits="objectBoundingBox" being set on it and/or due to the
133    * 'transform' attribute being set on it, this function returns the resulting
134    * transform.
135    */
136   gfxMatrix GetClipPathTransform(nsIFrame* aClippedFrame);
137 
138  private:
139   // SVGContainerFrame methods:
140   virtual gfxMatrix GetCanvasTM() override;
141 
142   already_AddRefed<DrawTarget> CreateClipMask(gfxContext& aReferenceContext,
143                                               gfx::IntPoint& aOffset);
144 
145   void PaintFrameIntoMask(nsIFrame* aFrame, nsIFrame* aClippedFrame,
146                           gfxContext& aTarget);
147 
148   // Set, during a GetClipMask() call, to the transform that still needs to be
149   // concatenated to the transform of the DrawTarget that was passed to
150   // GetClipMask in order to establish the coordinate space that the clipPath
151   // establishes for its contents (i.e. including applying 'clipPathUnits' and
152   // any 'transform' attribute set on the clipPath) specifically for clipping
153   // the frame that was passed to GetClipMask at that moment in time.  This is
154   // set so that if our GetCanvasTM method is called while GetClipMask is
155   // painting its children, the returned matrix will include the transforms
156   // that should be used when creating the mask for the frame passed to
157   // GetClipMask.
158   //
159   // Note: The removal of GetCanvasTM is nearly complete, so our GetCanvasTM
160   // may not even be called soon/any more.
161   gfxMatrix mMatrixForChildren;
162 
163   // Flag used to indicate whether a methods that may reenter due to
164   // following a reference to another instance is currently executing.
165   bool mIsBeingProcessed;
166 };
167 
168 }  // namespace mozilla
169 
170 #endif  // LAYOUT_SVG_SVGCLIPPATHFRAME_H_
171