layout/svg/nsSVGUtils.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef NS_SVGUTILS_H
     7 #define NS_SVGUTILS_H
     9 // include math.h to pick up definition of M_ maths defines e.g. M_PI
    10 #define _USE_MATH_DEFINES
    11 #include <math.h>
    13 #include "DrawMode.h"
    14 #include "gfx2DGlue.h"
    15 #include "gfxMatrix.h"
    16 #include "gfxPoint.h"
    17 #include "gfxRect.h"
    18 #include "mozilla/gfx/Rect.h"
    19 #include "nsAlgorithm.h"
    20 #include "nsChangeHint.h"
    21 #include "nsColor.h"
    22 #include "nsCOMPtr.h"
    23 #include "nsID.h"
    24 #include "nsISupportsBase.h"
    25 #include "nsMathUtils.h"
    26 #include "nsStyleStruct.h"
    27 #include "mozilla/Constants.h"
    28 #include <algorithm>
    30 class gfxContext;
    31 class gfxPattern;
    32 class nsFrameList;
    33 class nsIContent;
    34 class nsIDocument;
    35 class nsIFrame;
    36 class nsPresContext;
    37 class nsRenderingContext;
    38 class nsStyleContext;
    39 class nsStyleCoord;
    40 class nsSVGDisplayContainerFrame;
    41 class nsSVGElement;
    42 class nsSVGEnum;
    43 class nsSVGLength2;
    44 class nsSVGOuterSVGFrame;
    45 class nsSVGPathGeometryFrame;
    46 class nsTextFrame;
    47 class gfxTextContextPaint;
    49 struct nsStyleSVG;
    50 struct nsStyleSVGPaint;
    51 struct nsRect;
    52 struct nsIntRect;
    53 struct nsPoint;
    55 namespace mozilla {
    56 class SVGAnimatedPreserveAspectRatio;
    57 class SVGPreserveAspectRatio;
    58 namespace dom {
    59 class Element;
    60 } // namespace dom
    61 namespace gfx {
    62 class SourceSurface;
    63 }
    64 } // namespace mozilla
    66 // maximum dimension of an offscreen surface - choose so that
    67 // the surface size doesn't overflow a 32-bit signed int using
    68 // 4 bytes per pixel; in line with gfxASurface::CheckSurfaceSize
    69 // In fact Macs can't even manage that
    70 #define NS_SVG_OFFSCREEN_MAX_DIMENSION 4096
    72 #define SVG_HIT_TEST_FILL        0x01
    73 #define SVG_HIT_TEST_STROKE      0x02
    74 #define SVG_HIT_TEST_CHECK_MRECT 0x04
    77 bool NS_SVGDisplayListHitTestingEnabled();
    78 bool NS_SVGDisplayListPaintingEnabled();
    80 /**
    81  * Sometimes we need to distinguish between an empty box and a box
    82  * that contains an element that has no size e.g. a point at the origin.
    83  */
    84 class SVGBBox {
    85   typedef mozilla::gfx::Rect Rect;
    87 public:
    88   SVGBBox() 
    89     : mIsEmpty(true) {}
    91   SVGBBox(const Rect& aRect)
    92     : mBBox(aRect), mIsEmpty(false) {}
    94   SVGBBox(const gfxRect& aRect)
    95     : mBBox(ToRect(aRect)), mIsEmpty(false) {}
    97   gfxRect ToThebesRect() const {
    98     return ThebesRect(mBBox);
    99   }
   101   bool IsEmpty() const {
   102     return mIsEmpty;
   103   }
   105   void UnionEdges(const SVGBBox& aSVGBBox) {
   106     if (aSVGBBox.mIsEmpty) {
   107       return;
   108     }
   109     mBBox = mIsEmpty ? aSVGBBox.mBBox : mBBox.UnionEdges(aSVGBBox.mBBox);
   110     mIsEmpty = false;
   111   }
   113 private:
   114   Rect mBBox;
   115   bool mIsEmpty;
   116 };
   118 // GRRR WINDOWS HATE HATE HATE
   119 #undef CLIP_MASK
   121 class MOZ_STACK_CLASS SVGAutoRenderState
   122 {
   123 public:
   124   enum RenderMode {
   125     /**
   126      * Used to inform SVG frames that they should paint as normal.
   127      */
   128     NORMAL, 
   129     /** 
   130      * Used to inform SVG frames when they are painting as the child of a
   131      * simple clipPath. In this case they should only draw their basic geometry
   132      * as a path. They should not fill, stroke, or paint anything else.
   133      */
   134     CLIP, 
   135     /** 
   136      * Used to inform SVG frames when they are painting as the child of a
   137      * complex clipPath that requires the use of a clip mask. In this case they
   138      * should only draw their basic geometry as a path and then fill it using
   139      * fully opaque white. They should not stroke, or paint anything else.
   140      */
   141     CLIP_MASK 
   142   };
   144   SVGAutoRenderState(nsRenderingContext *aContext, RenderMode aMode
   145                      MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
   146   ~SVGAutoRenderState();
   148   void SetPaintingToWindow(bool aPaintingToWindow);
   150   static RenderMode GetRenderMode(nsRenderingContext *aContext);
   151   static bool IsPaintingToWindow(nsRenderingContext *aContext);
   153 private:
   154   nsRenderingContext *mContext;
   155   void *mOriginalRenderState;
   156   RenderMode mMode;
   157   bool mPaintingToWindow;
   158   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   159 };
   162 #define NS_ISVGFILTERREFERENCE_IID \
   163 { 0x9744ee20, 0x1bcf, 0x4c62, \
   164  { 0x86, 0x7d, 0xd3, 0x7a, 0x91, 0x60, 0x3e, 0xef } }
   166 class nsISVGFilterReference : public nsISupports
   167 {
   168 public:
   169   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGFILTERREFERENCE_IID)
   170   virtual void Invalidate() = 0;
   171 };
   173 NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGFilterReference, NS_ISVGFILTERREFERENCE_IID)
   175 /**
   176  * General functions used by all of SVG layout and possibly content code.
   177  * If a method is used by content and depends only on other content methods
   178  * it should go in SVGContentUtils instead.
   179  */
   180 class nsSVGUtils
   181 {
   182 public:
   183   typedef mozilla::dom::Element Element;
   185   static void Init();
   187   /**
   188    * Gets the nearest nsSVGInnerSVGFrame or nsSVGOuterSVGFrame frame. aFrame
   189    * must be an SVG frame. If aFrame is of type nsGkAtoms::svgOuterSVGFrame,
   190    * returns nullptr.
   191    */
   192   static nsSVGDisplayContainerFrame* GetNearestSVGViewport(nsIFrame *aFrame);
   194   /**
   195    * Returns the frame's post-filter visual overflow rect when passed the
   196    * frame's pre-filter visual overflow rect. If the frame is not currently
   197    * being filtered, this function simply returns aUnfilteredRect.
   198    */
   199   static nsRect GetPostFilterVisualOverflowRect(nsIFrame *aFrame,
   200                                                 const nsRect &aUnfilteredRect);
   202   /**
   203    * Schedules an update of the frame's bounds (which will in turn invalidate
   204    * the new area that the frame should paint to).
   205    *
   206    * This does nothing when passed an NS_FRAME_IS_NONDISPLAY frame.
   207    * In future we may want to allow ReflowSVG to be called on such frames,
   208    * but that would be better implemented as a ForceReflowSVG function to
   209    * be called synchronously while painting them without marking or paying
   210    * attention to dirty bits like this function.
   211    *
   212    * This is very similar to PresShell::FrameNeedsReflow. The main reason that
   213    * we have this function instead of using FrameNeedsReflow is because we need
   214    * to be able to call it under nsSVGOuterSVGFrame::NotifyViewportChange when
   215    * that function is called by nsSVGOuterSVGFrame::Reflow. FrameNeedsReflow
   216    * is not suitable for calling during reflow though, and it asserts as much.
   217    * The reason that we want to be callable under NotifyViewportChange is
   218    * because we want to synchronously notify and dirty the nsSVGOuterSVGFrame's
   219    * children so that when nsSVGOuterSVGFrame::DidReflow is called its children
   220    * will be updated for the new size as appropriate. Otherwise we'd have to
   221    * post an event to the event loop to mark dirty flags and request an update.
   222    *
   223    * Another reason that we don't currently want to call
   224    * PresShell::FrameNeedsReflow is because passing eRestyle to it to get it to
   225    * mark descendants dirty would cause it to descend through
   226    * nsSVGForeignObjectFrame frames to mark their children dirty, but we want to
   227    * handle nsSVGForeignObjectFrame specially. It would also do unnecessary work
   228    * descending into NS_FRAME_IS_NONDISPLAY frames.
   229    */
   230   static void ScheduleReflowSVG(nsIFrame *aFrame);
   232   /**
   233    * Returns true if the frame or any of its children need ReflowSVG
   234    * to be called on them.
   235    */
   236   static bool NeedsReflowSVG(nsIFrame *aFrame);
   238   /*
   239    * Update the filter invalidation region for ancestor frames, if relevant.
   240    */
   241   static void NotifyAncestorsOfFilterRegionChange(nsIFrame *aFrame);
   243   /* Computes the input length in terms of object space coordinates.
   244      Input: rect - bounding box
   245             length - length to be converted
   246   */
   247   static float ObjectSpace(const gfxRect &aRect, const nsSVGLength2 *aLength);
   249   /* Computes the input length in terms of user space coordinates.
   250      Input: content - object to be used for determining user space
   251      Input: length - length to be converted
   252   */
   253   static float UserSpace(nsSVGElement *aSVGElement, const nsSVGLength2 *aLength);
   255   /* Computes the input length in terms of user space coordinates.
   256      Input: aFrame - object to be used for determining user space
   257             length - length to be converted
   258   */
   259   static float UserSpace(nsIFrame *aFrame, const nsSVGLength2 *aLength);
   261   /* Find the outermost SVG frame of the passed frame */
   262   static nsSVGOuterSVGFrame *
   263   GetOuterSVGFrame(nsIFrame *aFrame);
   265   /**
   266    * Get the covered region for a frame. Return null if it's not an SVG frame.
   267    * @param aRect gets a rectangle in app units
   268    * @return the outer SVG frame which aRect is relative to
   269    */
   270   static nsIFrame*
   271   GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, nsRect* aRect);
   273   /* Paint SVG frame with SVG effects - aDirtyRect is the area being
   274    * redrawn, in device pixel coordinates relative to the outer svg */
   275   static void
   276   PaintFrameWithEffects(nsRenderingContext *aContext,
   277                         const nsIntRect *aDirtyRect,
   278                         nsIFrame *aFrame,
   279                         nsIFrame* aTransformRoot = nullptr);
   281   /* Hit testing - check if point hits the clipPath of indicated
   282    * frame.  Returns true if no clipPath set. */
   283   static bool
   284   HitTestClip(nsIFrame *aFrame, const nsPoint &aPoint);
   286   /* Hit testing - check if point hits any children of frame. */
   288   static nsIFrame *
   289   HitTestChildren(nsIFrame *aFrame, const nsPoint &aPoint);
   291   /*
   292    * Returns the CanvasTM of the indicated frame, whether it's a
   293    * child SVG frame, container SVG frame, or a regular frame.
   294    * For regular frames, we just return an identity matrix.
   295    */
   296   static gfxMatrix GetCanvasTM(nsIFrame* aFrame, uint32_t aFor,
   297                                nsIFrame* aTransformRoot = nullptr);
   299   /**
   300    * Returns the transform from aFrame's user space to canvas space. Only call
   301    * with SVG frames. This is like GetCanvasTM, except that it only includes
   302    * the transforms from aFrame's user space (i.e. the coordinate context
   303    * established by its 'transform' attribute, or else the coordinate context
   304    * that its _parent_ establishes for its children) to outer-<svg> device
   305    * space. Specifically, it does not include any other transforms introduced
   306    * by the frame such as x/y offsets and viewBox attributes.
   307    */
   308   static gfxMatrix GetUserToCanvasTM(nsIFrame* aFrame, uint32_t aFor);
   310   /**
   311    * Notify the descendants of aFrame of a change to one of their ancestors
   312    * that might affect them.
   313    */
   314   static void
   315   NotifyChildrenOfSVGChange(nsIFrame *aFrame, uint32_t aFlags);
   317   /*
   318    * Get frame's covered region by walking the children and doing union.
   319    */
   320   static nsRect
   321   GetCoveredRegion(const nsFrameList &aFrames);
   323   // Converts aPoint from an app unit point in outer-<svg> content rect space
   324   // to an app unit point in a frame's SVG userspace. 
   325   // This is a temporary helper we should no longer need after bug 614732 is
   326   // fixed.
   327   static nsPoint
   328   TransformOuterSVGPointToChildFrame(nsPoint aPoint,
   329                                      const gfxMatrix& aFrameToCanvasTM,
   330                                      nsPresContext* aPresContext);
   332   static nsRect
   333   TransformFrameRectToOuterSVG(const nsRect& aRect,
   334                                const gfxMatrix& aMatrix,
   335                                nsPresContext* aPresContext);
   337   /*
   338    * Convert a surface size to an integer for use by thebes
   339    * possibly making it smaller in the process so the surface does not
   340    * use excessive memory.
   341    *
   342    * @param aSize the desired surface size
   343    * @param aResultOverflows true if the desired surface size is too big
   344    * @return the surface size to use
   345    */
   346   static gfxIntSize ConvertToSurfaceSize(const gfxSize& aSize,
   347                                          bool *aResultOverflows);
   349   /*
   350    * Hit test a given rectangle/matrix.
   351    */
   352   static bool
   353   HitTestRect(const mozilla::gfx::Matrix &aMatrix,
   354               float aRX, float aRY, float aRWidth, float aRHeight,
   355               float aX, float aY);
   358   /**
   359    * Get the clip rect for the given frame, taking into account the CSS 'clip'
   360    * property. See:
   361    * http://www.w3.org/TR/SVG11/masking.html#OverflowAndClipProperties
   362    * The arguments for aX, aY, aWidth and aHeight should be the dimensions of
   363    * the viewport established by aFrame.
   364    */
   365   static gfxRect
   366   GetClipRectForFrame(nsIFrame *aFrame,
   367                       float aX, float aY, float aWidth, float aHeight);
   369   static void SetClipRect(gfxContext *aContext,
   370                           const gfxMatrix &aCTM,
   371                           const gfxRect &aRect);
   373   /* Using group opacity instead of fill or stroke opacity on a
   374    * geometry object seems to be a common authoring mistake.  If we're
   375    * not applying filters and not both stroking and filling, we can
   376    * generate the same result without going through the overhead of a
   377    * push/pop group. */
   378   static bool
   379   CanOptimizeOpacity(nsIFrame *aFrame);
   381   /**
   382    * Take the CTM to userspace for an element, and adjust it to a CTM to its
   383    * object bounding box space if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX.
   384    * (I.e. so that [0,0] is at the top left of its bbox, and [1,1] is at the
   385    * bottom right of its bbox).
   386    *
   387    * If the bbox is empty, this will return a singular matrix.
   388    */
   389   static gfxMatrix
   390   AdjustMatrixForUnits(const gfxMatrix &aMatrix,
   391                        nsSVGEnum *aUnits,
   392                        nsIFrame *aFrame);
   394   enum BBoxFlags {
   395     eBBoxIncludeFill           = 1 << 0,
   396     eBBoxIncludeFillGeometry   = 1 << 1,
   397     eBBoxIncludeStroke         = 1 << 2,
   398     eBBoxIncludeStrokeGeometry = 1 << 3,
   399     eBBoxIncludeMarkers        = 1 << 4
   400   };
   401   /**
   402    * Get the SVG bbox (the SVG spec's simplified idea of bounds) of aFrame in
   403    * aFrame's userspace.
   404    */
   405   static gfxRect GetBBox(nsIFrame *aFrame,
   406                          uint32_t aFlags = eBBoxIncludeFillGeometry);
   408   /*
   409    * "User space" is the space that the frame's BBox (as calculated by
   410    * nsSVGUtils::GetBBox) is in. "Frame space" is the space that has its origin
   411    * at the top left of the union of the frame's border-box rects over all
   412    * continuations.
   413    * This function returns the offset one needs to add to something in frame
   414    * space in order to get its coordinates in user space.
   415    */
   416   static gfxPoint FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame *aFrame);
   418   /**
   419    * Convert a userSpaceOnUse/objectBoundingBoxUnits rectangle that's specified
   420    * using four nsSVGLength2 values into a user unit rectangle in user space.
   421    *
   422    * @param aXYWH pointer to 4 consecutive nsSVGLength2 objects containing
   423    * the x, y, width and height values in that order
   424    * @param aBBox the bounding box of the object the rect is relative to;
   425    * may be null if aUnits is not SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
   426    * @param aFrame the object in which to interpret user-space units;
   427    * may be null if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
   428    */
   429   static gfxRect
   430   GetRelativeRect(uint16_t aUnits, const nsSVGLength2 *aXYWH,
   431                   const gfxRect &aBBox, nsIFrame *aFrame);
   433   /**
   434    * Find the first frame, starting with aStartFrame and going up its
   435    * parent chain, that is not an svgAFrame.
   436    */
   437   static nsIFrame* GetFirstNonAAncestorFrame(nsIFrame* aStartFrame);
   439   static bool OuterSVGIsCallingReflowSVG(nsIFrame *aFrame);
   440   static bool AnyOuterSVGIsCallingReflowSVG(nsIFrame *aFrame);
   442   /*
   443    * Get any additional transforms that apply only to stroking
   444    * e.g. non-scaling-stroke
   445    */
   446   static gfxMatrix GetStrokeTransform(nsIFrame *aFrame);
   448   /**
   449    * Compute the maximum possible device space stroke extents of a path given
   450    * the path's device space path extents, its stroke style and its ctm.
   451    *
   452    * This is a workaround for the lack of suitable cairo API for getting the
   453    * tight device space stroke extents of a path. This basically gives us the
   454    * tightest extents that we can guarantee fully enclose the inked stroke
   455    * without doing the calculations for the actual tight extents. We exploit
   456    * the fact that cairo does have an API for getting the tight device space
   457    * fill/path extents.
   458    *
   459    * This should die once bug 478152 is fixed.
   460    */
   461   static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
   462                                                nsTextFrame* aFrame,
   463                                                const gfxMatrix& aMatrix);
   464   static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
   465                                                nsSVGPathGeometryFrame* aFrame,
   466                                                const gfxMatrix& aMatrix);
   468   /**
   469    * Convert a floating-point value to a 32-bit integer value, clamping to
   470    * the range of valid integers.
   471    */
   472   static int32_t ClampToInt(double aVal)
   473   {
   474     return NS_lround(std::max(double(INT32_MIN),
   475                             std::min(double(INT32_MAX), aVal)));
   476   }
   478   static nscolor GetFallbackOrPaintColor(gfxContext *aContext,
   479                                          nsStyleContext *aStyleContext,
   480                                          nsStyleSVGPaint nsStyleSVG::*aFillOrStroke);
   482   /**
   483    * Set up cairo context with an object pattern
   484    */
   485   static bool SetupContextPaint(gfxContext *aContext,
   486                                 gfxTextContextPaint *aContextPaint,
   487                                 const nsStyleSVGPaint& aPaint,
   488                                 float aOpacity);
   490   /**
   491    * Sets the current paint on the specified gfxContent to be the SVG 'fill'
   492    * for the given frame.
   493    */
   494   static bool SetupCairoFillPaint(nsIFrame* aFrame, gfxContext* aContext,
   495                                   gfxTextContextPaint *aContextPaint = nullptr);
   497   /**
   498    * Sets the current paint on the specified gfxContent to be the SVG 'stroke'
   499    * for the given frame.
   500    */
   501   static bool SetupCairoStrokePaint(nsIFrame* aFrame, gfxContext* aContext,
   502                                     gfxTextContextPaint *aContextPaint = nullptr);
   504   static float GetOpacity(nsStyleSVGOpacitySource aOpacityType,
   505                           const float& aOpacity,
   506                           gfxTextContextPaint *aOuterContextPaint);
   508   /*
   509    * @return false if there is no stroke
   510    */
   511   static bool HasStroke(nsIFrame* aFrame,
   512                         gfxTextContextPaint *aContextPaint = nullptr);
   514   static float GetStrokeWidth(nsIFrame* aFrame,
   515                               gfxTextContextPaint *aContextPaint = nullptr);
   517   /*
   518    * Set up a cairo context for measuring the bounding box of a stroked path.
   519    */
   520   static void SetupCairoStrokeBBoxGeometry(nsIFrame* aFrame,
   521                                            gfxContext *aContext,
   522                                            gfxTextContextPaint *aContextPaint = nullptr);
   524   /*
   525    * Set up a cairo context for a stroked path (including any dashing that
   526    * applies).
   527    */
   528   static void SetupCairoStrokeGeometry(nsIFrame* aFrame, gfxContext *aContext,
   529                                        gfxTextContextPaint *aContextPaint = nullptr);
   531   /*
   532    * Set up a cairo context for stroking, including setting up any stroke-related
   533    * properties such as dashing and setting the current paint on the gfxContext.
   534    */
   535   static bool SetupCairoStroke(nsIFrame* aFrame, gfxContext *aContext,
   536                                gfxTextContextPaint *aContextPaint = nullptr);
   538   /**
   539    * This function returns a set of bit flags indicating which parts of the
   540    * element (fill, stroke, bounds) should intercept pointer events. It takes
   541    * into account the type of element and the value of the 'pointer-events'
   542    * property on the element.
   543    */
   544   static uint16_t GetGeometryHitTestFlags(nsIFrame* aFrame);
   546   /**
   547    * Render a SVG glyph.
   548    * @param aElement the SVG glyph element to render
   549    * @param aContext the thebes aContext to draw to
   550    * @param aDrawMode fill or stroke or both (see DrawMode)
   551    * @return true if rendering succeeded
   552    */
   553   static bool PaintSVGGlyph(Element* aElement, gfxContext* aContext,
   554                             DrawMode aDrawMode,
   555                             gfxTextContextPaint* aContextPaint);
   556   /**
   557    * Get the extents of a SVG glyph.
   558    * @param aElement the SVG glyph element
   559    * @param aSVGToAppSpace the matrix mapping the SVG glyph space to the
   560    *   target context space
   561    * @param aResult the result (valid when true is returned)
   562    * @return true if calculating the extents succeeded
   563    */
   564   static bool GetSVGGlyphExtents(Element* aElement,
   565                                  const gfxMatrix& aSVGToAppSpace,
   566                                  gfxRect* aResult);
   568   /**
   569    * Returns the app unit canvas bounds of a userspace rect.
   570    *
   571    * @param aToCanvas Transform from userspace to canvas device space.
   572    */
   573   static nsRect
   574   ToCanvasBounds(const gfxRect &aUserspaceRect,
   575                  const gfxMatrix &aToCanvas,
   576                  const nsPresContext *presContext);
   577 };
   579 #endif

mercurial