drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx | 596 +++++++-------- include/drawinglayer/processor2d/d2dpixelprocessor2d.hxx | 21 2 files changed, 320 insertions(+), 297 deletions(-)
New commits: commit 7e07225a1b48f3f987a818213256d3cbb9266d87 Author: Armin Le Grand (Allotropia) <armin.le.gr...@me.com> AuthorDate: Fri Jan 6 12:16:10 2023 +0100 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Fri Jan 6 15:24:39 2023 +0000 SDPR: Overhauled D2DRenderer to use sal::systools::COMReference All stuff used from MS with names starting with ID2D1* is COM API stuff, so referenced and interface-based. I thought about making this more safe since a while (shared/unique_ptr, ...) but found no good way to do it. Also did not want to use CComPtr from MS and expand the devenv we need on win, so was short before doing an own small smartptr class. Luckily I asked sberg and he pointed me to the already existing sal::systools::COMReference which exactly does what I need here - thanks! Unluckily I now had to change a lot of code - sigh. I wish I had known earlier :-/ This change contains the renderer completely adapted to using that much safer and better ressource control. Plus I added (even more) comments to try to make more clear in many plasces what's going on, what is done and why. Change-Id: Ia2aa3223d0e5f7ec6569cde176cec1fadcd921dc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145142 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> 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 diff --git a/include/drawinglayer/processor2d/d2dpixelprocessor2d.hxx b/include/drawinglayer/processor2d/d2dpixelprocessor2d.hxx index a08fef7b7ae2..10f9a11cb296 100644 --- a/include/drawinglayer/processor2d/d2dpixelprocessor2d.hxx +++ b/include/drawinglayer/processor2d/d2dpixelprocessor2d.hxx @@ -21,6 +21,7 @@ #include <drawinglayer/processor2d/baseprocessor2d.hxx> #include <basegfx/color/bcolormodifier.hxx> +#include <systools/win32/comtools.hxx> #include <sal/config.h> // win-specific @@ -56,7 +57,7 @@ class DRAWINGLAYER_DLLPUBLIC D2DPixelProcessor2D : public BaseProcessor2D basegfx::BColorModifierStack maBColorModifierStack; // win and render specific data - ID2D1RenderTarget* mpRT; + sal::systools::COMReference<ID2D1RenderTarget> mpRT; sal_uInt32 mnRecursionCounter; sal_uInt32 mnErrorCounter; @@ -90,9 +91,10 @@ class DRAWINGLAYER_DLLPUBLIC D2DPixelProcessor2D : public BaseProcessor2D processSingleLinePrimitive2D(const primitive2d::SingleLinePrimitive2D& rSingleLinePrimitive2D); // common helpers - ID2D1Bitmap* implCreateAlpha_Direct(const primitive2d::TransparencePrimitive2D& rTransCandidate, - const basegfx::B2DRange& rVisibleRange); - ID2D1Bitmap* + sal::systools::COMReference<ID2D1Bitmap> + implCreateAlpha_Direct(const primitive2d::TransparencePrimitive2D& rTransCandidate, + const basegfx::B2DRange& rVisibleRange); + sal::systools::COMReference<ID2D1Bitmap> implCreateAlpha_B2DBitmap(const primitive2d::TransparencePrimitive2D& rTransCandidate, const basegfx::B2DRange& rVisibleRange, D2D1_MATRIX_3X2_F& rMaskScale); @@ -109,14 +111,17 @@ protected: // local protected minimal accessors for usage in derivates, e.g. helpers void increaseError() { mnErrorCounter++; } bool hasError() const { return 0 != mnErrorCounter; } - void setRenderTarget(ID2D1RenderTarget* mpNewRT) { mpRT = mpNewRT; } - bool hasRenderTarget() const { return nullptr != mpRT; } - ID2D1RenderTarget& getRenderTarget() { return *mpRT; } + bool hasRenderTarget() const { return mpRT.is(); } + + void setRenderTarget(const sal::systools::COMReference<ID2D1RenderTarget>& rNewRT) + { + mpRT = rNewRT; + } + sal::systools::COMReference<ID2D1RenderTarget>& getRenderTarget() { return mpRT; } public: bool valid() const { return hasRenderTarget() && !hasError(); } D2DPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation, HDC aHdc); - virtual ~D2DPixelProcessor2D() override; }; }