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