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_SVGUTILS_H_
8 #define LAYOUT_SVG_SVGUTILS_H_
9 
10 // include math.h to pick up definition of M_ maths defines e.g. M_PI
11 #include <math.h>
12 
13 #include "DrawMode.h"
14 #include "ImgDrawResult.h"
15 #include "gfx2DGlue.h"
16 #include "gfxMatrix.h"
17 #include "gfxPoint.h"
18 #include "gfxRect.h"
19 #include "mozilla/gfx/Rect.h"
20 #include "nsAlgorithm.h"
21 #include "nsChangeHint.h"
22 #include "nsColor.h"
23 #include "nsCOMPtr.h"
24 #include "nsID.h"
25 #include "nsIFrame.h"
26 #include "nsISupportsBase.h"
27 #include "nsMathUtils.h"
28 #include "nsStyleStruct.h"
29 #include <algorithm>
30 
31 class gfxContext;
32 class nsFrameList;
33 class nsIContent;
34 
35 class nsPresContext;
36 class nsTextFrame;
37 
38 struct nsStyleSVG;
39 struct nsRect;
40 
41 namespace mozilla {
42 class SVGAnimatedEnumeration;
43 class SVGAnimatedLength;
44 class SVGContextPaint;
45 struct SVGContextPaintImpl;
46 class SVGDisplayContainerFrame;
47 class SVGGeometryFrame;
48 class SVGOuterSVGFrame;
49 namespace dom {
50 class Element;
51 class SVGElement;
52 class UserSpaceMetrics;
53 }  // namespace dom
54 namespace gfx {
55 class DrawTarget;
56 class GeneralPattern;
57 }  // namespace gfx
58 }  // namespace mozilla
59 
60 // maximum dimension of an offscreen surface - choose so that
61 // the surface size doesn't overflow a 32-bit signed int using
62 // 4 bytes per pixel; in line with Factory::CheckSurfaceSize
63 // In fact Macs can't even manage that
64 #define NS_SVG_OFFSCREEN_MAX_DIMENSION 4096
65 
66 #define SVG_HIT_TEST_FILL 0x01
67 #define SVG_HIT_TEST_STROKE 0x02
68 #define SVG_HIT_TEST_CHECK_MRECT 0x04
69 
70 bool NS_SVGDisplayListHitTestingEnabled();
71 bool NS_SVGDisplayListPaintingEnabled();
72 bool NS_SVGNewGetBBoxEnabled();
73 
74 namespace mozilla {
75 
76 /**
77  * Sometimes we need to distinguish between an empty box and a box
78  * that contains an element that has no size e.g. a point at the origin.
79  */
80 class SVGBBox final {
81   using Rect = gfx::Rect;
82 
83  public:
SVGBBox()84   SVGBBox() : mIsEmpty(true) {}
85 
SVGBBox(const Rect & aRect)86   MOZ_IMPLICIT SVGBBox(const Rect& aRect) : mBBox(aRect), mIsEmpty(false) {}
87 
SVGBBox(const gfxRect & aRect)88   MOZ_IMPLICIT SVGBBox(const gfxRect& aRect)
89       : mBBox(ToRect(aRect)), mIsEmpty(false) {}
90 
91   operator const Rect&() { return mBBox; }
92 
ToThebesRect()93   gfxRect ToThebesRect() const { return ThebesRect(mBBox); }
94 
IsEmpty()95   bool IsEmpty() const { return mIsEmpty; }
96 
IsFinite()97   bool IsFinite() const { return mBBox.IsFinite(); }
98 
Scale(float aScale)99   void Scale(float aScale) { mBBox.Scale(aScale); }
MoveBy(float x,float y)100   void MoveBy(float x, float y) { mBBox.MoveBy(x, y); }
101 
UnionEdges(const SVGBBox & aSVGBBox)102   void UnionEdges(const SVGBBox& aSVGBBox) {
103     if (aSVGBBox.mIsEmpty) {
104       return;
105     }
106     mBBox = mIsEmpty ? aSVGBBox.mBBox : mBBox.UnionEdges(aSVGBBox.mBBox);
107     mIsEmpty = false;
108   }
109 
Intersect(const SVGBBox & aSVGBBox)110   void Intersect(const SVGBBox& aSVGBBox) {
111     if (!mIsEmpty && !aSVGBBox.mIsEmpty) {
112       mBBox = mBBox.Intersect(aSVGBBox.mBBox);
113       if (mBBox.IsEmpty()) {
114         mIsEmpty = true;
115         mBBox = Rect(0, 0, 0, 0);
116       }
117     } else {
118       mIsEmpty = true;
119       mBBox = Rect(0, 0, 0, 0);
120     }
121   }
122 
123  private:
124   Rect mBBox;
125   bool mIsEmpty;
126 };
127 
128 // GRRR WINDOWS HATE HATE HATE
129 #undef CLIP_MASK
130 
131 class MOZ_RAII SVGAutoRenderState final {
132   using DrawTarget = gfx::DrawTarget;
133 
134  public:
135   explicit SVGAutoRenderState(DrawTarget* aDrawTarget);
136   ~SVGAutoRenderState();
137 
138   void SetPaintingToWindow(bool aPaintingToWindow);
139 
140   static bool IsPaintingToWindow(DrawTarget* aDrawTarget);
141 
142  private:
143   DrawTarget* mDrawTarget;
144   void* mOriginalRenderState;
145   bool mPaintingToWindow;
146 };
147 
148 /**
149  * General functions used by all of SVG layout and possibly content code.
150  * If a method is used by content and depends only on other content methods
151  * it should go in SVGContentUtils instead.
152  */
153 class SVGUtils final {
154  public:
155   using Element = dom::Element;
156   using SVGElement = dom::SVGElement;
157   using AntialiasMode = gfx::AntialiasMode;
158   using DrawTarget = gfx::DrawTarget;
159   using FillRule = gfx::FillRule;
160   using GeneralPattern = gfx::GeneralPattern;
161   using Size = gfx::Size;
162   using imgDrawingParams = image::imgDrawingParams;
163 
164   NS_DECLARE_FRAME_PROPERTY_DELETABLE(ObjectBoundingBoxProperty, gfxRect)
165 
166   /**
167    * Returns the frame's post-filter ink overflow rect when passed the
168    * frame's pre-filter ink overflow rect. If the frame is not currently
169    * being filtered, this function simply returns aUnfilteredRect.
170    */
171   static nsRect GetPostFilterInkOverflowRect(nsIFrame* aFrame,
172                                              const nsRect& aPreFilterRect);
173 
174   /**
175    * Schedules an update of the frame's bounds (which will in turn invalidate
176    * the new area that the frame should paint to).
177    *
178    * This does nothing when passed an NS_FRAME_IS_NONDISPLAY frame.
179    * In future we may want to allow ReflowSVG to be called on such frames,
180    * but that would be better implemented as a ForceReflowSVG function to
181    * be called synchronously while painting them without marking or paying
182    * attention to dirty bits like this function.
183    *
184    * This is very similar to PresShell::FrameNeedsReflow. The main reason that
185    * we have this function instead of using FrameNeedsReflow is because we need
186    * to be able to call it under SVGOuterSVGFrame::NotifyViewportChange when
187    * that function is called by SVGOuterSVGFrame::Reflow. FrameNeedsReflow
188    * is not suitable for calling during reflow though, and it asserts as much.
189    * The reason that we want to be callable under NotifyViewportChange is
190    * because we want to synchronously notify and dirty the SVGOuterSVGFrame's
191    * children so that when SVGOuterSVGFrame::DidReflow is called its children
192    * will be updated for the new size as appropriate. Otherwise we'd have to
193    * post an event to the event loop to mark dirty flags and request an update.
194    *
195    * Another reason that we don't currently want to call
196    * PresShell::FrameNeedsReflow is because passing eRestyle to it to get it to
197    * mark descendants dirty would cause it to descend through
198    * SVGForeignObjectFrame frames to mark their children dirty, but we want to
199    * handle SVGForeignObjectFrame specially. It would also do unnecessary work
200    * descending into NS_FRAME_IS_NONDISPLAY frames.
201    */
202   static void ScheduleReflowSVG(nsIFrame* aFrame);
203 
204   /**
205    * Returns true if the frame or any of its children need ReflowSVG
206    * to be called on them.
207    */
208   static bool NeedsReflowSVG(nsIFrame* aFrame);
209 
210   /**
211    * Percentage lengths in SVG are resolved against the width/height of the
212    * nearest viewport (or its viewBox, if set). This helper returns the size
213    * of this "context" for the given frame so that percentage values can be
214    * resolved.
215    */
216   static Size GetContextSize(const nsIFrame* aFrame);
217 
218   /* Computes the input length in terms of object space coordinates.
219      Input: rect - bounding box
220             length - length to be converted
221   */
222   static float ObjectSpace(const gfxRect& aRect,
223                            const SVGAnimatedLength* aLength);
224 
225   /* Computes the input length in terms of user space coordinates.
226      Input: content - object to be used for determining user space
227      Input: length - length to be converted
228   */
229   static float UserSpace(SVGElement* aSVGElement,
230                          const SVGAnimatedLength* aLength);
231   static float UserSpace(nsIFrame* aNonSVGContext,
232                          const SVGAnimatedLength* aLength);
233   static float UserSpace(const dom::UserSpaceMetrics& aMetrics,
234                          const SVGAnimatedLength* aLength);
235 
236   /* Find the outermost SVG frame of the passed frame */
237   static SVGOuterSVGFrame* GetOuterSVGFrame(nsIFrame* aFrame);
238 
239   /**
240    * Get the covered region for a frame. Return null if it's not an SVG frame.
241    * @param aRect gets a rectangle in app units
242    * @return the outer SVG frame which aRect is relative to
243    */
244   static nsIFrame* GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame,
245                                                     nsRect* aRect);
246 
247   /* Paint SVG frame with SVG effects - aDirtyRect is the area being
248    * redrawn, in device pixel coordinates relative to the outer svg */
249   static void PaintFrameWithEffects(nsIFrame* aFrame, gfxContext& aContext,
250                                     const gfxMatrix& aTransform,
251                                     imgDrawingParams& aImgParams,
252                                     const nsIntRect* aDirtyRect = nullptr);
253 
254   /* Hit testing - check if point hits the clipPath of indicated
255    * frame.  Returns true if no clipPath set. */
256   static bool HitTestClip(nsIFrame* aFrame, const gfxPoint& aPoint);
257 
258   /**
259    * Hit testing - check if point hits any children of aFrame.  aPoint is
260    * expected to be in the coordinate space established by aFrame for its
261    * children (e.g. the space established by the 'viewBox' attribute on <svg>).
262    */
263   static nsIFrame* HitTestChildren(SVGDisplayContainerFrame* aFrame,
264                                    const gfxPoint& aPoint);
265 
266   /*
267    * Returns the CanvasTM of the indicated frame, whether it's a
268    * child SVG frame, container SVG frame, or a regular frame.
269    * For regular frames, we just return an identity matrix.
270    */
271   static gfxMatrix GetCanvasTM(nsIFrame* aFrame);
272 
273   /**
274    * Notify the descendants of aFrame of a change to one of their ancestors
275    * that might affect them.
276    */
277   static void NotifyChildrenOfSVGChange(nsIFrame* aFrame, uint32_t aFlags);
278 
279   static nsRect TransformFrameRectToOuterSVG(const nsRect& aRect,
280                                              const gfxMatrix& aMatrix,
281                                              nsPresContext* aPresContext);
282 
283   /*
284    * Convert a surface size to an integer for use by thebes
285    * possibly making it smaller in the process so the surface does not
286    * use excessive memory.
287    *
288    * @param aSize the desired surface size
289    * @param aResultOverflows true if the desired surface size is too big
290    * @return the surface size to use
291    */
292   static gfx::IntSize ConvertToSurfaceSize(const gfxSize& aSize,
293                                            bool* aResultOverflows);
294 
295   /*
296    * Hit test a given rectangle/matrix.
297    */
298   static bool HitTestRect(const gfx::Matrix& aMatrix, float aRX, float aRY,
299                           float aRWidth, float aRHeight, float aX, float aY);
300 
301   /**
302    * Get the clip rect for the given frame, taking into account the CSS 'clip'
303    * property. See:
304    * http://www.w3.org/TR/SVG11/masking.html#OverflowAndClipProperties
305    * The arguments for aX, aY, aWidth and aHeight should be the dimensions of
306    * the viewport established by aFrame.
307    */
308   static gfxRect GetClipRectForFrame(nsIFrame* aFrame, float aX, float aY,
309                                      float aWidth, float aHeight);
310 
311   static void SetClipRect(gfxContext* aContext, const gfxMatrix& aCTM,
312                           const gfxRect& aRect);
313 
314   /* Using group opacity instead of fill or stroke opacity on a
315    * geometry object seems to be a common authoring mistake.  If we're
316    * not applying filters and not both stroking and filling, we can
317    * generate the same result without going through the overhead of a
318    * push/pop group. */
319   static bool CanOptimizeOpacity(nsIFrame* aFrame);
320 
321   /**
322    * Take the CTM to userspace for an element, and adjust it to a CTM to its
323    * object bounding box space if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX.
324    * (I.e. so that [0,0] is at the top left of its bbox, and [1,1] is at the
325    * bottom right of its bbox).
326    *
327    * If the bbox is empty, this will return a singular matrix.
328    *
329    * @param aFlags One or more of the BBoxFlags values defined below.
330    */
331   static gfxMatrix AdjustMatrixForUnits(const gfxMatrix& aMatrix,
332                                         SVGAnimatedEnumeration* aUnits,
333                                         nsIFrame* aFrame, uint32_t aFlags);
334 
335   enum BBoxFlags {
336     eBBoxIncludeFill = 1 << 0,
337     // Include the geometry of the fill even when the fill does not
338     // actually render (e.g. when fill="none" or fill-opacity="0")
339     eBBoxIncludeFillGeometry = 1 << 1,
340     eBBoxIncludeStroke = 1 << 2,
341     // Include the geometry of the stroke even when the stroke does not
342     // actually render (e.g. when stroke="none" or stroke-opacity="0")
343     eBBoxIncludeStrokeGeometry = 1 << 3,
344     eBBoxIncludeMarkers = 1 << 4,
345     eBBoxIncludeClipped = 1 << 5,
346     // Normally a getBBox call on outer-<svg> should only return the
347     // bounds of the elements children. This flag will cause the
348     // element's bounds to be returned instead.
349     eUseFrameBoundsForOuterSVG = 1 << 6,
350     // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
351     eForGetClientRects = 1 << 7,
352     // If the given frame is an HTML element, only include the region of the
353     // given frame, instead of all continuations of it, while computing bbox if
354     // this flag is set.
355     eIncludeOnlyCurrentFrameForNonSVGElement = 1 << 8,
356     // This flag is only has an effect when the target is a <use> element.
357     // getBBox returns the bounds of the elements children in user space if
358     // this flag is set; Otherwise, getBBox returns the union bounds in
359     // the coordinate system formed by the <use> element.
360     eUseUserSpaceOfUseElement = 1 << 9,
361     // For a frame with a clip-path, if this flag is set then the result
362     // will not be clipped to the bbox of the content inside the clip-path.
363     eDoNotClipToBBoxOfContentInsideClipPath = 1 << 10,
364   };
365   /**
366    * This function in primarily for implementing the SVG DOM function getBBox()
367    * and the SVG attribute value 'objectBoundingBox'.  However, it has been
368    * extended with various extra parameters in order to become more of a
369    * general purpose getter of all sorts of bounds that we might need to obtain
370    * for SVG elements, or even for other elements that have SVG effects applied
371    * to them.
372    *
373    * @param aFrame The frame of the element for which the bounds are to be
374    *   obtained.
375    * @param aFlags One or more of the BBoxFlags values defined above.
376    * @param aToBoundsSpace If not specified the returned rect is in aFrame's
377    *   element's "user space". A matrix can optionally be pass to specify a
378    *   transform from aFrame's user space to the bounds space of interest
379    *   (typically this will be the ancestor SVGOuterSVGFrame, but it could be
380    *   to any other coordinate space).
381    */
382   static gfxRect GetBBox(nsIFrame* aFrame,
383                          // If the default arg changes, update the handling for
384                          // ObjectBoundingBoxProperty() in the implementation.
385                          uint32_t aFlags = eBBoxIncludeFillGeometry,
386                          const gfxMatrix* aToBoundsSpace = nullptr);
387 
388   /*
389    * "User space" is the space that the frame's BBox (as calculated by
390    * SVGUtils::GetBBox) is in. "Frame space" is the space that has its origin
391    * at the top left of the union of the frame's border-box rects over all
392    * continuations.
393    * This function returns the offset one needs to add to something in frame
394    * space in order to get its coordinates in user space.
395    */
396   static gfxPoint FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame* aFrame);
397 
398   /**
399    * Convert a userSpaceOnUse/objectBoundingBoxUnits rectangle that's specified
400    * using four SVGAnimatedLength values into a user unit rectangle in user
401    * space.
402    *
403    * @param aXYWH pointer to 4 consecutive SVGAnimatedLength objects containing
404    * the x, y, width and height values in that order
405    * @param aBBox the bounding box of the object the rect is relative to;
406    * may be null if aUnits is not SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
407    * @param aFrame the object in which to interpret user-space units;
408    * may be null if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
409    */
410   static gfxRect GetRelativeRect(uint16_t aUnits,
411                                  const SVGAnimatedLength* aXYWH,
412                                  const gfxRect& aBBox, nsIFrame* aFrame);
413 
414   static gfxRect GetRelativeRect(uint16_t aUnits,
415                                  const SVGAnimatedLength* aXYWH,
416                                  const gfxRect& aBBox,
417                                  const dom::UserSpaceMetrics& aMetrics);
418 
419   /**
420    * Find the first frame, starting with aStartFrame and going up its
421    * parent chain, that is not an svgAFrame.
422    */
423   static nsIFrame* GetFirstNonAAncestorFrame(nsIFrame* aStartFrame);
424 
425   static bool OuterSVGIsCallingReflowSVG(nsIFrame* aFrame);
426   static bool AnyOuterSVGIsCallingReflowSVG(nsIFrame* aFrame);
427 
428   /**
429    * See https://svgwg.org/svg2-draft/painting.html#NonScalingStroke
430    *
431    * If the computed value of the 'vector-effect' property on aFrame is
432    * 'non-scaling-stroke', then this function will set aUserToOuterSVG to the
433    * transform from aFrame's SVG user space to the initial coordinate system
434    * established by the viewport of aFrame's outer-<svg>'s (the coordinate
435    * system in which the stroke is fixed).  If aUserToOuterSVG is set to a
436    * non-identity matrix this function returns true, else it returns false.
437    */
438   static bool GetNonScalingStrokeTransform(nsIFrame* aFrame,
439                                            gfxMatrix* aUserToOuterSVG);
440 
441   /**
442    * Compute the maximum possible device space stroke extents of a path given
443    * the path's device space path extents, its stroke style and its ctm.
444    *
445    * This is a workaround for the lack of suitable cairo API for getting the
446    * tight device space stroke extents of a path. This basically gives us the
447    * tightest extents that we can guarantee fully enclose the inked stroke
448    * without doing the calculations for the actual tight extents. We exploit
449    * the fact that cairo does have an API for getting the tight device space
450    * fill/path extents.
451    *
452    * This should die once bug 478152 is fixed.
453    */
454   static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
455                                                nsTextFrame* aFrame,
456                                                const gfxMatrix& aMatrix);
457   static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
458                                                SVGGeometryFrame* aFrame,
459                                                const gfxMatrix& aMatrix);
460 
461   /**
462    * Convert a floating-point value to a 32-bit integer value, clamping to
463    * the range of valid integers.
464    */
ClampToInt(double aVal)465   static int32_t ClampToInt(double aVal) {
466     return NS_lround(
467         std::max(double(INT32_MIN), std::min(double(INT32_MAX), aVal)));
468   }
469 
470   static nscolor GetFallbackOrPaintColor(
471       const ComputedStyle&, StyleSVGPaint nsStyleSVG::*aFillOrStroke);
472 
473   static void MakeFillPatternFor(nsIFrame* aFrame, gfxContext* aContext,
474                                  GeneralPattern* aOutPattern,
475                                  imgDrawingParams& aImgParams,
476                                  SVGContextPaint* aContextPaint = nullptr);
477 
478   static void MakeStrokePatternFor(nsIFrame* aFrame, gfxContext* aContext,
479                                    GeneralPattern* aOutPattern,
480                                    imgDrawingParams& aImgParams,
481                                    SVGContextPaint* aContextPaint = nullptr);
482 
483   static float GetOpacity(const StyleSVGOpacity&, SVGContextPaint*);
484 
485   /*
486    * @return false if there is no stroke
487    */
488   static bool HasStroke(nsIFrame* aFrame,
489                         SVGContextPaint* aContextPaint = nullptr);
490 
491   static float GetStrokeWidth(nsIFrame* aFrame,
492                               SVGContextPaint* aContextPaint = nullptr);
493 
494   /*
495    * Set up a context for a stroked path (including any dashing that applies).
496    */
497   static void SetupStrokeGeometry(nsIFrame* aFrame, gfxContext* aContext,
498                                   SVGContextPaint* aContextPaint = nullptr);
499 
500   /**
501    * This function returns a set of bit flags indicating which parts of the
502    * element (fill, stroke, bounds) should intercept pointer events. It takes
503    * into account the type of element and the value of the 'pointer-events'
504    * property on the element.
505    */
506   static uint16_t GetGeometryHitTestFlags(nsIFrame* aFrame);
507 
ToFillRule(StyleFillRule aFillRule)508   static FillRule ToFillRule(StyleFillRule aFillRule) {
509     return aFillRule == StyleFillRule::Evenodd ? FillRule::FILL_EVEN_ODD
510                                                : FillRule::FILL_WINDING;
511   }
512 
ToAntialiasMode(StyleTextRendering aTextRendering)513   static AntialiasMode ToAntialiasMode(StyleTextRendering aTextRendering) {
514     return aTextRendering == StyleTextRendering::Optimizespeed
515                ? AntialiasMode::NONE
516                : AntialiasMode::SUBPIXEL;
517   }
518 
519   /**
520    * Render a SVG glyph.
521    * @param aElement the SVG glyph element to render
522    * @param aContext the thebes aContext to draw to
523    * @return true if rendering succeeded
524    */
525   static void PaintSVGGlyph(Element* aElement, gfxContext* aContext);
526 
527   /**
528    * Get the extents of a SVG glyph.
529    * @param aElement the SVG glyph element
530    * @param aSVGToAppSpace the matrix mapping the SVG glyph space to the
531    *   target context space
532    * @param aResult the result (valid when true is returned)
533    * @return true if calculating the extents succeeded
534    */
535   static bool GetSVGGlyphExtents(Element* aElement,
536                                  const gfxMatrix& aSVGToAppSpace,
537                                  gfxRect* aResult);
538 
539   /**
540    * Returns the app unit canvas bounds of a userspace rect.
541    *
542    * @param aToCanvas Transform from userspace to canvas device space.
543    */
544   static nsRect ToCanvasBounds(const gfxRect& aUserspaceRect,
545                                const gfxMatrix& aToCanvas,
546                                const nsPresContext* presContext);
547 
548   struct MaskUsage {
549     bool shouldGenerateMaskLayer;
550     bool shouldGenerateClipMaskLayer;
551     bool shouldApplyClipPath;
552     bool shouldApplyBasicShapeOrPath;
553     float opacity;
554 
MaskUsageMaskUsage555     MaskUsage()
556         : shouldGenerateMaskLayer(false),
557           shouldGenerateClipMaskLayer(false),
558           shouldApplyClipPath(false),
559           shouldApplyBasicShapeOrPath(false),
560           opacity(0.0) {}
561 
shouldDoSomethingMaskUsage562     bool shouldDoSomething() {
563       return shouldGenerateMaskLayer || shouldGenerateClipMaskLayer ||
564              shouldApplyClipPath || shouldApplyBasicShapeOrPath ||
565              opacity != 1.0;
566     }
567   };
568 
569   static void DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity,
570                                  MaskUsage& aUsage);
571 
572   static float ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity);
573 
574   /**
575    * SVG frames expect to paint in SVG user units, which are equal to CSS px
576    * units. This method provides a transform matrix to multiply onto a
577    * gfxContext's current transform to convert the context's current units from
578    * its usual dev pixels to SVG user units/CSS px to keep the SVG code happy.
579    */
580   static gfxMatrix GetCSSPxToDevPxMatrix(nsIFrame* aNonSVGFrame);
581 
IsInSVGTextSubtree(const nsIFrame * aFrame)582   static bool IsInSVGTextSubtree(const nsIFrame* aFrame) {
583     // Returns true if the frame is an SVGTextFrame or one of its descendants.
584     return aFrame->HasAnyStateBits(NS_FRAME_IS_SVG_TEXT);
585   }
586 
587   /**
588    * It is a replacement of
589    * SVGElement::PrependLocalTransformsTo(eUserSpaceToParent).
590    * If no CSS transform is involved, they should behave exactly the same;
591    * if there are CSS transforms, this one will take them into account
592    * while SVGElement::PrependLocalTransformsTo won't.
593    */
594   static gfxMatrix GetTransformMatrixInUserSpace(const nsIFrame* aFrame);
595 };
596 
597 }  // namespace mozilla
598 
599 #endif  // LAYOUT_SVG_SVGUTILS_H_
600