tor-browser

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

SVGIntegrationUtils.h (11342B)


      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_SVGINTEGRATIONUTILS_H_
      8 #define LAYOUT_SVG_SVGINTEGRATIONUTILS_H_
      9 
     10 #include "ImgDrawResult.h"
     11 #include "gfxMatrix.h"
     12 #include "gfxRect.h"
     13 #include "mozilla/ServoStyleConsts.h"
     14 #include "mozilla/gfx/Rect.h"
     15 #include "mozilla/webrender/WebRenderTypes.h"
     16 #include "nsRegionFwd.h"
     17 
     18 class gfxContext;
     19 class gfxDrawable;
     20 class nsIFrame;
     21 struct nsPoint;
     22 struct nsRect;
     23 struct nsSize;
     24 
     25 // zipstruct.h defines this and causes issues if in the same translation unit.
     26 #undef UNSUPPORTED
     27 
     28 enum class WrFiltersStatus {
     29  // Image will be rendered unftilered - the filter graph contains invalid refs
     30  // (which SVG spec states will be rendered as if there is no filter graph).
     31  UNSUPPORTED = 0,
     32  // Image will be rendered unfiltered - the filter graph provided is
     33  // excessively costly to render and has been dropped (per SVG spec we can do
     34  // this to preserve user experience).
     35  DISABLED_FOR_PERFORMANCE = 1,
     36  // Image will be rendered using blob fallback (software rendering) due to
     37  // unsupported operations (in either the CSS or SVGFE path).
     38  BLOB_FALLBACK = 2,
     39  // Image will be rendered using a simple CSS filter chain in WebRender.
     40  CHAIN = 3,
     41  // Filter graph will be rendered using WebRender SVGFE code path, this can
     42  // handle any kind of filter graph consisting of supported operations (most
     43  // operations are supported).
     44  SVGFE = 4,
     45 };
     46 
     47 struct WrFiltersHolder {
     48  // TODO(Bug 1899691): Better to use AutoTArray here...
     49  nsTArray<mozilla::wr::FilterOp> filters;
     50  nsTArray<mozilla::wr::WrFilterData> filter_datas;
     51  mozilla::Maybe<nsRect> post_filters_clip;
     52  // This exists just to own the values long enough for them to be copied into
     53  // rust.
     54  nsTArray<nsTArray<float>> values;
     55 };
     56 
     57 namespace mozilla {
     58 class nsDisplayList;
     59 class nsDisplayListBuilder;
     60 
     61 /**
     62 * Whether we're dealing with a backdrop-filter or a filter.
     63 */
     64 enum class StyleFilterType : uint8_t { BackdropFilter, Filter };
     65 
     66 namespace gfx {
     67 class DrawTarget;
     68 }  // namespace gfx
     69 
     70 /**
     71 * Integration of SVG effects (clipPath clipping, masking and filters) into
     72 * regular display list based painting and hit-testing.
     73 */
     74 class SVGIntegrationUtils final {
     75  using DrawTarget = gfx::DrawTarget;
     76  using IntRect = gfx::IntRect;
     77  using imgDrawingParams = image::imgDrawingParams;
     78 
     79 public:
     80  /**
     81   * Returns true if SVG effects that affect the overflow of the given frame
     82   * are currently applied to the frame.
     83   */
     84  static bool UsingOverflowAffectingEffects(const nsIFrame* aFrame);
     85 
     86  /**
     87   * Returns true if SVG effects are currently applied to this frame.
     88   */
     89  static bool UsingEffectsForFrame(const nsIFrame* aFrame);
     90 
     91  /**
     92   * Returns the size of the union of the border-box rects of all of
     93   * aNonSVGFrame's continuations.
     94   */
     95  static nsSize GetContinuationUnionSize(nsIFrame* aNonSVGFrame);
     96 
     97  /**
     98   * When SVG effects need to resolve percentage, userSpaceOnUse lengths, they
     99   * need a coordinate context to resolve them against. This method provides
    100   * that coordinate context for non-SVG frames with SVG effects applied to
    101   * them. The gfxSize returned is the size of the union of all of the given
    102   * frame's continuations' border boxes, converted to SVG user units (equal to
    103   * CSS px units), as required by the SVG code.
    104   */
    105  static gfx::Size GetSVGCoordContextForNonSVGFrame(nsIFrame* aNonSVGFrame);
    106 
    107  /**
    108   * SVG effects such as SVG filters, masking and clipPath may require an SVG
    109   * "bbox" for the element they're being applied to in order to make decisions
    110   * about positioning, and to resolve various lengths against. This method
    111   * provides the "bbox" for non-SVG frames. The bbox returned is in CSS px
    112   * units, and aUnionContinuations decide whether bbox contains the area of
    113   * current frame only or the union of all aNonSVGFrame's continuations'
    114   * overflow areas, relative to the top-left of the union of all aNonSVGFrame's
    115   * continuations' border box rects.
    116   */
    117  static gfxRect GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame,
    118                                          bool aUnionContinuations);
    119 
    120  /**
    121   * Used to adjust a frame's pre-effects ink overflow rect to take account
    122   * of SVG effects.
    123   *
    124   * XXX This method will not do the right thing for frames with continuations.
    125   * It really needs all the continuations to have been reflowed before being
    126   * called, but we currently call it on each continuation as its overflow
    127   * rects are set during the reflow of each particular continuation. Gecko's
    128   * current reflow architecture does not allow us to set the overflow rects
    129   * for a whole chain of continuations for a given element at the point when
    130   * the last continuation is reflowed. See:
    131   * http://groups.google.com/group/mozilla.dev.tech.layout/msg/6b179066f3051f65
    132   */
    133  static nsRect ComputePostEffectsInkOverflowRect(
    134      nsIFrame* aFrame, const nsRect& aPreEffectsOverflowRect);
    135 
    136  /**
    137   * Figure out which area of the source is needed given an area to
    138   * repaint
    139   */
    140  static nsRect GetRequiredSourceForInvalidArea(nsIFrame* aFrame,
    141                                                const nsRect& aDirtyRect);
    142 
    143  /**
    144   * Returns true if the given point is not clipped out by effects.
    145   * @param aPt in appunits relative to aFrame
    146   */
    147  static bool HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt);
    148 
    149  struct MOZ_STACK_CLASS PaintFramesParams {
    150    gfxContext& ctx;
    151    nsIFrame* frame;
    152    nsRect dirtyRect;
    153    nsRect borderArea;
    154    nsDisplayListBuilder* builder;
    155    bool handleOpacity;  // If true, PaintMaskAndClipPath/ PaintFilter should
    156                         // apply css opacity.
    157    Maybe<LayoutDeviceRect> maskRect;
    158    imgDrawingParams& imgParams;
    159 
    160    explicit PaintFramesParams(gfxContext& aCtx, nsIFrame* aFrame,
    161                               const nsRect& aDirtyRect,
    162                               const nsRect& aBorderArea,
    163                               nsDisplayListBuilder* aBuilder,
    164                               bool aHandleOpacity,
    165                               imgDrawingParams& aImgParams)
    166        : ctx(aCtx),
    167          frame(aFrame),
    168          dirtyRect(aDirtyRect),
    169          borderArea(aBorderArea),
    170          builder(aBuilder),
    171          handleOpacity(aHandleOpacity),
    172          imgParams(aImgParams) {}
    173  };
    174 
    175  // This should use FunctionRef instead of std::function because we don't need
    176  // to take ownership of the function. See bug 1490781.
    177  static void PaintMaskAndClipPath(const PaintFramesParams& aParams,
    178                                   const std::function<void()>& aPaintChild);
    179 
    180  /**
    181   * Paint mask of frame onto a given context, aParams.ctx.
    182   * aParams.ctx must contain an A8 surface. Returns false if the mask
    183   * didn't get painted and should be ignored at the call site.
    184   * isMaskComplete is an outparameter returning whether the mask is complete.
    185   * Incomplete masks should not be drawn and the proper fallback behaviour
    186   * depends on if the masked element is html or svg.
    187   */
    188  static bool PaintMask(const PaintFramesParams& aParams,
    189                        bool& aOutIsMaskComplete);
    190 
    191  /**
    192   * Paint the frame contents.
    193   * SVG frames will have had matrix propagation set to false already.
    194   * Non-SVG frames have to do their own thing.
    195   * The caller will do a Save()/Restore() as necessary so feel free
    196   * to mess with context state.
    197   * The context will be configured to use the "user space" coordinate
    198   * system if passing aTransform/aDirtyRect, or untouched otherwise.
    199   * @param aImgParams the params to draw with.
    200   * @param aTransform the user-to-device space matrix, if painting with
    201   *        filters.
    202   * @param aDirtyRect the dirty rect *in user space pixels*
    203   */
    204  using SVGFilterPaintCallback = std::function<void(
    205      gfxContext& aContext, imgDrawingParams&, const gfxMatrix* aTransform,
    206      const nsIntRect* aDirtyRect)>;
    207 
    208  /**
    209   * Paint non-SVG frame with filter and opacity effect.
    210   */
    211  static void PaintFilter(const PaintFramesParams& aParams,
    212                          Span<const StyleFilter> aFilters,
    213                          const SVGFilterPaintCallback& aCallback);
    214 
    215  /**
    216   * Build WebRender filters for a frame with CSS filters applied to it.
    217   */
    218  static WrFiltersStatus CreateWebRenderCSSFilters(
    219      Span<const StyleFilter> aFilters, nsIFrame* aFrame,
    220      WrFiltersHolder& aWrFilters);
    221 
    222  /**
    223   * Try to build WebRender filters for a frame with SVG filters applied to it
    224   * if the filters are supported.
    225   */
    226  static WrFiltersStatus BuildWebRenderFilters(
    227      nsIFrame* aFilteredFrame, Span<const StyleFilter> aFilters,
    228      StyleFilterType aStyleFilterType, WrFiltersHolder& aWrFilters,
    229      const nsPoint& aOffsetForSVGFilters);
    230 
    231  /**
    232   * Check if the filters present on |aFrame| are supported by WebRender.
    233   */
    234  static bool CanCreateWebRenderFiltersForFrame(nsIFrame* aFrame);
    235 
    236  /**
    237   * Check if |aFrame| uses any SVG effects that cannot be rendered in the
    238   * compositor.
    239   */
    240  static bool UsesSVGEffectsNotSupportedInCompositor(nsIFrame* aFrame);
    241 
    242  /**
    243   * @param aRenderingContext the target rendering context in which the paint
    244   * server will be rendered
    245   * @param aTarget the target frame onto which the paint server will be
    246   * rendered
    247   * @param aPaintServer a first-continuation frame to use as the source
    248   * @param aFilter a filter to be applied when scaling
    249   * @param aDest the area the paint server image should be mapped to
    250   * @param aFill the area to be filled with copies of the paint server image
    251   * @param aAnchor a point in aFill which we will ensure is pixel-aligned in
    252   * the output
    253   * @param aDirty pixels outside this area may be skipped
    254   * @param aPaintServerSize the size that would be filled when using
    255   * background-repeat:no-repeat and background-size:auto. For normal background
    256   * images, this would be the intrinsic size of the image; for gradients and
    257   * patterns this would be the whole target frame fill area.
    258   * @param aFlags pass SyncDecodeImages and any images in the paint
    259   * server will be decoding synchronously if they are not decoded already.
    260   */
    261  enum class DecodeFlag {
    262    SyncDecodeImages,
    263  };
    264  using DecodeFlags = EnumSet<DecodeFlag>;
    265 
    266  static already_AddRefed<gfxDrawable> DrawableFromPaintServer(
    267      nsIFrame* aFrame, nsIFrame* aTarget, const nsSize& aPaintServerSize,
    268      const gfx::IntSize& aRenderSize, const DrawTarget* aDrawTarget,
    269      const gfxMatrix& aContextMatrix, DecodeFlags aFlags);
    270 
    271  /**
    272   * For non-SVG frames, this gives the offset to the frame's "user space".
    273   * For SVG frames, this returns a zero offset.
    274   */
    275  static nsPoint GetOffsetToBoundingBox(nsIFrame* aFrame);
    276 
    277  /**
    278   * The offset between the reference frame and the bounding box of the
    279   * target frame in device units.
    280   */
    281  static gfxPoint GetOffsetToUserSpaceInDevPx(nsIFrame* aFrame,
    282                                              const PaintFramesParams& aParams);
    283 };
    284 
    285 }  // namespace mozilla
    286 
    287 #endif  // LAYOUT_SVG_SVGINTEGRATIONUTILS_H_