diff options
Diffstat (limited to 'drawinglayer')
-rw-r--r-- | drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx | 596 |
1 files changed, 307 insertions, 289 deletions
diff --git a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx index 2ed7ea526959..04c6b400039b 100644 --- a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx @@ -56,51 +56,44 @@ using namespace com::sun::star; namespace { -class ID2D1FactoryProvider +class ID2D1GlobalFactoryProvider { - ID2D1Factory* mpD2DFactory; + sal::systools::COMReference<ID2D1Factory> mpD2DFactory; public: - ID2D1FactoryProvider() + ID2D1GlobalFactoryProvider() : mpD2DFactory(nullptr) { - HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), - nullptr, reinterpret_cast<void**>(&mpD2DFactory)); + const HRESULT hr(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory), nullptr, + reinterpret_cast<void**>(&mpD2DFactory))); if (!SUCCEEDED(hr)) - mpD2DFactory = nullptr; + mpD2DFactory.clear(); } - ~ID2D1FactoryProvider() - { - if (mpD2DFactory) - mpD2DFactory->Release(); - } + ~ID2D1GlobalFactoryProvider() {} - ID2D1Factory* getID2D1Factory() const { return mpD2DFactory; } + sal::systools::COMReference<ID2D1Factory>& getID2D1Factory() { return mpD2DFactory; } }; -ID2D1FactoryProvider aID2D1FactoryProvider; +ID2D1GlobalFactoryProvider aID2D1GlobalFactoryProvider; class ID2D1GlobalRenderTargetProvider { - ID2D1DCRenderTarget* mpID2D1DCRenderTarget; + sal::systools::COMReference<ID2D1DCRenderTarget> mpID2D1DCRenderTarget; public: ID2D1GlobalRenderTargetProvider() - : mpID2D1DCRenderTarget(nullptr) + : mpID2D1DCRenderTarget() { } - ~ID2D1GlobalRenderTargetProvider() - { - if (mpID2D1DCRenderTarget) - mpID2D1DCRenderTarget->Release(); - } + ~ID2D1GlobalRenderTargetProvider() {} - ID2D1DCRenderTarget* getID2D1DCRenderTarget() const + sal::systools::COMReference<ID2D1DCRenderTarget>& getID2D1DCRenderTarget() { - if (nullptr == mpID2D1DCRenderTarget && aID2D1FactoryProvider.getID2D1Factory()) + if (!mpID2D1DCRenderTarget && aID2D1GlobalFactoryProvider.getID2D1Factory()) { const D2D1_RENDER_TARGET_PROPERTIES aRTProps(D2D1::RenderTargetProperties( D2D1_RENDER_TARGET_TYPE_DEFAULT, @@ -108,9 +101,8 @@ public: D2D1_ALPHA_MODE_IGNORE), //D2D1_ALPHA_MODE_PREMULTIPLIED), 0, 0, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT)); - const HRESULT hr(aID2D1FactoryProvider.getID2D1Factory()->CreateDCRenderTarget( - &aRTProps, - &(const_cast<ID2D1GlobalRenderTargetProvider*>(this)->mpID2D1DCRenderTarget))); + const HRESULT hr(aID2D1GlobalFactoryProvider.getID2D1Factory()->CreateDCRenderTarget( + &aRTProps, &mpID2D1DCRenderTarget)); // interestingly this ID2D1DCRenderTarget already works and can hold // created ID2D1Bitmap(s) in RenderTarget-specific form, *without* @@ -119,7 +111,7 @@ public: // to have a HDC that is valid during LO's lifetime. if (!SUCCEEDED(hr)) - const_cast<ID2D1GlobalRenderTargetProvider*>(this)->mpID2D1DCRenderTarget = nullptr; + mpID2D1DCRenderTarget.clear(); } return mpID2D1DCRenderTarget; @@ -131,24 +123,20 @@ ID2D1GlobalRenderTargetProvider aID2D1GlobalRenderTargetProvider; class SystemDependentData_ID2D1PathGeometry : public basegfx::SystemDependentData { private: - ID2D1PathGeometry* mpID2D1PathGeometry; + sal::systools::COMReference<ID2D1PathGeometry> mpID2D1PathGeometry; public: - SystemDependentData_ID2D1PathGeometry(ID2D1PathGeometry* pID2D1PathGeometry) + SystemDependentData_ID2D1PathGeometry( + sal::systools::COMReference<ID2D1PathGeometry>& rID2D1PathGeometry) : basegfx::SystemDependentData(Application::GetSystemDependentDataManager()) - , mpID2D1PathGeometry(pID2D1PathGeometry) + , mpID2D1PathGeometry(rID2D1PathGeometry) { } - ~SystemDependentData_ID2D1PathGeometry() + const sal::systools::COMReference<ID2D1PathGeometry>& getID2D1PathGeometry() const { - if (nullptr != getID2D1PathGeometry()) - { - mpID2D1PathGeometry->Release(); - } + return mpID2D1PathGeometry; } - - ID2D1PathGeometry* getID2D1PathGeometry() const { return mpID2D1PathGeometry; } virtual sal_Int64 estimateUsageInBytes() const override; }; @@ -156,10 +144,10 @@ sal_Int64 SystemDependentData_ID2D1PathGeometry::estimateUsageInBytes() const { sal_Int64 aRetval(0); - if (nullptr != getID2D1PathGeometry()) + if (getID2D1PathGeometry()) { UINT32 nCount(0); - HRESULT hr = getID2D1PathGeometry()->GetSegmentCount(&nCount); + const HRESULT hr(getID2D1PathGeometry()->GetSegmentCount(&nCount)); if (SUCCEEDED(hr)) { @@ -212,7 +200,8 @@ basegfx::B2DPoint impPixelSnap(const basegfx::B2DPolygon& rPolygon, return rPolygon.getB2DPoint(nIndex); } -void addB2DPolygonToPathGeometry(ID2D1GeometrySink* pSink, const basegfx::B2DPolygon& rPolygon, +void addB2DPolygonToPathGeometry(sal::systools::COMReference<ID2D1GeometrySink>& rSink, + const basegfx::B2DPolygon& rPolygon, const drawinglayer::geometry::ViewInformation2D* pViewInformation) { const sal_uInt32 nPointCount(rPolygon.count()); @@ -230,7 +219,7 @@ void addB2DPolygonToPathGeometry(ID2D1GeometrySink* pSink, const basegfx::B2DPol if (aEdge.isBezier()) { - pSink->AddBezier( + rSink->AddBezier( D2D1::BezierSegment(D2D1::Point2F(aEdge.getControlPointA().getX(), aEdge.getControlPointA().getY()), //C1 D2D1::Point2F(aEdge.getControlPointB().getX(), @@ -239,7 +228,7 @@ void addB2DPolygonToPathGeometry(ID2D1GeometrySink* pSink, const basegfx::B2DPol } else { - pSink->AddLine(D2D1::Point2F(aEndPoint.getX(), aEndPoint.getY())); + rSink->AddLine(D2D1::Point2F(aEndPoint.getX(), aEndPoint.getY())); } } } @@ -266,16 +255,17 @@ getOrCreatePathGeometry(const basegfx::B2DPolygon& rPolygon, } } - ID2D1PathGeometry* pID2D1PathGeometry(nullptr); - HRESULT hr = aID2D1FactoryProvider.getID2D1Factory()->CreatePathGeometry(&pID2D1PathGeometry); + sal::systools::COMReference<ID2D1PathGeometry> pID2D1PathGeometry; + HRESULT hr( + aID2D1GlobalFactoryProvider.getID2D1Factory()->CreatePathGeometry(&pID2D1PathGeometry)); const sal_uInt32 nPointCount(rPolygon.count()); if (SUCCEEDED(hr) && nPointCount) { - ID2D1GeometrySink* pSink = nullptr; + sal::systools::COMReference<ID2D1GeometrySink> pSink; hr = pID2D1PathGeometry->Open(&pSink); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pSink) { const basegfx::B2DPoint aStart(rViewInformation.getPixelSnapHairline() ? rPolygon.getB2DPoint(0) @@ -286,12 +276,11 @@ getOrCreatePathGeometry(const basegfx::B2DPolygon& rPolygon, addB2DPolygonToPathGeometry(pSink, rPolygon, &rViewInformation); pSink->EndFigure(rPolygon.isClosed() ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); pSink->Close(); - pSink->Release(); } } // add to buffering mechanism - if (nullptr != pID2D1PathGeometry) + if (pID2D1PathGeometry) { if (rViewInformation.getPixelSnapHairline() || nPointCount <= 4) { @@ -321,16 +310,17 @@ getOrCreateFillGeometry(const basegfx::B2DPolyPolygon& rPolyPolygon) return pSystemDependentData_ID2D1PathGeometry; } - ID2D1PathGeometry* pID2D1PathGeometry(nullptr); - HRESULT hr = aID2D1FactoryProvider.getID2D1Factory()->CreatePathGeometry(&pID2D1PathGeometry); + sal::systools::COMReference<ID2D1PathGeometry> pID2D1PathGeometry; + HRESULT hr( + aID2D1GlobalFactoryProvider.getID2D1Factory()->CreatePathGeometry(&pID2D1PathGeometry)); const sal_uInt32 nCount(rPolyPolygon.count()); if (SUCCEEDED(hr) && nCount) { - ID2D1GeometrySink* pSink = nullptr; + sal::systools::COMReference<ID2D1GeometrySink> pSink; hr = pID2D1PathGeometry->Open(&pSink); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pSink) { for (sal_uInt32 a(0); a < nCount; a++) { @@ -349,12 +339,11 @@ getOrCreateFillGeometry(const basegfx::B2DPolyPolygon& rPolyPolygon) } pSink->Close(); - pSink->Release(); } } // add to buffering mechanism - if (nullptr != pID2D1PathGeometry) + if (pID2D1PathGeometry) { return rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_ID2D1PathGeometry>( pID2D1PathGeometry); @@ -366,27 +355,21 @@ getOrCreateFillGeometry(const basegfx::B2DPolyPolygon& rPolyPolygon) class SystemDependentData_ID2D1Bitmap : public basegfx::SystemDependentData { private: - ID2D1Bitmap* mpD2DBitmap; + sal::systools::COMReference<ID2D1Bitmap> mpD2DBitmap; const std::shared_ptr<SalBitmap> maAssociatedAlpha; public: - SystemDependentData_ID2D1Bitmap(ID2D1Bitmap* pD2DBitmap, + SystemDependentData_ID2D1Bitmap(sal::systools::COMReference<ID2D1Bitmap>& rD2DBitmap, const std::shared_ptr<SalBitmap>& rAssociatedAlpha) : basegfx::SystemDependentData(Application::GetSystemDependentDataManager()) - , mpD2DBitmap(pD2DBitmap) + , mpD2DBitmap(rD2DBitmap) , maAssociatedAlpha(rAssociatedAlpha) { } - ~SystemDependentData_ID2D1Bitmap() - { - if (nullptr != getID2D1Bitmap()) - { - mpD2DBitmap->Release(); - } - } + ~SystemDependentData_ID2D1Bitmap() {} - ID2D1Bitmap* getID2D1Bitmap() const { return mpD2DBitmap; } + const sal::systools::COMReference<ID2D1Bitmap>& getID2D1Bitmap() const { return mpD2DBitmap; } const std::shared_ptr<SalBitmap>& getAssociatedAlpha() const { return maAssociatedAlpha; } virtual sal_Int64 estimateUsageInBytes() const override; @@ -396,8 +379,9 @@ sal_Int64 SystemDependentData_ID2D1Bitmap::estimateUsageInBytes() const { sal_Int64 aRetval(0); - if (nullptr != getID2D1Bitmap()) + if (getID2D1Bitmap()) { + // use factor 4 for RGBA_8 as estimation const D2D1_SIZE_U aSizePixel(getID2D1Bitmap()->GetPixelSize()); aRetval = static_cast<sal_Int64>(aSizePixel.width) * static_cast<sal_Int64>(aSizePixel.height) * 4; @@ -406,7 +390,7 @@ sal_Int64 SystemDependentData_ID2D1Bitmap::estimateUsageInBytes() const return aRetval; } -ID2D1Bitmap* createB2DBitmap(const BitmapEx& rBitmapEx) +sal::systools::COMReference<ID2D1Bitmap> createB2DBitmap(const BitmapEx& rBitmapEx) { const Size& rSizePixel(rBitmapEx.GetSizePixel()); const bool bAlpha(rBitmapEx.IsAlpha()); @@ -453,35 +437,34 @@ ID2D1Bitmap* createB2DBitmap(const BitmapEx& rBitmapEx) } } - // use GlobalRenderTraget to allow usage combined with + // use GlobalRenderTarget to allow usage combined with // the Direct2D CreateSharedBitmap-mechanism. This is needed // since ID2D1Bitmap is a ID2D1RenderTarget-dependent resource // and thus - in principle - would have to be re-created for // *each* new ID2D1RenderTarget, that means for *each* new // target HDC, resp. OutputDevice - ID2D1DCRenderTarget* pGlobalRenderTraget( - aID2D1GlobalRenderTargetProvider.getID2D1DCRenderTarget()); - ID2D1Bitmap* pID2D1Bitmap(nullptr); + sal::systools::COMReference<ID2D1Bitmap> pID2D1Bitmap; - if (nullptr != pGlobalRenderTraget) + if (aID2D1GlobalRenderTargetProvider.getID2D1DCRenderTarget()) { - HRESULT hr = pGlobalRenderTraget->CreateBitmap( + const HRESULT hr(aID2D1GlobalRenderTargetProvider.getID2D1DCRenderTarget()->CreateBitmap( D2D1::SizeU(rSizePixel.Width(), rSizePixel.Height()), &aData[0], rSizePixel.Width() * sizeof(sal_uInt32), D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, // DXGI_FORMAT bAlpha ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE)), // D2D1_ALPHA_MODE - &pID2D1Bitmap); + &pID2D1Bitmap)); if (!SUCCEEDED(hr)) - return nullptr; + pID2D1Bitmap.clear(); } return pID2D1Bitmap; } -ID2D1Bitmap* getOrCreateB2DBitmap(ID2D1RenderTarget& rRT, const BitmapEx& rBitmapEx) +sal::systools::COMReference<ID2D1Bitmap> +getOrCreateB2DBitmap(sal::systools::COMReference<ID2D1RenderTarget>& rRT, const BitmapEx& rBitmapEx) { const basegfx::SystemDependentDataHolder* pHolder( rBitmapEx.GetBitmap().accessSystemDependentDataHolder()); @@ -508,9 +491,9 @@ ID2D1Bitmap* getOrCreateB2DBitmap(ID2D1RenderTarget& rRT, const BitmapEx& rBitma if (!pSystemDependentData_ID2D1Bitmap) { // have to create newly - ID2D1Bitmap* pID2D1Bitmap(createB2DBitmap(rBitmapEx)); + sal::systools::COMReference<ID2D1Bitmap> pID2D1Bitmap(createB2DBitmap(rBitmapEx)); - if (nullptr != pID2D1Bitmap) + if (pID2D1Bitmap) { // creation worked, create SystemDependentData_ID2D1Bitmap pSystemDependentData_ID2D1Bitmap = std::make_shared<SystemDependentData_ID2D1Bitmap>( @@ -527,21 +510,22 @@ ID2D1Bitmap* getOrCreateB2DBitmap(ID2D1RenderTarget& rRT, const BitmapEx& rBitma } } + sal::systools::COMReference<ID2D1Bitmap> pWrappedD2DBitmap; + if (pSystemDependentData_ID2D1Bitmap) { // embed to CreateSharedBitmap, that makes it usable on // the specified RenderTarget - ID2D1Bitmap* pWrappedD2DBitmap(nullptr); - HRESULT hr(rRT.CreateSharedBitmap( + const HRESULT hr(rRT->CreateSharedBitmap( __uuidof(ID2D1Bitmap), static_cast<void*>(pSystemDependentData_ID2D1Bitmap->getID2D1Bitmap()), nullptr, &pWrappedD2DBitmap)); - if (SUCCEEDED(hr)) - return pWrappedD2DBitmap; + if (!SUCCEEDED(hr)) + pWrappedD2DBitmap.clear(); } - return nullptr; + return pWrappedD2DBitmap; } // This is a simple local derivation of D2DPixelProcessor2D to be used @@ -551,21 +535,19 @@ ID2D1Bitmap* getOrCreateB2DBitmap(ID2D1RenderTarget& rRT, const BitmapEx& rBitma // (you need to call process() with the primitives to be painted of // course). Then use the local helper getID2D1Bitmap() to access the // ID2D1Bitmap which was the target of that operation. -// The class does not need to call mpBitmapRenderTarget->Release() since -// mpRT of parent is set to it and that calls Release() already in its -// destructor, so no destructor needed here. class D2DBitmapPixelProcessor2D final : public drawinglayer::processor2d::D2DPixelProcessor2D { // the local ID2D1BitmapRenderTarget - ID2D1BitmapRenderTarget* mpBitmapRenderTarget; + sal::systools::COMReference<ID2D1BitmapRenderTarget> mpBitmapRenderTarget; public: // helper class to create another instance of D2DPixelProcessor2D for // creating helper-ID2D1Bitmap's for a given ID2D1RenderTarget D2DBitmapPixelProcessor2D(const drawinglayer::geometry::ViewInformation2D& rViewInformation, - sal_uInt32 nWidth, sal_uInt32 nHeight, ID2D1RenderTarget& rParent) + sal_uInt32 nWidth, sal_uInt32 nHeight, + sal::systools::COMReference<ID2D1RenderTarget>& rParent) : drawinglayer::processor2d::D2DPixelProcessor2D(rViewInformation) - , mpBitmapRenderTarget(nullptr) + , mpBitmapRenderTarget() { if (0 == nWidth || 0 == nHeight) { @@ -577,7 +559,7 @@ public: { // Allocate compatible RGBA render target const D2D1_SIZE_U aRenderTargetSizePixel(D2D1::SizeU(nWidth, nHeight)); - HRESULT hr(rParent.CreateCompatibleRenderTarget( + const HRESULT hr(rParent->CreateCompatibleRenderTarget( nullptr, &aRenderTargetSizePixel, nullptr, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &mpBitmapRenderTarget)); @@ -588,30 +570,33 @@ public: } else { - setRenderTarget(mpBitmapRenderTarget); + sal::systools::COMReference<ID2D1RenderTarget> pRT; + mpBitmapRenderTarget->QueryInterface(__uuidof(ID2D1RenderTarget), + reinterpret_cast<void**>(&pRT)); + setRenderTarget(pRT); } } if (hasRenderTarget()) { // clear as render preparation - getRenderTarget().BeginDraw(); - getRenderTarget().Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)); - getRenderTarget().EndDraw(); + getRenderTarget()->BeginDraw(); + getRenderTarget()->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)); + getRenderTarget()->EndDraw(); } } - ID2D1Bitmap* getID2D1Bitmap() const + sal::systools::COMReference<ID2D1Bitmap> getID2D1Bitmap() const { + sal::systools::COMReference<ID2D1Bitmap> pResult; + // access the resulting bitmap if exists - if (nullptr != mpBitmapRenderTarget) + if (mpBitmapRenderTarget) { - ID2D1Bitmap* pInBetweenResult(nullptr); - mpBitmapRenderTarget->GetBitmap(&pInBetweenResult); - return pInBetweenResult; + mpBitmapRenderTarget->GetBitmap(&pResult); } - return nullptr; + return pResult; } }; } @@ -621,7 +606,7 @@ namespace drawinglayer::processor2d D2DPixelProcessor2D::D2DPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation) : BaseProcessor2D(rViewInformation) , maBColorModifierStack() - , mpRT(nullptr) + , mpRT() , mnRecursionCounter(0) , mnErrorCounter(0) { @@ -631,11 +616,11 @@ D2DPixelProcessor2D::D2DPixelProcessor2D(const geometry::ViewInformation2D& rVie HDC aHdc) : BaseProcessor2D(rViewInformation) , maBColorModifierStack() - , mpRT(nullptr) + , mpRT() , mnRecursionCounter(0) , mnErrorCounter(0) { - ID2D1DCRenderTarget* pDCRT = nullptr; + sal::systools::COMReference<ID2D1DCRenderTarget> pDCRT; tools::Long aOutWidth(0), aOutHeight(0); if (aHdc) @@ -644,7 +629,7 @@ D2DPixelProcessor2D::D2DPixelProcessor2D(const geometry::ViewInformation2D& rVie aOutHeight = GetDeviceCaps(aHdc, VERTRES); } - if (aOutWidth > 0 && aOutHeight > 0 && aID2D1FactoryProvider.getID2D1Factory()) + if (aOutWidth > 0 && aOutHeight > 0 && aID2D1GlobalFactoryProvider.getID2D1Factory()) { const D2D1_RENDER_TARGET_PROPERTIES aRTProps(D2D1::RenderTargetProperties( D2D1_RENDER_TARGET_TYPE_DEFAULT, @@ -653,12 +638,10 @@ D2DPixelProcessor2D::D2DPixelProcessor2D(const geometry::ViewInformation2D& rVie 0, 0, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT)); const HRESULT hr( - aID2D1FactoryProvider.getID2D1Factory()->CreateDCRenderTarget(&aRTProps, &pDCRT)); + aID2D1GlobalFactoryProvider.getID2D1Factory()->CreateDCRenderTarget(&aRTProps, &pDCRT)); if (!SUCCEEDED(hr)) - { - pDCRT = nullptr; - } + pDCRT.clear(); } if (pDCRT) @@ -668,10 +651,7 @@ D2DPixelProcessor2D::D2DPixelProcessor2D(const geometry::ViewInformation2D& rVie const HRESULT hr(pDCRT->BindDC(aHdc, &rc)); if (!SUCCEEDED(hr)) - { - pDCRT->Release(); - pDCRT = nullptr; - } + pDCRT.clear(); } if (pDCRT) @@ -701,7 +681,9 @@ D2DPixelProcessor2D::D2DPixelProcessor2D(const geometry::ViewInformation2D& rVie if (pDCRT) { - setRenderTarget(pDCRT); + sal::systools::COMReference<ID2D1RenderTarget> pRT; + pDCRT->QueryInterface(__uuidof(ID2D1RenderTarget), reinterpret_cast<void**>(&pRT)); + setRenderTarget(pRT); } else { @@ -709,19 +691,16 @@ D2DPixelProcessor2D::D2DPixelProcessor2D(const geometry::ViewInformation2D& rVie } } -D2DPixelProcessor2D::~D2DPixelProcessor2D() -{ - if (hasRenderTarget()) - getRenderTarget().Release(); -} - void D2DPixelProcessor2D::processPolygonHairlinePrimitive2D( const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D) { const basegfx::B2DPolygon& rPolygon(rPolygonHairlinePrimitive2D.getB2DPolygon()); if (!rPolygon.count()) + { + // no geometry, done return; + } bool bDone(false); std::shared_ptr<SystemDependentData_ID2D1PathGeometry> pSystemDependentData_ID2D1PathGeometry( @@ -729,41 +708,38 @@ void D2DPixelProcessor2D::processPolygonHairlinePrimitive2D( if (pSystemDependentData_ID2D1PathGeometry) { - ID2D1TransformedGeometry* pTransformedGeometry = nullptr; + sal::systools::COMReference<ID2D1TransformedGeometry> pTransformedGeometry; const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0); const basegfx::B2DHomMatrix& rObjectToView( getViewInformation2D().getObjectToViewTransformation()); - HRESULT hr = aID2D1FactoryProvider.getID2D1Factory()->CreateTransformedGeometry( + HRESULT hr(aID2D1GlobalFactoryProvider.getID2D1Factory()->CreateTransformedGeometry( pSystemDependentData_ID2D1PathGeometry->getID2D1PathGeometry(), D2D1::Matrix3x2F(rObjectToView.a(), rObjectToView.b(), rObjectToView.c(), rObjectToView.d(), rObjectToView.e() + fAAOffset, rObjectToView.f() + fAAOffset), - &pTransformedGeometry); + &pTransformedGeometry)); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pTransformedGeometry) { const basegfx::BColor aHairlineColor( maBColorModifierStack.getModifiedColor(rPolygonHairlinePrimitive2D.getBColor())); const D2D1::ColorF aD2DColor(aHairlineColor.getRed(), aHairlineColor.getGreen(), aHairlineColor.getBlue()); - ID2D1SolidColorBrush* pColorBrush(nullptr); - hr = getRenderTarget().CreateSolidColorBrush(aD2DColor, &pColorBrush); + sal::systools::COMReference<ID2D1SolidColorBrush> pColorBrush; + hr = getRenderTarget()->CreateSolidColorBrush(aD2DColor, &pColorBrush); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pColorBrush) { - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); // TODO: Unfortunately Direct2D paint of one pixel wide lines does not // correctly and completely blend 100% over the background. Experimenting // shows that a value around/slightly below 2.0 is needed which hints that // alpha blending the half-shifted lines (see fAAOffset above) is involved. // To get correct blending I try to use just wider hairlines for now. This // may need to be improved - or balanced (trying sqrt(2) now...) - getRenderTarget().DrawGeometry(pTransformedGeometry, pColorBrush, 1.44f); + getRenderTarget()->DrawGeometry(pTransformedGeometry, pColorBrush, 1.44f); bDone = true; - pColorBrush->Release(); } - - pTransformedGeometry->Release(); } } @@ -778,7 +754,10 @@ void D2DPixelProcessor2D::processPolyPolygonColorPrimitive2D( const sal_uInt32 nCount(rPolyPolygon.count()); if (!nCount) + { + // no geometry, done return; + } bool bDone(false); std::shared_ptr<SystemDependentData_ID2D1PathGeometry> pSystemDependentData_ID2D1PathGeometry( @@ -786,36 +765,33 @@ void D2DPixelProcessor2D::processPolyPolygonColorPrimitive2D( if (pSystemDependentData_ID2D1PathGeometry) { - ID2D1TransformedGeometry* pTransformedGeometry = nullptr; + sal::systools::COMReference<ID2D1TransformedGeometry> pTransformedGeometry; const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0); const basegfx::B2DHomMatrix& rObjectToView( getViewInformation2D().getObjectToViewTransformation()); - HRESULT hr = aID2D1FactoryProvider.getID2D1Factory()->CreateTransformedGeometry( + HRESULT hr(aID2D1GlobalFactoryProvider.getID2D1Factory()->CreateTransformedGeometry( pSystemDependentData_ID2D1PathGeometry->getID2D1PathGeometry(), D2D1::Matrix3x2F(rObjectToView.a(), rObjectToView.b(), rObjectToView.c(), rObjectToView.d(), rObjectToView.e() + fAAOffset, rObjectToView.f() + fAAOffset), - &pTransformedGeometry); + &pTransformedGeometry)); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pTransformedGeometry) { const basegfx::BColor aFillColor( maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor())); const D2D1::ColorF aD2DColor(aFillColor.getRed(), aFillColor.getGreen(), aFillColor.getBlue()); - ID2D1SolidColorBrush* pColorBrush(nullptr); - hr = getRenderTarget().CreateSolidColorBrush(aD2DColor, &pColorBrush); + sal::systools::COMReference<ID2D1SolidColorBrush> pColorBrush; + hr = getRenderTarget()->CreateSolidColorBrush(aD2DColor, &pColorBrush); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pColorBrush) { - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); - getRenderTarget().FillGeometry(pTransformedGeometry, pColorBrush); + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->FillGeometry(pTransformedGeometry, pColorBrush); bDone = true; - pColorBrush->Release(); } - - pTransformedGeometry->Release(); } } @@ -839,7 +815,7 @@ void D2DPixelProcessor2D::processBitmapPrimitive2D( if (!aUnitRange.overlaps(rDiscreteViewPort)) { - // content is outside discrete local ViewPort + // content is outside discrete local ViewPort, done return; } } @@ -848,16 +824,18 @@ void D2DPixelProcessor2D::processBitmapPrimitive2D( if (aBitmapEx.IsEmpty() || aBitmapEx.GetSizePixel().IsEmpty()) { + // no pixel data, done return; } if (maBColorModifierStack.count()) { + // need to apply ColorModifier to Bitmap data aBitmapEx = aBitmapEx.ModifyBitmapEx(maBColorModifierStack); if (aBitmapEx.IsEmpty()) { - // color gets completely replaced, get it + // color gets completely replaced, get it (any input works) const basegfx::BColor aModifiedColor( maBColorModifierStack.getModifiedColor(basegfx::BColor())); @@ -870,24 +848,25 @@ void D2DPixelProcessor2D::processBitmapPrimitive2D( new primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), aModifiedColor)); + // draw as Polygon, done processPolyPolygonColorPrimitive2D(*aTemp); return; } } bool bDone(false); - ID2D1Bitmap* pD2DBitmap(getOrCreateB2DBitmap(getRenderTarget(), aBitmapEx)); + sal::systools::COMReference<ID2D1Bitmap> pD2DBitmap( + getOrCreateB2DBitmap(getRenderTarget(), aBitmapEx)); - if (nullptr != pD2DBitmap) + if (pD2DBitmap) { const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0); - getRenderTarget().SetTransform(D2D1::Matrix3x2F( + getRenderTarget()->SetTransform(D2D1::Matrix3x2F( aLocalTransform.a(), aLocalTransform.b(), aLocalTransform.c(), aLocalTransform.d(), aLocalTransform.e() + fAAOffset, aLocalTransform.f() + fAAOffset)); // destinationRectangle is part of transformation above, so use UnitRange - getRenderTarget().DrawBitmap(pD2DBitmap, D2D1::RectF(0.0, 0.0, 1.0, 1.0)); - pD2DBitmap->Release(); + getRenderTarget()->DrawBitmap(pD2DBitmap, D2D1::RectF(0.0, 0.0, 1.0, 1.0)); bDone = true; } @@ -895,27 +874,28 @@ void D2DPixelProcessor2D::processBitmapPrimitive2D( increaseError(); } -ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_Direct( +sal::systools::COMReference<ID2D1Bitmap> D2DPixelProcessor2D::implCreateAlpha_Direct( const primitive2d::TransparencePrimitive2D& rTransCandidate, const basegfx::B2DRange& rVisibleRange) { // Try if we can use ID2D1DeviceContext/d2d1_1 by querying for interface. // Only then can we use ID2D1Effect/CLSID_D2D1LuminanceToAlpha and it makes // sense to try to do it this way in this implementation - ID2D1DeviceContext* pID2D1DeviceContext(nullptr); - getRenderTarget().QueryInterface(__uuidof(ID2D1DeviceContext), - reinterpret_cast<void**>(&pID2D1DeviceContext)); + sal::systools::COMReference<ID2D1DeviceContext> pID2D1DeviceContext; + getRenderTarget()->QueryInterface(__uuidof(ID2D1DeviceContext), + reinterpret_cast<void**>(&pID2D1DeviceContext)); + sal::systools::COMReference<ID2D1Bitmap> pRetval; - if (nullptr == pID2D1DeviceContext) + if (!pID2D1DeviceContext) { - // no, done - use fallback by returning empty - we have not the preconditions for this - return nullptr; + // no, done - tell caller to use fallback by returning empty - we have + // not the preconditions for this + return pRetval; } // Release early, was only a test and I saw comments in docu thatQueryInterface // does already increase that refcount - pID2D1DeviceContext->Release(); - pID2D1DeviceContext = nullptr; + pID2D1DeviceContext.clear(); // I had a former version (call it 'a') where I directly painted to a // alpha-only bitmap target, see aAlphaFormat below and refer to @@ -972,15 +952,14 @@ ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_Direct( if (!aSubContentRenderer.valid()) { // did not work, done - return nullptr; + return pRetval; } // render sub-content recursively aSubContentRenderer.process(rTransCandidate.getTransparence()); // grab Bitmap & prepare results from RGBA content rendering - ID2D1Bitmap* pInBetweenResult(aSubContentRenderer.getID2D1Bitmap()); - ID2D1Bitmap* pRetval(nullptr); + sal::systools::COMReference<ID2D1Bitmap> pInBetweenResult(aSubContentRenderer.getID2D1Bitmap()); // Now we need a target to render this to, using the ID2D1Effect tooling. // We can directly apply the effect to an alpha-only 8bit target here, @@ -989,12 +968,12 @@ ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_Direct( // to pContent again, but that does not work due to the bitmap // fetched being probably only an internal reference to the // ID2D1BitmapRenderTarget, thus it would draw onto itself -> chaos - ID2D1BitmapRenderTarget* pContent(nullptr); + sal::systools::COMReference<ID2D1BitmapRenderTarget> pContent; const D2D1_PIXEL_FORMAT aAlphaFormat( D2D1::PixelFormat(DXGI_FORMAT_A8_UNORM, D2D1_ALPHA_MODE_STRAIGHT)); const D2D1_SIZE_U aRenderTargetSizePixel( D2D1::SizeU(ceil(rVisibleRange.getWidth()), ceil(rVisibleRange.getHeight()))); - HRESULT hr(getRenderTarget().CreateCompatibleRenderTarget( + const HRESULT hr(getRenderTarget()->CreateCompatibleRenderTarget( nullptr, &aRenderTargetSizePixel, &aAlphaFormat, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &pContent)); @@ -1007,7 +986,7 @@ ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_Direct( if (pID2D1DeviceContext) { // create the effect - ID2D1Effect* pLuminanceToAlpha(nullptr); + sal::systools::COMReference<ID2D1Effect> pLuminanceToAlpha; pID2D1DeviceContext->CreateEffect(CLSID_D2D1LuminanceToAlpha, &pLuminanceToAlpha); if (pLuminanceToAlpha) @@ -1022,20 +1001,14 @@ ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_Direct( // grab result pContent->GetBitmap(&pRetval); - pLuminanceToAlpha->Release(); } - - pID2D1DeviceContext->Release(); } - - pContent->Release(); } - pInBetweenResult->Release(); return pRetval; } -ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_B2DBitmap( +sal::systools::COMReference<ID2D1Bitmap> D2DPixelProcessor2D::implCreateAlpha_B2DBitmap( const primitive2d::TransparencePrimitive2D& rTransCandidate, const basegfx::B2DRange& rVisibleRange, D2D1_MATRIX_3X2_F& rMaskScale) { @@ -1062,11 +1035,12 @@ ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_B2DBitmap( const AlphaMask aAlpha(::drawinglayer::createAlphaMask( std::move(xEmbedSeq), aEmptyViewInformation2D, nDiscreteClippedWidth, nDiscreteClippedHeight, nMaximumQuadraticPixels, true)); + sal::systools::COMReference<ID2D1Bitmap> pRetval; if (aAlpha.IsEmpty()) { // if we have no content we are done - return nullptr; + return pRetval; } // use alpha data to create the ID2D1Bitmap @@ -1088,19 +1062,16 @@ ID2D1Bitmap* D2DPixelProcessor2D::implCreateAlpha_B2DBitmap( } } - ID2D1Bitmap* pRetval(nullptr); const D2D1_BITMAP_PROPERTIES aBmProps(D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED))); - HRESULT hr = getRenderTarget().CreateBitmap( + const HRESULT hr(getRenderTarget()->CreateBitmap( D2D1::SizeU(rSizePixel.Width(), rSizePixel.Height()), &aData[0], - rSizePixel.Width() * sizeof(sal_uInt8), &aBmProps, &pRetval); + rSizePixel.Width() * sizeof(sal_uInt8), &aBmProps, &pRetval)); - // D2D1_BITMAP_PROPERTIES - - if (!SUCCEEDED(hr) || nullptr == pRetval) + if (!SUCCEEDED(hr) || !pRetval) { // did not work, done - return nullptr; + return pRetval; } // create needed adapted transformation for alpha brush. @@ -1129,16 +1100,22 @@ void D2DPixelProcessor2D::processTransparencePrimitive2D( const primitive2d::TransparencePrimitive2D& rTransCandidate) { if (rTransCandidate.getChildren().empty()) + { + // no content, done return; + } if (rTransCandidate.getTransparence().empty()) + { + // no mask (so nothing visible), done return; + } // calculate visible range, create only for that range basegfx::B2DRange aDiscreteRange( rTransCandidate.getChildren().getB2DRange(getViewInformation2D())); aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation()); - const D2D1_SIZE_U aB2DSizePixel(getRenderTarget().GetPixelSize()); + const D2D1_SIZE_U aB2DSizePixel(getRenderTarget()->GetPixelSize()); const basegfx::B2DRange aViewRange(0.0, 0.0, aB2DSizePixel.width, aB2DSizePixel.height); basegfx::B2DRange aVisibleRange(aDiscreteRange); aVisibleRange.intersect(aViewRange); @@ -1150,64 +1127,60 @@ void D2DPixelProcessor2D::processTransparencePrimitive2D( } // try to create directly, this needs the current mpRT to be a ID2D1DeviceContext/d2d1_1 - // what is not guaranteed but usually works for more modern windows (after 7) - ID2D1Bitmap* pAlphaBitmap(implCreateAlpha_Direct(rTransCandidate, aVisibleRange)); + // what is not guarenteed but usually works for more modern windows (after 7) + sal::systools::COMReference<ID2D1Bitmap> pAlphaBitmap( + implCreateAlpha_Direct(rTransCandidate, aVisibleRange)); D2D1_MATRIX_3X2_F aMaskScale(D2D1::Matrix3x2F::Identity()); - if (nullptr == pAlphaBitmap) + if (!pAlphaBitmap) { // did not work, use more expensive fallback to existing tooling pAlphaBitmap = implCreateAlpha_B2DBitmap(rTransCandidate, aVisibleRange, aMaskScale); } - if (nullptr == pAlphaBitmap) + if (!pAlphaBitmap) { // could not create alpha channel, error increaseError(); return; } - ID2D1Layer* pLayer = nullptr; - HRESULT hr = getRenderTarget().CreateLayer(nullptr, &pLayer); + sal::systools::COMReference<ID2D1Layer> pLayer; + HRESULT hr(getRenderTarget()->CreateLayer(nullptr, &pLayer)); bool bDone(false); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pLayer) { - ID2D1BitmapBrush* pBitmapBrush = nullptr; - hr = getRenderTarget().CreateBitmapBrush(pAlphaBitmap, &pBitmapBrush); + sal::systools::COMReference<ID2D1BitmapBrush> pBitmapBrush; + hr = getRenderTarget()->CreateBitmapBrush(pAlphaBitmap, &pBitmapBrush); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pBitmapBrush) { // apply MaskScale to Brush, maybe used if implCreateAlpha_B2DBitmap was needed pBitmapBrush->SetTransform(aMaskScale); // need to set transform offset for Layer initialization, we work // in discrete device coordinates - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Translation( + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Translation( floor(aVisibleRange.getMinX()), floor(aVisibleRange.getMinY()))); - getRenderTarget().PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr, - D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, - D2D1::Matrix3x2F::Identity(), 1.0, - pBitmapBrush), - pLayer); + getRenderTarget()->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr, + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, + D2D1::Matrix3x2F::Identity(), 1.0, + pBitmapBrush), + pLayer); // ... but need to reset to paint content unchanged - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); - // draw content + // draw content recursively process(rTransCandidate.getChildren()); - getRenderTarget().PopLayer(); + getRenderTarget()->PopLayer(); bDone = true; - pBitmapBrush->Release(); } - - pLayer->Release(); } - pAlphaBitmap->Release(); - if (!bDone) increaseError(); } @@ -1237,7 +1210,7 @@ void D2DPixelProcessor2D::processUnifiedTransparencePrimitive2D( basegfx::B2DRange aTransparencyRange( rTransCandidate.getChildren().getB2DRange(getViewInformation2D())); aTransparencyRange.transform(getViewInformation2D().getObjectToViewTransformation()); - const D2D1_SIZE_U aB2DSizePixel(getRenderTarget().GetPixelSize()); + const D2D1_SIZE_U aB2DSizePixel(getRenderTarget()->GetPixelSize()); const basegfx::B2DRange aViewRange(0.0, 0.0, aB2DSizePixel.width, aB2DSizePixel.height); // not visible, done @@ -1247,25 +1220,22 @@ void D2DPixelProcessor2D::processUnifiedTransparencePrimitive2D( } bool bDone(false); - ID2D1Layer* pLayer = nullptr; - HRESULT hr = getRenderTarget().CreateLayer(nullptr, &pLayer); + sal::systools::COMReference<ID2D1Layer> pLayer; + const HRESULT hr(getRenderTarget()->CreateLayer(nullptr, &pLayer)); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pLayer) { // need to set correct transform for Layer initialization, we work // in discrete device coordinates - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); - - getRenderTarget().PushLayer( + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->PushLayer( D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1::IdentityMatrix(), 1.0 - rTransCandidate.getTransparence()), // opacity pLayer); process(rTransCandidate.getChildren()); - getRenderTarget().PopLayer(); + getRenderTarget()->PopLayer(); bDone = true; - - pLayer->Release(); } if (!bDone) @@ -1276,20 +1246,29 @@ void D2DPixelProcessor2D::processMaskPrimitive2DPixel( const primitive2d::MaskPrimitive2D& rMaskCandidate) { if (rMaskCandidate.getChildren().empty()) + { + // no content, done return; + } basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); if (!aMask.count()) + { + // no mask (so nothing inside), done return; + } basegfx::B2DRange aMaskRange(aMask.getB2DRange()); aMaskRange.transform(getViewInformation2D().getObjectToViewTransformation()); - const D2D1_SIZE_U aB2DSizePixel(getRenderTarget().GetPixelSize()); + const D2D1_SIZE_U aB2DSizePixel(getRenderTarget()->GetPixelSize()); const basegfx::B2DRange aViewRange(0.0, 0.0, aB2DSizePixel.width, aB2DSizePixel.height); if (!aViewRange.overlaps(aMaskRange)) + { + // not in visible range, done return; + } bool bDone(false); std::shared_ptr<SystemDependentData_ID2D1PathGeometry> pSystemDependentData_ID2D1MaskGeometry( @@ -1297,36 +1276,31 @@ void D2DPixelProcessor2D::processMaskPrimitive2DPixel( if (pSystemDependentData_ID2D1MaskGeometry) { - ID2D1TransformedGeometry* pTransformedMaskGeometry = nullptr; + sal::systools::COMReference<ID2D1TransformedGeometry> pTransformedMaskGeometry; const basegfx::B2DHomMatrix& rObjectToView( getViewInformation2D().getObjectToViewTransformation()); - HRESULT hr = aID2D1FactoryProvider.getID2D1Factory()->CreateTransformedGeometry( + HRESULT hr(aID2D1GlobalFactoryProvider.getID2D1Factory()->CreateTransformedGeometry( pSystemDependentData_ID2D1MaskGeometry->getID2D1PathGeometry(), D2D1::Matrix3x2F(rObjectToView.a(), rObjectToView.b(), rObjectToView.c(), rObjectToView.d(), rObjectToView.e(), rObjectToView.f()), - &pTransformedMaskGeometry); + &pTransformedMaskGeometry)); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pTransformedMaskGeometry) { - ID2D1Layer* pLayer = nullptr; - hr = getRenderTarget().CreateLayer(nullptr, &pLayer); + sal::systools::COMReference<ID2D1Layer> pLayer; + hr = getRenderTarget()->CreateLayer(nullptr, &pLayer); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pLayer) { // need to set correct transform for Layer initialization, we work // in discrete device coordinates - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); - - getRenderTarget().PushLayer( + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->PushLayer( D2D1::LayerParameters(D2D1::InfiniteRect(), pTransformedMaskGeometry), pLayer); process(rMaskCandidate.getChildren()); - getRenderTarget().PopLayer(); + getRenderTarget()->PopLayer(); bDone = true; - - pLayer->Release(); } - - pTransformedMaskGeometry->Release(); } } @@ -1338,24 +1312,28 @@ void D2DPixelProcessor2D::processPointArrayPrimitive2D( const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate) { const std::vector<basegfx::B2DPoint>& rPositions(rPointArrayCandidate.getPositions()); + if (rPositions.empty()) + { + // no geometry, done return; + } const basegfx::BColor aPointColor( maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor())); - ID2D1SolidColorBrush* pColorBrush(nullptr); + sal::systools::COMReference<ID2D1SolidColorBrush> pColorBrush; D2D1::ColorF aD2DColor(aPointColor.getRed(), aPointColor.getGreen(), aPointColor.getBlue()); - HRESULT hr = getRenderTarget().CreateSolidColorBrush(aD2DColor, &pColorBrush); + const HRESULT hr(getRenderTarget()->CreateSolidColorBrush(aD2DColor, &pColorBrush)); bool bDone(false); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pColorBrush) { - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); // To really paint a single pixel I found nothing better than // switch off AA and draw a pixel-aligned rectangle - const D2D1_ANTIALIAS_MODE aOldAAMode(getRenderTarget().GetAntialiasMode()); - getRenderTarget().SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + const D2D1_ANTIALIAS_MODE aOldAAMode(getRenderTarget()->GetAntialiasMode()); + getRenderTarget()->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); for (auto const& pos : rPositions) { @@ -1365,12 +1343,11 @@ void D2DPixelProcessor2D::processPointArrayPrimitive2D( const double fY(ceil(aDiscretePos.getY())); const D2D1_RECT_F rect = { FLOAT(fX), FLOAT(fY), FLOAT(fX), FLOAT(fY) }; - getRenderTarget().DrawRectangle(&rect, pColorBrush); + getRenderTarget()->DrawRectangle(&rect, pColorBrush); } - getRenderTarget().SetAntialiasMode(aOldAAMode); + getRenderTarget()->SetAntialiasMode(aOldAAMode); bDone = true; - pColorBrush->Release(); } if (!bDone) @@ -1381,19 +1358,28 @@ void D2DPixelProcessor2D::processMarkerArrayPrimitive2D( const primitive2d::MarkerArrayPrimitive2D& rMarkerArrayCandidate) { const std::vector<basegfx::B2DPoint>& rPositions(rMarkerArrayCandidate.getPositions()); + if (rPositions.empty()) + { + // no geometry, done return; + } const BitmapEx& rMarker(rMarkerArrayCandidate.getMarker()); + if (rMarker.IsEmpty()) + { + // no marker defined, done return; + } - ID2D1Bitmap* pD2DBitmap(getOrCreateB2DBitmap(getRenderTarget(), rMarker)); + sal::systools::COMReference<ID2D1Bitmap> pD2DBitmap( + getOrCreateB2DBitmap(getRenderTarget(), rMarker)); bool bDone(false); - if (nullptr != pD2DBitmap) + if (pD2DBitmap) { - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); const Size& rSizePixel(rMarker.GetSizePixel()); const tools::Long nMiX((rSizePixel.Width() / 2) + 1); const tools::Long nMiY((rSizePixel.Height() / 2) + 1); @@ -1401,8 +1387,8 @@ void D2DPixelProcessor2D::processMarkerArrayPrimitive2D( const tools::Long nPlY(rSizePixel.Height() - nMiY); // draw with non-AA to show unhampered, clear, non-scaled marker - const D2D1_ANTIALIAS_MODE aOldAAMode(getRenderTarget().GetAntialiasMode()); - getRenderTarget().SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + const D2D1_ANTIALIAS_MODE aOldAAMode(getRenderTarget()->GetAntialiasMode()); + getRenderTarget()->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); for (auto const& pos : rPositions) { @@ -1413,12 +1399,11 @@ void D2DPixelProcessor2D::processMarkerArrayPrimitive2D( const D2D1_RECT_F rect = { FLOAT(fX - nMiX), FLOAT(fY - nMiY), FLOAT(fX + nPlX), FLOAT(fY + nPlY) }; - getRenderTarget().DrawBitmap(pD2DBitmap, &rect); + getRenderTarget()->DrawBitmap(pD2DBitmap, &rect); } - getRenderTarget().SetAntialiasMode(aOldAAMode); + getRenderTarget()->SetAntialiasMode(aOldAAMode); bDone = true; - pD2DBitmap->Release(); } if (!bDone) @@ -1438,7 +1423,7 @@ void D2DPixelProcessor2D::processBackgroundColorPrimitive2D( rBackgroundColorCandidate.getBColor().getBlue(), 1.0 - rBackgroundColorCandidate.getTransparency()); - getRenderTarget().Clear(aD2DColor); + getRenderTarget()->Clear(aD2DColor); } void D2DPixelProcessor2D::processModifiedColorPrimitive2D( @@ -1532,16 +1517,16 @@ void D2DPixelProcessor2D::processPolygonStrokePrimitive2D( if (pSystemDependentData_ID2D1PathGeometry) { - ID2D1TransformedGeometry* pTransformedGeometry = nullptr; + sal::systools::COMReference<ID2D1TransformedGeometry> pTransformedGeometry; const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0); - HRESULT hr = aID2D1FactoryProvider.getID2D1Factory()->CreateTransformedGeometry( + HRESULT hr(aID2D1GlobalFactoryProvider.getID2D1Factory()->CreateTransformedGeometry( pSystemDependentData_ID2D1PathGeometry->getID2D1PathGeometry(), D2D1::Matrix3x2F(rObjectToView.a(), rObjectToView.b(), rObjectToView.c(), rObjectToView.d(), rObjectToView.e() + fAAOffset, rObjectToView.f() + fAAOffset), - &pTransformedGeometry); + &pTransformedGeometry)); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pTransformedGeometry) { const basegfx::BColor aLineColor( maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); @@ -1553,12 +1538,12 @@ void D2DPixelProcessor2D::processPolygonStrokePrimitive2D( aD2DColor.a = 0.5; } - ID2D1SolidColorBrush* pColorBrush(nullptr); - hr = getRenderTarget().CreateSolidColorBrush(aD2DColor, &pColorBrush); + sal::systools::COMReference<ID2D1SolidColorBrush> pColorBrush; + hr = getRenderTarget()->CreateSolidColorBrush(aD2DColor, &pColorBrush); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pColorBrush) { - ID2D1StrokeStyle* pStrokeStyle(nullptr); + sal::systools::COMReference<ID2D1StrokeStyle> pStrokeStyle; D2D1_CAP_STYLE aCapStyle(D2D1_CAP_STYLE_FLAT); D2D1_LINE_JOIN aLineJoin(D2D1_LINE_JOIN_MITER); const attribute::StrokeAttribute& rStrokeAttribute( @@ -1598,7 +1583,7 @@ void D2DPixelProcessor2D::processPolygonStrokePrimitive2D( // nice, but not what we need or is the standard for other graphic systems. Luckily there // is also D2D1_LINE_JOIN_MITER_OR_BEVEL and (after some search) the page // https://learn.microsoft.com/en-us/windows/win32/api/d2d1/ne-d2d1-d2d1_line_join - // which gives some explanation, so that is what we need to use. + // which gives some explanation, so that is what we need to use here. // (2) Instead of using an angle in radians (15 deg default) MS uses // "miterLimit is relative to 1/2 LineWidth", so a length. After some experimenting // it shows that the (better understandable) angle has to be converted to the length @@ -1607,6 +1592,8 @@ void D2DPixelProcessor2D::processPolygonStrokePrimitive2D( // experimentally come to a correction value around 0.9925. Since that seems to // be no obvious numerical value involved somehow (and as long as I find no other // explanation) I will have to use that. + // NOTE: To find that correction value I usd that handy bRenderDecomposeForCompareInRed + // and changes in debugger - as work tipp // With both done I can use Direct2D for Miter completely - what is good for speed. aLineJoin = D2D1_LINE_JOIN_MITER_OR_BEVEL; @@ -1647,7 +1634,7 @@ void D2DPixelProcessor2D::processPolygonStrokePrimitive2D( } } - hr = aID2D1FactoryProvider.getID2D1Factory()->CreateStrokeStyle( + hr = aID2D1GlobalFactoryProvider.getID2D1Factory()->CreateStrokeStyle( D2D1::StrokeStyleProperties(aCapStyle, // startCap aCapStyle, // endCap aCapStyle, // dashCap @@ -1658,21 +1645,16 @@ void D2DPixelProcessor2D::processPolygonStrokePrimitive2D( bDashUsed ? dashes.data() : nullptr, bDashUsed ? dashes.size() : 0, &pStrokeStyle); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pStrokeStyle) { - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); - getRenderTarget().DrawGeometry( + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->DrawGeometry( pTransformedGeometry, pColorBrush, // TODO: Hairline LineWidth, see comment at processPolygonHairlinePrimitive2D bHairline ? 1.44 : fDiscreteLineWidth, pStrokeStyle); bDone = true; - pStrokeStyle->Release(); } - - pColorBrush->Release(); } - - pTransformedGeometry->Release(); } } @@ -1696,16 +1678,16 @@ void D2DPixelProcessor2D::processLineRectanglePrimitive2D( maBColorModifierStack.getModifiedColor(rLineRectanglePrimitive2D.getBColor())); const D2D1::ColorF aD2DColor(aHairlineColor.getRed(), aHairlineColor.getGreen(), aHairlineColor.getBlue()); - ID2D1SolidColorBrush* pColorBrush(nullptr); - HRESULT hr(getRenderTarget().CreateSolidColorBrush(aD2DColor, &pColorBrush)); + sal::systools::COMReference<ID2D1SolidColorBrush> pColorBrush; + const HRESULT hr(getRenderTarget()->CreateSolidColorBrush(aD2DColor, &pColorBrush)); bool bDone(false); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pColorBrush) { const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0); const basegfx::B2DHomMatrix aLocalTransform( getViewInformation2D().getObjectToViewTransformation()); - getRenderTarget().SetTransform(D2D1::Matrix3x2F( + getRenderTarget()->SetTransform(D2D1::Matrix3x2F( aLocalTransform.a(), aLocalTransform.b(), aLocalTransform.c(), aLocalTransform.d(), aLocalTransform.e() + fAAOffset, aLocalTransform.f() + fAAOffset)); const basegfx::B2DRange& rRange(rLineRectanglePrimitive2D.getB2DRange()); @@ -1716,7 +1698,7 @@ void D2DPixelProcessor2D::processLineRectanglePrimitive2D( * basegfx::B2DVector(1.44, 0.0)) .getLength()); - getRenderTarget().DrawRectangle(&rect, pColorBrush, fDiscreteLineWidth); + getRenderTarget()->DrawRectangle(&rect, pColorBrush, fDiscreteLineWidth); bDone = true; } @@ -1736,23 +1718,23 @@ void D2DPixelProcessor2D::processFilledRectanglePrimitive2D( const basegfx::BColor aFillColor( maBColorModifierStack.getModifiedColor(rFilledRectanglePrimitive2D.getBColor())); const D2D1::ColorF aD2DColor(aFillColor.getRed(), aFillColor.getGreen(), aFillColor.getBlue()); - ID2D1SolidColorBrush* pColorBrush(nullptr); - HRESULT hr(getRenderTarget().CreateSolidColorBrush(aD2DColor, &pColorBrush)); + sal::systools::COMReference<ID2D1SolidColorBrush> pColorBrush; + const HRESULT hr(getRenderTarget()->CreateSolidColorBrush(aD2DColor, &pColorBrush)); bool bDone(false); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pColorBrush) { const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0); const basegfx::B2DHomMatrix aLocalTransform( getViewInformation2D().getObjectToViewTransformation()); - getRenderTarget().SetTransform(D2D1::Matrix3x2F( + getRenderTarget()->SetTransform(D2D1::Matrix3x2F( aLocalTransform.a(), aLocalTransform.b(), aLocalTransform.c(), aLocalTransform.d(), aLocalTransform.e() + fAAOffset, aLocalTransform.f() + fAAOffset)); const basegfx::B2DRange& rRange(rFilledRectanglePrimitive2D.getB2DRange()); const D2D1_RECT_F rect = { FLOAT(rRange.getMinX()), FLOAT(rRange.getMinY()), FLOAT(rRange.getMaxX()), FLOAT(rRange.getMaxY()) }; - getRenderTarget().FillRectangle(&rect, pColorBrush); + getRenderTarget()->FillRectangle(&rect, pColorBrush); bDone = true; } @@ -1766,11 +1748,11 @@ void D2DPixelProcessor2D::processSingleLinePrimitive2D( const basegfx::BColor aLineColor( maBColorModifierStack.getModifiedColor(rSingleLinePrimitive2D.getBColor())); const D2D1::ColorF aD2DColor(aLineColor.getRed(), aLineColor.getGreen(), aLineColor.getBlue()); - ID2D1SolidColorBrush* pColorBrush(nullptr); - HRESULT hr(getRenderTarget().CreateSolidColorBrush(aD2DColor, &pColorBrush)); + sal::systools::COMReference<ID2D1SolidColorBrush> pColorBrush; + const HRESULT hr(getRenderTarget()->CreateSolidColorBrush(aD2DColor, &pColorBrush)); bool bDone(false); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && pColorBrush) { const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0); basegfx::B2DHomMatrix aLocalTransform( @@ -1778,13 +1760,13 @@ void D2DPixelProcessor2D::processSingleLinePrimitive2D( const basegfx::B2DPoint aStart(aLocalTransform * rSingleLinePrimitive2D.getStart()); const basegfx::B2DPoint aEnd(aLocalTransform * rSingleLinePrimitive2D.getEnd()); - getRenderTarget().SetTransform(D2D1::Matrix3x2F::Identity()); + getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); const D2D1_POINT_2F aD2D1Start = { FLOAT(aStart.getX() + fAAOffset), FLOAT(aStart.getY() + fAAOffset) }; const D2D1_POINT_2F aD2D1End = { FLOAT(aEnd.getX() + fAAOffset), FLOAT(aEnd.getY() + fAAOffset) }; - getRenderTarget().DrawLine(aD2D1Start, aD2D1End, pColorBrush, 1.44f); + getRenderTarget()->DrawLine(aD2D1Start, aD2D1End, pColorBrush, 1.44f); bDone = true; } @@ -1795,12 +1777,19 @@ void D2DPixelProcessor2D::processSingleLinePrimitive2D( void D2DPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) { if (0 == mnRecursionCounter) - getRenderTarget().BeginDraw(); + getRenderTarget()->BeginDraw(); mnRecursionCounter++; switch (rCandidate.getPrimitive2DID()) { - // geometry that *has* to be processed + // Geometry that *has* to be processed + // + // These Primitives have *no* decompose implementation, so these are the basic ones + // Just four to go to make a processor work completely (but not optimized) + // NOTE: This *could* theoretically be reduced to one and all could implement + // a decompose to pixel data, but that seemed not to make sense to me when + // I designed this. Thus these four are the lowest-level best representation + // from my POV case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D: { processBitmapPrimitive2D( @@ -1826,7 +1815,16 @@ void D2DPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv break; } - // embedding/groups that *have* to be processed + // Embedding/groups that *have* to be processed + // + // These represent qualifiers for freely defined content, e.g. making + // any combinatiopn of priitives freely transformed or transparent + // NOTE: PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D and + // PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D are pretty much default- + // implementations that cand and are re-used in all processors. + // So - with these and PRIMITIVE2D_ID_INVERTPRIMITIVE2D marked to + // be removed in the future - just three really to be implemented + // locally specifically case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D: { processTransparencePrimitive2D( @@ -1837,7 +1835,9 @@ void D2DPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv { // TODO: fallback is at VclPixelProcessor2D::processInvertPrimitive2D, so // not in reach. Ignore for now. - // processInvertPrimitive2D(rCandidate); + // NOTE: We *urgently* need to get rid of the last parts in LO that use + // XOR paint. Modern graphic systems allow no read access to the + // pixel targets, but that's naturally a precondition for XOR break; } case PRIMITIVE2D_ID_MASKPRIMITIVE2D: @@ -1859,52 +1859,70 @@ void D2DPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv break; } - // geometry that *may* be processed due to being able to do it better - // then using the decomposition + // Geometry that *may* be processed due to being able to do it better + // then using the decomposition. + // NOTE: In these implementations you could always call what the default + // case below does - call process(rCandidate) to use the decomposition. + // So these impls should only do something if they can do it better/ + // faster that the decomposition. So some of them check if they could + // - and if not - use exactly that. case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D: { + // transparence with a fixed alpha for all content, can be done + // significally faster processUnifiedTransparencePrimitive2D( static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate)); break; } case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D: { + // can be done simpler and without AA better locally processMarkerArrayPrimitive2D( static_cast<const primitive2d::MarkerArrayPrimitive2D&>(rCandidate)); break; } case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D: { + // reset to a color, can be done more effectively locally, would + // else decompose to a polygon fill processBackgroundColorPrimitive2D( static_cast<const primitive2d::BackgroundColorPrimitive2D&>(rCandidate)); break; } case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: { + // fat and stroked lines - much better doable locally, would decompose + // to the full line geometry creation (tesselation) processPolygonStrokePrimitive2D( static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate)); break; } case PRIMITIVE2D_ID_LINERECTANGLEPRIMITIVE2D: { + // simple primitve to support future fast callbacks from OutputDevice + // (see 'Example POC' in Gerrit), decomposes to polygon primitive processLineRectanglePrimitive2D( static_cast<const primitive2d::LineRectanglePrimitive2D&>(rCandidate)); break; } case PRIMITIVE2D_ID_FILLEDRECTANGLEPRIMITIVE2D: { + // simple primitve to support future fast callbacks from OutputDevice + // (see 'Example POC' in Gerrit), decomposes to filled polygon primitive processFilledRectanglePrimitive2D( static_cast<const primitive2d::FilledRectanglePrimitive2D&>(rCandidate)); break; } case PRIMITIVE2D_ID_SINGLELINEPRIMITIVE2D: { + // simple primitve to support future fast callbacks from OutputDevice + // (see 'Example POC' in Gerrit), decomposes to polygon primitive processSingleLinePrimitive2D( static_cast<const primitive2d::SingleLinePrimitive2D&>(rCandidate)); break; } - // continue with decompose + // continue with decompose as fallback default: { SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString( @@ -1917,7 +1935,7 @@ void D2DPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv mnRecursionCounter--; if (0 == mnRecursionCounter) - getRenderTarget().EndDraw(); + getRenderTarget()->EndDraw(); } } // end of namespace |