tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FilterInstance.h (16674B)


      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_FILTERINSTANCE_H_
      8 #define LAYOUT_SVG_FILTERINSTANCE_H_
      9 
     10 #include "FilterDescription.h"
     11 #include "gfxMatrix.h"
     12 #include "gfxPoint.h"
     13 #include "gfxRect.h"
     14 #include "mozilla/SVGIntegrationUtils.h"
     15 #include "mozilla/ServoStyleConsts.h"
     16 #include "mozilla/gfx/2D.h"
     17 #include "mozilla/webrender/WebRenderTypes.h"
     18 #include "nsCOMPtr.h"
     19 #include "nsHashKeys.h"
     20 #include "nsPoint.h"
     21 #include "nsRect.h"
     22 #include "nsSize.h"
     23 #include "nsTArray.h"
     24 
     25 class gfxContext;
     26 class nsIContent;
     27 class nsIFrame;
     28 struct WrFiltersHolder;
     29 
     30 namespace mozilla {
     31 class ISVGFilterObserverList;
     32 class SVGFilterFrame;
     33 
     34 namespace dom {
     35 class UserSpaceMetrics;
     36 }  // namespace dom
     37 
     38 namespace image {
     39 struct imgDrawingParams;
     40 }
     41 
     42 /**
     43 * This class performs all filter processing.
     44 *
     45 * We build a graph of the filter image data flow, essentially
     46 * converting the filter graph to SSA. This lets us easily propagate
     47 * analysis data (such as bounding-boxes) over the filter primitive graph.
     48 *
     49 * Definition of "filter space": filter space is a coordinate system that is
     50 * aligned with the user space of the filtered element, with its origin located
     51 * at the top left of the filter region, and with one unit equal in size to one
     52 * pixel of the offscreen surface into which the filter output would/will be
     53 * painted.
     54 *
     55 * The definition of "filter region" can be found here:
     56 * http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion
     57 */
     58 class FilterInstance {
     59  using IntRect = gfx::IntRect;
     60  using SourceSurface = gfx::SourceSurface;
     61  using DrawTarget = gfx::DrawTarget;
     62  using FilterPrimitiveDescription = gfx::FilterPrimitiveDescription;
     63  using FilterDescription = gfx::FilterDescription;
     64  using UserSpaceMetrics = dom::UserSpaceMetrics;
     65  using imgDrawingParams = image::imgDrawingParams;
     66  using SVGFilterPaintCallback = SVGIntegrationUtils::SVGFilterPaintCallback;
     67 
     68 public:
     69  /**
     70   * Create a FilterDescription for the supplied filter. All coordinates in
     71   * the description are in filter space.
     72   * @param aFilterInputIsTainted Describes whether the SourceImage /
     73   *   SourceAlpha input is tainted. This affects whether feDisplacementMap
     74   *   will respect the filter input as its map input, and it affects the
     75   *   IsTainted() state on the filter primitives in the FilterDescription.
     76   *   "Tainted" is a term from the filters spec and means security-sensitive
     77   *   content, i.e. pixels that JS should not be able to read in any way.
     78   * @param aOutAdditionalImages Will contain additional images needed to
     79   *   render the filter (from feImage primitives).
     80   * @return A FilterDescription describing the filter.
     81   */
     82  static FilterDescription GetFilterDescription(
     83      nsIContent* aFilteredElement, Span<const StyleFilter> aFilterChain,
     84      ISVGFilterObserverList* aFiltersObserverList, bool aFilterInputIsTainted,
     85      const UserSpaceMetrics& aMetrics, const gfxRect& aBBox,
     86      nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages);
     87 
     88  /**
     89   * Paint the given filtered frame.
     90   * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
     91   *   frame space (i.e. relative to its origin, the top-left corner of its
     92   *   border box).
     93   */
     94  static void PaintFilteredFrame(
     95      nsIFrame* aFilteredFrame, Span<const StyleFilter> aFilterChain,
     96      const nsTArray<SVGFilterFrame*>& aFilterFrames, gfxContext* aCtx,
     97      const SVGFilterPaintCallback& aPaintCallback, const nsRegion* aDirtyArea,
     98      imgDrawingParams& aImgParams, float aOpacity = 1.0f,
     99      const gfxRect* aOverrideBBox = nullptr);
    100 
    101  /**
    102   * Returns the post-filter area that could be dirtied when the given
    103   * pre-filter area of aFilteredFrame changes.
    104   * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that
    105   *   has changed, relative to aFilteredFrame, in app units.
    106   */
    107  static nsRegion GetPostFilterDirtyArea(nsIFrame* aFilteredFrame,
    108                                         const nsRegion& aPreFilterDirtyRegion);
    109 
    110  /**
    111   * Returns the pre-filter area that is needed from aFilteredFrame when the
    112   * given post-filter area needs to be repainted.
    113   * @param aPostFilterDirtyRegion The post-filter area that is dirty, relative
    114   *   to aFilteredFrame, in app units.
    115   */
    116  static nsRegion GetPreFilterNeededArea(
    117      nsIFrame* aFilteredFrame, const nsTArray<SVGFilterFrame*>& aFilterFrames,
    118      const nsRegion& aPostFilterDirtyRegion);
    119 
    120  /**
    121   * Returns the post-filter ink overflow rect (paint bounds) of
    122   * aFilteredFrame.
    123   * @param aOverrideBBox A user space rect, in user units, that should be used
    124   *   as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null.
    125   * @param aPreFilterBounds The pre-filter ink overflow rect of
    126   *   aFilteredFrame, if non-null.
    127   */
    128  static Maybe<nsRect> GetPostFilterBounds(
    129      nsIFrame* aFilteredFrame, const nsTArray<SVGFilterFrame*>& aFilterFrames,
    130      const gfxRect* aOverrideBBox = nullptr,
    131      const nsRect* aPreFilterBounds = nullptr);
    132 
    133  /**
    134   * Try to build WebRender filters for a frame if the filters applied to it are
    135   * supported, returns a status that indicates which code path will handle the
    136   * filters on this frame, or if we must fall back to blob image.
    137   */
    138  static WrFiltersStatus BuildWebRenderFilters(
    139      nsIFrame* aFilteredFrame,
    140      mozilla::Span<const mozilla::StyleFilter> aFilters,
    141      StyleFilterType aStyleFilterType, WrFiltersHolder& aWrFilters,
    142      const nsPoint& aOffsetForSVGFilters);
    143 
    144  /**
    145   * Try to build WebRender SVG filter graph for a frame based on SVG and CSS
    146   * filters.  If given an unreasonably costly set of filters this can reject
    147   * the entire filter graph (a behavior permitted by SVG spec).
    148   *
    149   * See WrFiltersStatus for possible outcomes.
    150   * Prefs such as gfx.webrender.svg-filter-effects affect this.
    151   */
    152  static WrFiltersStatus BuildWebRenderSVGFiltersImpl(
    153      nsIFrame* aFilteredFrame,
    154      mozilla::Span<const mozilla::StyleFilter> aFilters,
    155      StyleFilterType aStyleFilterType, WrFiltersHolder& aWrFilters,
    156      const nsPoint& aOffsetForSVGFilters);
    157 
    158 private:
    159  /**
    160   * @param aTargetFrame The frame of the filtered element under consideration,
    161   *   may be null.
    162   * @param aTargetContent The filtered element itself.
    163   * @param aMetrics The metrics to resolve SVG lengths against.
    164   * @param aFilterChain The list of filters to apply.
    165   * @param aFilterFrames The frames for the filters in the chain.
    166   * @param aFilterInputIsTainted Describes whether the SourceImage /
    167   *   SourceAlpha input is tainted. This affects whether feDisplacementMap
    168   *   will respect the filter input as its map input.
    169   * @param aPaintCallback [optional] The callback that Render() should use to
    170   *   paint. Only required if you will call Render().
    171   * @param aPaintTransform The transform to apply to convert to
    172   *   aTargetFrame's SVG user space. Only used when painting.
    173   * @param aPostFilterDirtyRegion [optional] The post-filter area
    174   *   that has to be repainted, in app units. Only required if you will
    175   *   call ComputeSourceNeededRect() or Render().
    176   * @param aPreFilterDirtyRegion [optional] The pre-filter area of
    177   *   the filtered element that changed, in app units. Only required if you
    178   *   will call ComputePostFilterDirtyRegion().
    179   * @param aPreFilterInkOverflowRectOverride [optional] Use a different
    180   *   ink overflow rect for the target element.
    181   * @param aOverrideBBox [optional] Use a different SVG bbox for the target
    182   *   element. Must be non-null if aTargetFrame is null.
    183   * @param aFilterSpaceBoundsNotSnapped [optional] The calculated bbox in
    184   *   userspace can be returend in the provided outparam.
    185   */
    186  FilterInstance(
    187      nsIFrame* aTargetFrame, nsIContent* aTargetContent,
    188      const UserSpaceMetrics& aMetrics, Span<const StyleFilter> aFilterChain,
    189      const nsTArray<SVGFilterFrame*>& aFilterFrames,
    190      bool aFilterInputIsTainted,
    191      const SVGIntegrationUtils::SVGFilterPaintCallback& aPaintCallback,
    192      const gfxMatrix& aPaintTransform,
    193      const nsRegion* aPostFilterDirtyRegion = nullptr,
    194      const nsRegion* aPreFilterDirtyRegion = nullptr,
    195      const nsRect* aPreFilterInkOverflowRectOverride = nullptr,
    196      const gfxRect* aOverrideBBox = nullptr,
    197      gfxRect* aFilterSpaceBoundsNotSnapped = nullptr);
    198 
    199  static WrFiltersStatus BuildWebRenderFiltersImpl(
    200      nsIFrame* aFilteredFrame,
    201      mozilla::Span<const mozilla::StyleFilter> aFilters,
    202      StyleFilterType aStyleFilterType, WrFiltersHolder& aWrFilters);
    203 
    204  /**
    205   * Returns true if the filter instance was created successfully.
    206   */
    207  bool IsInitialized() const { return mInitialized; }
    208 
    209  /**
    210   * Draws the filter output into aDrawTarget. The area that
    211   * needs to be painted must have been specified before calling this method
    212   * by passing it as the aPostFilterDirtyRegion argument to the
    213   * FilterInstance constructor.
    214   */
    215  void Render(gfxContext* aCtx, imgDrawingParams& aImgParams,
    216              float aOpacity = 1.0f);
    217 
    218  const FilterDescription& ExtractDescriptionAndAdditionalImages(
    219      nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages) {
    220    aOutAdditionalImages = std::move(mInputImages);
    221    return mFilterDescription;
    222  }
    223 
    224  /**
    225   * Sets the aPostFilterDirtyRegion outparam to the post-filter area in frame
    226   * space that would be dirtied by mTargetFrame when a given
    227   * pre-filter area of mTargetFrame is dirtied. The pre-filter area must have
    228   * been specified before calling this method by passing it as the
    229   * aPreFilterDirtyRegion argument to the FilterInstance constructor.
    230   */
    231  nsRegion ComputePostFilterDirtyRegion();
    232 
    233  /**
    234   * Sets the aPostFilterExtents outparam to the post-filter bounds in frame
    235   * space for the whole filter output. This is not necessarily equivalent to
    236   * the area that would be dirtied in the result when the entire pre-filter
    237   * area is dirtied, because some filter primitives can generate output
    238   * without any input.
    239   */
    240  nsRect ComputePostFilterExtents();
    241 
    242  /**
    243   * Sets the aDirty outparam to the pre-filter bounds in frame space of the
    244   * area of mTargetFrame that is needed in order to paint the filtered output
    245   * for a given post-filter dirtied area. The post-filter area must have been
    246   * specified before calling this method by passing it as the
    247   * aPostFilterDirtyRegion argument to the FilterInstance constructor.
    248   */
    249  nsRect ComputeSourceNeededRect();
    250 
    251  struct SourceInfo {
    252    // Specifies which parts of the source need to be rendered.
    253    // Set by ComputeNeededBoxes().
    254    nsIntRect mNeededBounds;
    255 
    256    // The surface that contains the input rendering.
    257    // Set by BuildSourceImage / BuildSourcePaint.
    258    RefPtr<SourceSurface> mSourceSurface;
    259 
    260    // The position and size of mSourceSurface in filter space.
    261    // Set by BuildSourceImage / BuildSourcePaint.
    262    IntRect mSurfaceRect;
    263  };
    264 
    265  /**
    266   * Creates a SourceSurface for either the FillPaint or StrokePaint graph
    267   * nodes
    268   */
    269  void BuildSourcePaint(SourceInfo* aSource, imgDrawingParams& aImgParams);
    270 
    271  /**
    272   * Creates a SourceSurface for either the FillPaint and StrokePaint graph
    273   * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and
    274   * mStrokePaint.mSourceSurface respectively.
    275   */
    276  void BuildSourcePaints(imgDrawingParams& aImgParams);
    277 
    278  /**
    279   * Creates the SourceSurface for the SourceGraphic graph node, paints its
    280   * contents, and assigns it to mSourceGraphic.mSourceSurface.
    281   */
    282  void BuildSourceImage(DrawTarget* aDest, imgDrawingParams& aImgParams,
    283                        mozilla::gfx::FilterNode* aFilter,
    284                        mozilla::gfx::FilterNode* aSource,
    285                        const mozilla::gfx::Rect& aSourceRect);
    286 
    287  /**
    288   * Build the list of FilterPrimitiveDescriptions that describes the filter's
    289   * filter primitives and their connections. This populates
    290   * mPrimitiveDescriptions and mInputImages. aFilterInputIsTainted describes
    291   * whether the SourceGraphic is tainted.
    292   */
    293  nsresult BuildPrimitives(Span<const StyleFilter> aFilterChain,
    294                           const nsTArray<SVGFilterFrame*>& aFilterFrames,
    295                           bool aFilterInputIsTainted);
    296 
    297  /**
    298   * Add to the list of FilterPrimitiveDescriptions for a particular SVG
    299   * reference filter or CSS filter. This populates mPrimitiveDescriptions and
    300   * mInputImages. aInputIsTainted describes whether the input to aFilter is
    301   * tainted.
    302   */
    303  nsresult BuildPrimitivesForFilter(
    304      const StyleFilter& aFilter, SVGFilterFrame* aFilterFrame,
    305      bool aInputIsTainted,
    306      nsTArray<FilterPrimitiveDescription>& aPrimitiveDescriptions);
    307 
    308  /**
    309   * Computes the filter space bounds of the areas that we actually *need* from
    310   * the filter sources, based on the value of mPostFilterDirtyRegion.
    311   * This sets mNeededBounds on the corresponding SourceInfo structs.
    312   */
    313  void ComputeNeededBoxes();
    314 
    315  /**
    316   * Returns the output bounds of the final FilterPrimitiveDescription.
    317   */
    318  nsIntRect OutputFilterSpaceBounds() const;
    319 
    320  /**
    321   * Compute the scale factors between user space and filter space.
    322   */
    323  bool ComputeUserSpaceToFilterSpaceScale();
    324 
    325  /**
    326   * Transform a rect between user space and filter space.
    327   */
    328  gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const;
    329  gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const;
    330 
    331  /**
    332   * Converts an nsRect or an nsRegion that is relative to a filtered frame's
    333   * origin (i.e. the top-left corner of its border box) into filter space,
    334   * rounding out.
    335   * Returns the entire filter region if aRect / aRegion is null, or if the
    336   * result is too large to be stored in an nsIntRect.
    337   */
    338  nsIntRect FrameSpaceToFilterSpace(const nsRect* aRect) const;
    339  nsIntRegion FrameSpaceToFilterSpace(const nsRegion* aRegion) const;
    340 
    341  /**
    342   * Converts an nsIntRect or an nsIntRegion from filter space into the space
    343   * that is relative to a filtered frame's origin (i.e. the top-left corner
    344   * of its border box) in app units, rounding out.
    345   */
    346  nsRect FilterSpaceToFrameSpace(const nsIntRect& aRect) const;
    347  nsRegion FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const;
    348 
    349  /**
    350   * Returns the transform from frame space to the coordinate space that
    351   * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the
    352   * top-left corner of its border box, aka the top left corner of its mRect.
    353   */
    354  gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const;
    355 
    356  bool ComputeTargetBBoxInFilterSpace();
    357 
    358  /**
    359   * The frame for the element that is currently being filtered.
    360   */
    361  nsIFrame* mTargetFrame;
    362 
    363  /**
    364   * The filtered element.
    365   */
    366  nsIContent* mTargetContent;
    367 
    368  /**
    369   * The user space metrics of the filtered frame.
    370   */
    371  const UserSpaceMetrics& mMetrics;
    372 
    373  const SVGFilterPaintCallback& mPaintCallback;
    374 
    375  /**
    376   * The SVG bbox of the element that is being filtered, in user space.
    377   */
    378  gfxRect mTargetBBox;
    379 
    380  /**
    381   * The SVG bbox of the element that is being filtered, in filter space.
    382   */
    383  nsIntRect mTargetBBoxInFilterSpace;
    384 
    385  /**
    386   * The SVG filter element rect, in filter space, may be non-integer.
    387   */
    388  gfxRect mFilterSpaceBoundsNotSnapped;
    389 
    390  /**
    391   * Transform rects between filter space and frame space in CSS pixels.
    392   */
    393  gfxMatrix mFilterSpaceToFrameSpaceInCSSPxTransform;
    394  gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform;
    395 
    396  /**
    397   * The scale factors between user space and filter space.
    398   */
    399  gfx::MatrixScalesDouble mUserSpaceToFilterSpaceScale;
    400  gfx::MatrixScalesDouble mFilterSpaceToUserSpaceScale;
    401 
    402  /**
    403   * Pre-filter paint bounds of the element that is being filtered, in filter
    404   * space.
    405   */
    406  nsIntRect mTargetBounds;
    407 
    408  /**
    409   * The dirty area that needs to be repainted, in filter space.
    410   */
    411  nsIntRegion mPostFilterDirtyRegion;
    412 
    413  /**
    414   * The pre-filter area of the filtered element that changed, in filter space.
    415   */
    416  nsIntRegion mPreFilterDirtyRegion;
    417 
    418  SourceInfo mSourceGraphic;
    419  SourceInfo mFillPaint;
    420  SourceInfo mStrokePaint;
    421 
    422  /**
    423   * The transform to the SVG user space of mTargetFrame.
    424   */
    425  gfxMatrix mPaintTransform;
    426 
    427  nsTArray<RefPtr<SourceSurface>> mInputImages;
    428  FilterDescription mFilterDescription;
    429  bool mInitialized;
    430 };
    431 
    432 }  // namespace mozilla
    433 
    434 #endif  // LAYOUT_SVG_FILTERINSTANCE_H_