michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef __NS_FILTERINSTANCE_H__ michael@0: #define __NS_FILTERINSTANCE_H__ michael@0: michael@0: #include "gfxMatrix.h" michael@0: #include "gfxPoint.h" michael@0: #include "gfxRect.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsHashKeys.h" michael@0: #include "nsPoint.h" michael@0: #include "nsRect.h" michael@0: #include "nsSize.h" michael@0: #include "nsSVGFilters.h" michael@0: #include "nsSVGNumber2.h" michael@0: #include "nsSVGNumberPair.h" michael@0: #include "nsTArray.h" michael@0: #include "nsIFrame.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: michael@0: class gfxASurface; michael@0: class nsIFrame; michael@0: class nsSVGFilterPaintCallback; michael@0: michael@0: /** michael@0: * This class performs all filter processing. michael@0: * michael@0: * We build a graph of the filter image data flow, essentially michael@0: * converting the filter graph to SSA. This lets us easily propagate michael@0: * analysis data (such as bounding-boxes) over the filter primitive graph. michael@0: * michael@0: * Definition of "filter space": filter space is a coordinate system that is michael@0: * aligned with the user space of the filtered element, with its origin located michael@0: * at the top left of the filter region, and with one unit equal in size to one michael@0: * pixel of the offscreen surface into which the filter output would/will be michael@0: * painted. michael@0: * michael@0: * The definition of "filter region" can be found here: michael@0: * http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion michael@0: */ michael@0: class nsFilterInstance michael@0: { michael@0: typedef mozilla::gfx::IntRect IntRect; michael@0: typedef mozilla::gfx::SourceSurface SourceSurface; michael@0: typedef mozilla::gfx::DrawTarget DrawTarget; michael@0: typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription; michael@0: michael@0: public: michael@0: /** michael@0: * Paint the given filtered frame. michael@0: * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's michael@0: * frame space (i.e. relative to its origin, the top-left corner of its michael@0: * border box). michael@0: */ michael@0: static nsresult PaintFilteredFrame(nsRenderingContext *aContext, michael@0: nsIFrame *aFilteredFrame, michael@0: nsSVGFilterPaintCallback *aPaintCallback, michael@0: const nsRegion* aDirtyArea, michael@0: nsIFrame* aTransformRoot = nullptr); michael@0: michael@0: /** michael@0: * Returns the post-filter area that could be dirtied when the given michael@0: * pre-filter area of aFilteredFrame changes. michael@0: * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that has michael@0: * changed, relative to aFilteredFrame, in app units. michael@0: */ michael@0: static nsRegion GetPostFilterDirtyArea(nsIFrame *aFilteredFrame, michael@0: const nsRegion& aPreFilterDirtyRegion); michael@0: michael@0: /** michael@0: * Returns the pre-filter area that is needed from aFilteredFrame when the michael@0: * given post-filter area needs to be repainted. michael@0: * @param aPostFilterDirtyRegion The post-filter area that is dirty, relative michael@0: * to aFilteredFrame, in app units. michael@0: */ michael@0: static nsRegion GetPreFilterNeededArea(nsIFrame *aFilteredFrame, michael@0: const nsRegion& aPostFilterDirtyRegion); michael@0: michael@0: /** michael@0: * Returns the post-filter visual overflow rect (paint bounds) of michael@0: * aFilteredFrame. michael@0: * @param aOverrideBBox A user space rect, in user units, that should be used michael@0: * as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null. michael@0: * @param aPreFilterBounds The pre-filter visual overflow rect of michael@0: * aFilteredFrame, if non-null. michael@0: */ michael@0: static nsRect GetPostFilterBounds(nsIFrame *aFilteredFrame, michael@0: const gfxRect *aOverrideBBox = nullptr, michael@0: const nsRect *aPreFilterBounds = nullptr); michael@0: michael@0: /** michael@0: * @param aTargetFrame The frame of the filtered element under consideration. michael@0: * @param aPaintCallback [optional] The callback that Render() should use to michael@0: * paint. Only required if you will call Render(). michael@0: * @param aPostFilterDirtyRegion [optional] The post-filter area michael@0: * that has to be repainted, in app units. Only required if you will michael@0: * call ComputeSourceNeededRect() or Render(). michael@0: * @param aPreFilterDirtyRegion [optional] The pre-filter area of michael@0: * the filtered element that changed, in app units. Only required if you michael@0: * will call ComputePostFilterDirtyRegion(). michael@0: * @param aOverridePreFilterVisualOverflowRect [optional] Use a different michael@0: * visual overflow rect for the target element. michael@0: * @param aOverrideBBox [optional] Use a different SVG bbox for the target michael@0: * element. michael@0: * @param aTransformRoot [optional] The transform root frame for painting. michael@0: */ michael@0: nsFilterInstance(nsIFrame *aTargetFrame, michael@0: nsSVGFilterPaintCallback *aPaintCallback, michael@0: const nsRegion *aPostFilterDirtyRegion = nullptr, michael@0: const nsRegion *aPreFilterDirtyRegion = nullptr, michael@0: const nsRect *aOverridePreFilterVisualOverflowRect = nullptr, michael@0: const gfxRect *aOverrideBBox = nullptr, michael@0: nsIFrame* aTransformRoot = nullptr); michael@0: michael@0: /** michael@0: * Returns true if the filter instance was created successfully. michael@0: */ michael@0: bool IsInitialized() const { return mInitialized; } michael@0: michael@0: /** michael@0: * Draws the filter output into aContext. The area that michael@0: * needs to be painted must have been specified before calling this method michael@0: * by passing it as the aPostFilterDirtyRegion argument to the michael@0: * nsFilterInstance constructor. michael@0: */ michael@0: nsresult Render(gfxContext* aContext); michael@0: michael@0: /** michael@0: * Sets the aPostFilterDirtyRegion outparam to the post-filter area in frame michael@0: * space that would be dirtied by mTargetFrame when a given michael@0: * pre-filter area of mTargetFrame is dirtied. The pre-filter area must have michael@0: * been specified before calling this method by passing it as the michael@0: * aPreFilterDirtyRegion argument to the nsFilterInstance constructor. michael@0: */ michael@0: nsresult ComputePostFilterDirtyRegion(nsRegion* aPostFilterDirtyRegion); michael@0: michael@0: /** michael@0: * Sets the aPostFilterExtents outparam to the post-filter bounds in frame michael@0: * space for the whole filter output. This is not necessarily equivalent to michael@0: * the area that would be dirtied in the result when the entire pre-filter michael@0: * area is dirtied, because some filter primitives can generate output michael@0: * without any input. michael@0: */ michael@0: nsresult ComputePostFilterExtents(nsRect* aPostFilterExtents); michael@0: michael@0: /** michael@0: * Sets the aDirty outparam to the pre-filter bounds in frame space of the michael@0: * area of mTargetFrame that is needed in order to paint the filtered output michael@0: * for a given post-filter dirtied area. The post-filter area must have been michael@0: * specified before calling this method by passing it as the aPostFilterDirtyRegion michael@0: * argument to the nsFilterInstance constructor. michael@0: */ michael@0: nsresult ComputeSourceNeededRect(nsRect* aDirty); michael@0: michael@0: michael@0: /** michael@0: * Returns the transform from filter space to outer- device space. michael@0: */ michael@0: gfxMatrix GetFilterSpaceToDeviceSpaceTransform() const { michael@0: return mFilterSpaceToDeviceSpaceTransform; michael@0: } michael@0: michael@0: private: michael@0: struct SourceInfo { michael@0: // Specifies which parts of the source need to be rendered. michael@0: // Set by ComputeNeededBoxes(). michael@0: nsIntRect mNeededBounds; michael@0: michael@0: // The surface that contains the input rendering. michael@0: // Set by BuildSourceImage / BuildSourcePaint. michael@0: mozilla::RefPtr mSourceSurface; michael@0: michael@0: // The position and size of mSourceSurface in filter space. michael@0: // Set by BuildSourceImage / BuildSourcePaint. michael@0: IntRect mSurfaceRect; michael@0: }; michael@0: michael@0: /** michael@0: * Creates a SourceSurface for either the FillPaint or StrokePaint graph michael@0: * nodes michael@0: */ michael@0: nsresult BuildSourcePaint(SourceInfo *aPrimitive, michael@0: gfxASurface* aTargetSurface, michael@0: DrawTarget* aTargetDT); michael@0: michael@0: /** michael@0: * Creates a SourceSurface for either the FillPaint and StrokePaint graph michael@0: * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and michael@0: * mStrokePaint.mSourceSurface respectively. michael@0: */ michael@0: nsresult BuildSourcePaints(gfxASurface* aTargetSurface, michael@0: DrawTarget* aTargetDT); michael@0: michael@0: /** michael@0: * Creates the SourceSurface for the SourceGraphic graph node, paints its michael@0: * contents, and assigns it to mSourceGraphic.mSourceSurface. michael@0: */ michael@0: nsresult BuildSourceImage(gfxASurface* aTargetSurface, michael@0: DrawTarget* aTargetDT); michael@0: michael@0: /** michael@0: * Build the list of FilterPrimitiveDescriptions that describes the filter's michael@0: * filter primitives and their connections. This populates michael@0: * mPrimitiveDescriptions and mInputImages. michael@0: */ michael@0: nsresult BuildPrimitives(); michael@0: michael@0: /** michael@0: * Add to the list of FilterPrimitiveDescriptions for a particular SVG michael@0: * reference filter or CSS filter. This populates mPrimitiveDescrs and michael@0: * mInputImages. michael@0: */ michael@0: nsresult BuildPrimitivesForFilter(const nsStyleFilter& aFilter); michael@0: michael@0: /** michael@0: * Computes the filter space bounds of the areas that we actually *need* from michael@0: * the filter sources, based on the value of mPostFilterDirtyRegion. michael@0: * This sets mNeededBounds on the corresponding SourceInfo structs. michael@0: */ michael@0: void ComputeNeededBoxes(); michael@0: michael@0: /** michael@0: * Compute the scale factors between user space and filter space. michael@0: */ michael@0: nsresult ComputeUserSpaceToFilterSpaceScale(); michael@0: michael@0: /** michael@0: * Transform a rect between user space and filter space. michael@0: */ michael@0: gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const; michael@0: gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const; michael@0: michael@0: /** michael@0: * Converts an nsRect or an nsRegion that is relative to a filtered frame's michael@0: * origin (i.e. the top-left corner of its border box) into filter space, michael@0: * rounding out. michael@0: * Returns the entire filter region if aRect / aRegion is null, or if the michael@0: * result is too large to be stored in an nsIntRect. michael@0: */ michael@0: nsIntRect FrameSpaceToFilterSpace(const nsRect* aRect) const; michael@0: nsIntRegion FrameSpaceToFilterSpace(const nsRegion* aRegion) const; michael@0: michael@0: /** michael@0: * Converts an nsIntRect or an nsIntRegion from filter space into the space michael@0: * that is relative to a filtered frame's origin (i.e. the top-left corner michael@0: * of its border box) in app units, rounding out. michael@0: */ michael@0: nsRect FilterSpaceToFrameSpace(const nsIntRect& aRect) const; michael@0: nsRegion FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const; michael@0: michael@0: /** michael@0: * Returns the transform from frame space to the coordinate space that michael@0: * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the michael@0: * top-left corner of its border box, aka the top left corner of its mRect. michael@0: */ michael@0: gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const; michael@0: michael@0: /** michael@0: * The frame for the element that is currently being filtered. michael@0: */ michael@0: nsIFrame* mTargetFrame; michael@0: michael@0: nsSVGFilterPaintCallback* mPaintCallback; michael@0: michael@0: /** michael@0: * The SVG bbox of the element that is being filtered, in user space. michael@0: */ michael@0: gfxRect mTargetBBox; michael@0: michael@0: /** michael@0: * The transform from filter space to outer- device space. michael@0: */ michael@0: gfxMatrix mFilterSpaceToDeviceSpaceTransform; michael@0: michael@0: /** michael@0: * Transform rects between filter space and frame space in CSS pixels. michael@0: */ michael@0: gfxMatrix mFilterSpaceToFrameSpaceInCSSPxTransform; michael@0: gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform; michael@0: michael@0: /** michael@0: * The "filter region", in the filtered element's user space. michael@0: */ michael@0: gfxRect mUserSpaceBounds; michael@0: nsIntRect mFilterSpaceBounds; michael@0: michael@0: /** michael@0: * The scale factors between user space and filter space. michael@0: */ michael@0: gfxSize mUserSpaceToFilterSpaceScale; michael@0: gfxSize mFilterSpaceToUserSpaceScale; michael@0: michael@0: /** michael@0: * Pre-filter paint bounds of the element that is being filtered, in filter michael@0: * space. michael@0: */ michael@0: nsIntRect mTargetBounds; michael@0: michael@0: /** michael@0: * The dirty area that needs to be repainted, in filter space. michael@0: */ michael@0: nsIntRegion mPostFilterDirtyRegion; michael@0: michael@0: /** michael@0: * The pre-filter area of the filtered element that changed, in filter space. michael@0: */ michael@0: nsIntRegion mPreFilterDirtyRegion; michael@0: michael@0: SourceInfo mSourceGraphic; michael@0: SourceInfo mFillPaint; michael@0: SourceInfo mStrokePaint; michael@0: nsIFrame* mTransformRoot; michael@0: nsTArray> mInputImages; michael@0: nsTArray mPrimitiveDescriptions; michael@0: int32_t mAppUnitsPerCSSPx; michael@0: bool mInitialized; michael@0: }; michael@0: michael@0: #endif