/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_GFX_DRAWTARGETD2D1_H_ #define MOZILLA_GFX_DRAWTARGETD2D1_H_ #include "2D.h" #include #include #include "PathD2D.h" #include "HelpersD2D.h" #include "mozilla/StaticPtr.h" #include #include #include struct IDWriteFactory; namespace mozilla { namespace gfx { class SourceSurfaceD2D1; const int32_t kLayerCacheSize1 = 5; class DrawTargetD2D1 : public DrawTarget { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetD2D1, override) DrawTargetD2D1(); virtual ~DrawTargetD2D1(); virtual bool IsValid() const override; virtual DrawTargetType GetType() const override { return DrawTargetType::HARDWARE_RASTER; } virtual BackendType GetBackendType() const override { return BackendType::DIRECT2D1_1; } virtual already_AddRefed Snapshot() override; virtual already_AddRefed IntoLuminanceSource( LuminanceType aLuminanceType, float aOpacity) override; virtual IntSize GetSize() const override { return mSize; } virtual void Flush() override; virtual void DrawSurface(SourceSurface* aSurface, const Rect& aDest, const Rect& aSource, const DrawSurfaceOptions& aSurfOptions, const DrawOptions& aOptions) override; virtual void DrawFilter(FilterNode* aNode, const Rect& aSourceRect, const Point& aDestPoint, const DrawOptions& aOptions = DrawOptions()) override; virtual void DrawSurfaceWithShadow(SourceSurface* aSurface, const Point& aDest, const ShadowOptions& aShadow, CompositionOp aOperator) override; virtual void ClearRect(const Rect& aRect) override; virtual void MaskSurface( const Pattern& aSource, SourceSurface* aMask, Point aOffset, const DrawOptions& aOptions = DrawOptions()) override; virtual void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect, const IntPoint& aDestination) override; virtual void FillRect(const Rect& aRect, const Pattern& aPattern, const DrawOptions& aOptions = DrawOptions()) override; virtual void FillRoundedRect( const RoundedRect& aRect, const Pattern& aPattern, const DrawOptions& aOptions = DrawOptions()) override; virtual void StrokeRect(const Rect& aRect, const Pattern& aPattern, const StrokeOptions& aStrokeOptions = StrokeOptions(), const DrawOptions& aOptions = DrawOptions()) override; virtual void StrokeLine(const Point& aStart, const Point& aEnd, const Pattern& aPattern, const StrokeOptions& aStrokeOptions = StrokeOptions(), const DrawOptions& aOptions = DrawOptions()) override; virtual void Stroke(const Path* aPath, const Pattern& aPattern, const StrokeOptions& aStrokeOptions = StrokeOptions(), const DrawOptions& aOptions = DrawOptions()) override; virtual void Fill(const Path* aPath, const Pattern& aPattern, const DrawOptions& aOptions = DrawOptions()) override; virtual void FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern, const DrawOptions& aOptions = DrawOptions()) override; virtual void Mask(const Pattern& aSource, const Pattern& aMask, const DrawOptions& aOptions = DrawOptions()) override; virtual void PushClip(const Path* aPath) override; virtual void PushClipRect(const Rect& aRect) override; virtual void PushDeviceSpaceClipRects(const IntRect* aRects, uint32_t aCount) override; virtual void PopClip() override; virtual bool RemoveAllClips() override; virtual void PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask, const Matrix& aMaskTransform, const IntRect& aBounds = IntRect(), bool aCopyBackground = false) override; virtual void PopLayer() override; virtual already_AddRefed CreateSourceSurfaceFromData( unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat) const override; virtual already_AddRefed OptimizeSourceSurface( SourceSurface* aSurface) const override; virtual already_AddRefed CreateSourceSurfaceFromNativeSurface( const NativeSurface& aSurface) const override { return nullptr; } virtual already_AddRefed CreateSimilarDrawTarget( const IntSize& aSize, SurfaceFormat aFormat) const override; virtual bool CanCreateSimilarDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) const override; virtual RefPtr CreateClippedDrawTarget( const Rect& aBounds, SurfaceFormat aFormat) override; virtual already_AddRefed CreatePathBuilder( FillRule aFillRule = FillRule::FILL_WINDING) const override; virtual already_AddRefed CreateGradientStops( GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode = ExtendMode::CLAMP) const override; virtual already_AddRefed CreateFilter(FilterType aType) override; virtual bool SupportsRegionClipping() const override { return false; } virtual bool IsCurrentGroupOpaque() override { return CurrentLayer().mIsOpaque; } virtual void* GetNativeSurface(NativeSurfaceType aType) override { return nullptr; } virtual void DetachAllSnapshots() override { MarkChanged(); } bool Init(const IntSize& aSize, SurfaceFormat aFormat); bool Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat); uint32_t GetByteSize() const; // This function will get an image for a surface, it may adjust the source // transform for any transformation of the resulting image relative to the // oritingal SourceSurface. By default, the surface and its transform are // interpreted in user-space, but may be specified in device-space instead. already_AddRefed GetImageForSurface( SourceSurface* aSurface, Matrix& aSourceTransform, ExtendMode aExtendMode, const IntRect* aSourceRect = nullptr, bool aUserSpace = true); already_AddRefed GetImageForSurface(SourceSurface* aSurface, ExtendMode aExtendMode) { Matrix mat; return GetImageForSurface(aSurface, mat, aExtendMode, nullptr); } static RefPtr factory(); static void CleanupD2D(); operator std::string() const { std::stringstream stream; stream << "DrawTargetD2D 1.1 (" << this << ")"; return stream.str(); } static uint32_t GetMaxSurfaceSize() { return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; } static uint64_t mVRAMUsageDT; static uint64_t mVRAMUsageSS; private: friend class SourceSurfaceD2D1; void FlushInternal(bool aHasDependencyMutex = false); bool EnsureInitialized(); typedef std::unordered_set TargetSet; // This function will mark the surface as changing, and make sure any // copy-on-write snapshots are notified. void MarkChanged(); bool ShouldClipTemporarySurfaceDrawing(CompositionOp aOp, const Pattern& aPattern, bool aClipIsComplex); bool PrepareForDrawing(CompositionOp aOp, const Pattern& aPattern); void FinalizeDrawing(CompositionOp aOp, const Pattern& aPattern); void FlushTransformToDC() { if (mTransformDirty) { mDC->SetTransform(D2DMatrix(mTransform)); mTransformDirty = false; } } void AddDependencyOnSource(SourceSurfaceD2D1* aSource); // Must be called with all clips popped and an identity matrix set. already_AddRefed GetImageForLayerContent( const IntRect* aBounds = nullptr, bool aShouldPreserveContent = true); ID2D1Image* CurrentTarget() { if (CurrentLayer().mCurrentList) { return CurrentLayer().mCurrentList; } return mBitmap; } // This returns the clipped geometry, in addition it returns aClipBounds which // represents the intersection of all pixel-aligned rectangular clips that // are currently set. The returned clipped geometry must be clipped by these // bounds to correctly reflect the total clip. This is in device space and // only for clips applied to the -current layer-. already_AddRefed GetClippedGeometry(IntRect* aClipBounds); already_AddRefed GetInverseClippedGeometry(); // This gives the device space clip rect applied to the -current layer-. bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned); void PopAllClips(); void PushAllClips(); void PushClipsToDC(ID2D1DeviceContext* aDC, bool aForceIgnoreAlpha = false, const D2D1_RECT_F& aMaxRect = D2D1::InfiniteRect()); void PopClipsFromDC(ID2D1DeviceContext* aDC); already_AddRefed CreateTransparentBlackBrush(); already_AddRefed GetSolidColorBrush( const D2D_COLOR_F& aColor); already_AddRefed CreateBrushForPattern(const Pattern& aPattern, Float aAlpha = 1.0f); void PushClipGeometry(ID2D1Geometry* aGeometry, const D2D1_MATRIX_3X2_F& aTransform, bool aPixelAligned = false); void PushD2DLayer(ID2D1DeviceContext* aDC, ID2D1Geometry* aGeometry, const D2D1_MATRIX_3X2_F& aTransform, bool aPixelAligned = false, bool aForceIgnoreAlpha = false, const D2D1_RECT_F& aLayerRect = D2D1::InfiniteRect()); // This function is used to determine if the mDC is still valid; if it is // stale, we should avoid using it to execute any draw commands. bool IsDeviceContextValid() const; IntSize mSize; RefPtr mCurrentClippedGeometry; // This is only valid if mCurrentClippedGeometry is non-null. And will // only be the intersection of all pixel-aligned retangular clips. This is in // device space. IntRect mCurrentClipBounds; mutable RefPtr mDC; RefPtr mBitmap; RefPtr mCommandList; RefPtr mSolidColorBrush; // We store this to prevent excessive SetTextRenderingParams calls. RefPtr mTextRenderingParams; // List of pushed clips. struct PushedClip { D2D1_RECT_F mBounds; // If mGeometry is non-null, the mTransform member will be used. D2D1_MATRIX_3X2_F mTransform; RefPtr mGeometry; // Indicates if mBounds, and when non-null, mGeometry with mTransform // applied, are pixel-aligned. bool mIsPixelAligned; }; // List of pushed layers. struct PushedLayer { PushedLayer() : mClipsArePushed(false), mIsOpaque(false), mOldPermitSubpixelAA(false) {} std::vector mPushedClips; RefPtr mCurrentList; // True if the current clip stack is pushed to the CurrentTarget(). bool mClipsArePushed; bool mIsOpaque; bool mOldPermitSubpixelAA; }; std::vector mPushedLayers; PushedLayer& CurrentLayer() { return mPushedLayers.back(); } // The latest snapshot of this surface. This needs to be told when this // target is modified. We keep it alive as a cache. RefPtr mSnapshot; std::shared_ptr mSnapshotLock; // A list of targets we need to flush when we're modified. TargetSet mDependentTargets; // A list of targets which have this object in their mDependentTargets set TargetSet mDependingOnTargets; uint32_t mUsedCommandListsSincePurge; uint32_t mTransformedGlyphsSinceLastPurge; // When a BlendEffect has been drawn to a command list, and that command list // is subsequently used -again- as an input to a blend effect for a command // list, this causes an infinite recursion inside D2D as it tries to resolve // the bounds. If we resolve the current command list before this happens we // can avoid the subsequent hang. (See bug 1293586) uint32_t mComplexBlendsWithListInList; static StaticRefPtr mFactory; // This value is uesed to verify if the DrawTarget is created by a stale // device. uint32_t mDeviceSeq; // List of effects we use bool EnsureLuminanceEffect(); RefPtr mLuminanceEffect; enum class InitState { Uninitialized, Success, Failure }; InitState mInitState; RefPtr mSurface; }; } // namespace gfx } // namespace mozilla #endif /* MOZILLA_GFX_DRAWTARGETD2D_H_ */