diff --git a/include/svx/svdpntv.hxx b/include/svx/svdpntv.hxx index 8665262f0508..df3c95131590 100644 --- a/include/svx/svdpntv.hxx +++ b/include/svx/svdpntv.hxx @@ -207,7 +207,8 @@ protected: bool mbHideChart : 1; bool mbHideDraw : 1; // hide draw objects other than form controls bool mbHideFormControl : 1; // hide form controls only - bool mbPaintTextEdit : 1; // if should paint currently edited text + bool mbHideBackground : 1; // don't draw the (page's or matser page's) background + bool mbPaintTextEdit : 1; // if should paint currently edited text public: // Interface for BufferedOoutputAllowed flag @@ -473,10 +474,13 @@ public: bool getHideChart() const { return mbHideChart; } bool getHideDraw() const { return mbHideDraw; } bool getHideFormControl() const { return mbHideFormControl; } + bool getHideBackground() const { return mbHideBackground; } + void setHideOle(bool bNew) { if(bNew != mbHideOle) mbHideOle = bNew; } void setHideChart(bool bNew) { if(bNew != mbHideChart) mbHideChart = bNew; } void setHideDraw(bool bNew) { if(bNew != mbHideDraw) mbHideDraw = bNew; } void setHideFormControl(bool bNew) { if(bNew != mbHideFormControl) mbHideFormControl = bNew; } + void setHideBackground(bool bNew) { mbHideBackground = bNew; } void SetGridCoarse(const Size& rSiz) { maGridBig=rSiz; } void SetGridFine(const Size& rSiz) { diff --git a/sd/qa/unit/tiledrendering/data/SlideRenderingTest.odp b/sd/qa/unit/tiledrendering/data/SlideRenderingTest.odp index 4c7d4f101e32..8ffd7d38f051 100644 Binary files a/sd/qa/unit/tiledrendering/data/SlideRenderingTest.odp and b/sd/qa/unit/tiledrendering/data/SlideRenderingTest.odp differ diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx index 11b740ebdc74..0ab9ca8a3723 100644 --- a/sd/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx @@ -3125,8 +3125,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering) // The document has nothing set for the background, so it should be application color = white // On the master slide there is a (blue) rectangle on the right side - top-left should be transparent // On the main slide there is a (green) rectangle on the top-left size - right side should be transparent - // enable layer output to PNG files - const bool bOutputPNG = false; + + const bool bOutputPNG = false; // Control layer output to PNG files + SdXImpressDocument* pXImpressDocument = createDoc("SlideRenderingTest.odp"); pXImpressDocument->initializeForTiledRendering(uno::Sequence()); sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); @@ -3137,16 +3138,18 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering) sal_Int32 nViewHeight = 2000; CPPUNIT_ASSERT(pXImpressDocument->createSlideRenderer(0, nViewWidth, nViewHeight, true, true)); CPPUNIT_ASSERT_EQUAL(2000, nViewWidth); - CPPUNIT_ASSERT_EQUAL(1125, nViewHeight); // adjusted to the slide aspect ratio - std::vector pBuffer(nViewWidth * nViewHeight * 4); - bool bIsBitmapLayer = false; - OUString rJsonMsg; + CPPUNIT_ASSERT_EQUAL(1125, nViewHeight); - CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, rJsonMsg)); - CPPUNIT_ASSERT(bIsBitmapLayer); - // TODO - check JSON content - // printf ("1 %s\n\n", rJsonMsg.toUtf8().getStr()); + const Color aTransparentColor(ColorAlpha, 0x00000000); { + std::vector pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString rJsonMsg; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, rJsonMsg)); + CPPUNIT_ASSERT(bIsBitmapLayer); + // TODO - check JSON content + // printf ("1 %s\n\n", rJsonMsg.toUtf8().getStr()); + BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true); if (bOutputPNG) { @@ -3155,14 +3158,49 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering) aPNGWriter.write(aBitmapEx); } + // top-left corner + CPPUNIT_ASSERT_EQUAL(aTransparentColor, aBitmapEx.GetPixelColor(20, 20)); + // bottom-left corner - CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00000000), aBitmapEx.GetPixelColor(20, nViewHeight - 20)); + CPPUNIT_ASSERT_EQUAL(aTransparentColor, aBitmapEx.GetPixelColor(20, nViewHeight - 20)); // bottom-right corner - CPPUNIT_ASSERT_EQUAL(Color(0xff, 0xd5, 0x46), aBitmapEx.GetPixelColor(nViewWidth - 20, nViewHeight - 20)); + CPPUNIT_ASSERT_EQUAL(Color(0xff, 0xd0, 0x40), aBitmapEx.GetPixelColor(nViewWidth - 20, nViewHeight - 20)); + } + + { + std::vector pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString rJsonMsg; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, rJsonMsg)); + CPPUNIT_ASSERT(bIsBitmapLayer); + // TODO - check JSON content + // printf ("2 %s\n\n", rJsonMsg.toUtf8().getStr()); + + BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true); + if (bOutputPNG) + { + SvFileStream aStream("/home/quikee/XXX_02.png", StreamMode::WRITE | StreamMode::TRUNC); + vcl::PngImageWriter aPNGWriter(aStream); + aPNGWriter.write(aBitmapEx); + } + + // top-left corner + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0x50, 0x90), aBitmapEx.GetPixelColor(20, 20)); + + // bottom-left corner + CPPUNIT_ASSERT_EQUAL(aTransparentColor, aBitmapEx.GetPixelColor(20, nViewHeight - 20)); + + // bottom-right corner + CPPUNIT_ASSERT_EQUAL(aTransparentColor, aBitmapEx.GetPixelColor(nViewWidth - 20, nViewHeight - 20)); + } + + { + std::vector pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString rJsonMsg; + CPPUNIT_ASSERT(pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, rJsonMsg)); } - // should return true - no more content - CPPUNIT_ASSERT(pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, rJsonMsg)); pXImpressDocument->postSlideshowCleanup(); } diff --git a/sd/source/ui/inc/SlideshowLayerRenderer.hxx b/sd/source/ui/inc/SlideshowLayerRenderer.hxx index 28525839d579..33c2ca69d502 100644 --- a/sd/source/ui/inc/SlideshowLayerRenderer.hxx +++ b/sd/source/ui/inc/SlideshowLayerRenderer.hxx @@ -12,23 +12,36 @@ #include #include #include +#include class SdrPage; -class BitmapEx; +class SdrModel; + class Size; namespace sd { +enum class SlideRenderStage +{ + Master, + Slide +}; + class SD_DLLPUBLIC SlideshowLayerRenderer { - SdrPage* mpPage; + SdrPage& mrPage; + SdrModel& mrModel; + Size maSlideSize; - bool bRenderDone = false; + + std::deque maRenderStages; public: - SlideshowLayerRenderer(SdrPage* pPage); + SlideshowLayerRenderer(SdrPage& rPage); Size calculateAndSetSizePixel(Size const& rDesiredSizePixel); bool render(unsigned char* pBuffer, OString& rJsonMsg); + bool renderMaster(unsigned char* pBuffer, OString& rJsonMsg); + bool renderSlide(unsigned char* pBuffer, OString& rJsonMsg); }; } // end of namespace sd diff --git a/sd/source/ui/tools/SlideshowLayerRenderer.cxx b/sd/source/ui/tools/SlideshowLayerRenderer.cxx index 4bcdc25b9190..ec238d3a139f 100644 --- a/sd/source/ui/tools/SlideshowLayerRenderer.cxx +++ b/sd/source/ui/tools/SlideshowLayerRenderer.cxx @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -23,9 +25,23 @@ namespace sd { namespace { -class SelectObjectRedirector : public sdr::contact::ViewObjectContactRedirector +struct RedirectorOptions { + bool mbSkipMainPageObjects = false; + bool mbSkipMasterPageObjects = false; +}; + +class ObjectRedirector : public sdr::contact::ViewObjectContactRedirector +{ +protected: + RedirectorOptions maOptions; + public: + ObjectRedirector(RedirectorOptions const& rOptions) + : maOptions(rOptions) + { + } + virtual void createRedirectedPrimitive2DSequence( const sdr::contact::ViewObjectContact& rOriginal, const sdr::contact::DisplayInfo& rDisplayInfo, @@ -37,12 +53,15 @@ public: if (pObject == nullptr || pPage == nullptr) { // Not a SdrObject or a object not connected to a page (object with no page) - - //sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( - // rOriginal, rDisplayInfo, rVisitor); return; } + if (maOptions.mbSkipMasterPageObjects && pPage->IsMasterPage()) + return; + + if (maOptions.mbSkipMainPageObjects && !pPage->IsMasterPage()) + return; + const bool bDoCreateGeometry( pObject->getSdrPageFromSdrObject()->checkVisibility(rOriginal, rDisplayInfo, true)); @@ -60,43 +79,57 @@ public: rOriginal, rDisplayInfo, rVisitor); } }; + +bool hasEmptyMaster(SdrPage const& rPage) +{ + if (!rPage.TRG_HasMasterPage()) + return true; + + SdrPage& rMaster = rPage.TRG_GetMasterPage(); + for (size_t i = 0; i < rMaster.GetObjCount(); i++) + { + auto pObject = rMaster.GetObj(i); + if (!pObject->IsEmptyPresObj()) + return false; + } + return true; } -SlideshowLayerRenderer::SlideshowLayerRenderer(SdrPage* pPage) - : mpPage(pPage) +} // end anonymous namespace + +SlideshowLayerRenderer::SlideshowLayerRenderer(SdrPage& rPage) + : mrPage(rPage) + , mrModel(rPage.getSdrModelFromSdrPage()) { + if (!hasEmptyMaster(rPage)) + maRenderStages.emplace_back(SlideRenderStage::Master); + maRenderStages.emplace_back(SlideRenderStage::Slide); } Size SlideshowLayerRenderer::calculateAndSetSizePixel(Size const& rDesiredSizePixel) { - if (!mpPage) - return Size(); - - double fRatio = double(mpPage->GetHeight()) / mpPage->GetWidth(); + double fRatio = double(mrPage.GetHeight()) / mrPage.GetWidth(); Size aSize(rDesiredSizePixel.Width(), ::tools::Long(rDesiredSizePixel.Width() * fRatio)); maSlideSize = aSize; return maSlideSize; } -bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) +bool SlideshowLayerRenderer::renderMaster(unsigned char* pBuffer, OString& rJsonMsg) { - if (bRenderDone) - return false; - - if (!mpPage) - return false; - - SdrModel& rModel = mpPage->getSdrModelFromSdrPage(); + SdrOutliner& rOutliner = mrModel.GetDrawOutliner(); + const EEControlBits nOldControlBits(rOutliner.GetControlWord()); + EEControlBits nControlBits = nOldControlBits & ~EEControlBits::ONLINESPELLING; + rOutliner.SetControlWord(nControlBits); ScopedVclPtrInstance pDevice(DeviceFormat::WITHOUT_ALPHA); pDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); - pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(maSlideSize, Fraction(2.0), Point(), + pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(maSlideSize, Fraction(1.0), Point(), pBuffer); Point aPoint; - Size aPageSize(mpPage->GetSize()); + Size aPageSize(mrPage.GetSize()); MapMode aMapMode(MapUnit::Map100thMM); const Fraction aFracX(maSlideSize.Width(), pDevice->LogicToPixel(aPageSize, aMapMode).Width()); @@ -108,7 +141,7 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) pDevice->SetMapMode(aMapMode); - SdrView aView(rModel, pDevice); + SdrView aView(mrModel, pDevice); aView.SetPageVisible(false); aView.SetPageShadowVisible(false); @@ -117,16 +150,16 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) aView.SetGridVisible(false); aView.SetHlplVisible(false); aView.SetGlueVisible(false); - - aView.ShowSdrPage(mpPage); + aView.setHideBackground(false); + aView.ShowSdrPage(&mrPage); vcl::Region aRegion(::tools::Rectangle(aPoint, aPageSize)); - SelectObjectRedirector aRedirector; + ObjectRedirector aRedirector({ .mbSkipMainPageObjects = true }); aView.CompleteRedraw(pDevice, aRegion, &aRedirector); ::tools::JsonWriter aJsonWriter; - aJsonWriter.put("group", "DrawPage"); - aJsonWriter.put("slideHash", GetInterfaceHash(GetXDrawPageForSdrPage(mpPage))); + aJsonWriter.put("group", "MasterPage"); + aJsonWriter.put("slideHash", GetInterfaceHash(GetXDrawPageForSdrPage(&mrPage))); aJsonWriter.put("index", 0); aJsonWriter.put("type", "bitmap"); { @@ -136,7 +169,85 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) } rJsonMsg = aJsonWriter.finishAndGetAsOString(); - bRenderDone = true; + rOutliner.SetControlWord(nOldControlBits); + + return true; +} + +bool SlideshowLayerRenderer::renderSlide(unsigned char* pBuffer, OString& rJsonMsg) +{ + SdrOutliner& rOutliner = mrModel.GetDrawOutliner(); + const EEControlBits nOldControlBits(rOutliner.GetControlWord()); + EEControlBits nControlBits = nOldControlBits & ~EEControlBits::ONLINESPELLING; + rOutliner.SetControlWord(nControlBits); + + ScopedVclPtrInstance pDevice(DeviceFormat::WITHOUT_ALPHA); + pDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); + + pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(maSlideSize, Fraction(1.0), Point(), + pBuffer); + + Point aPoint; + Size aPageSize(mrPage.GetSize()); + + MapMode aMapMode(MapUnit::Map100thMM); + const Fraction aFracX(maSlideSize.Width(), pDevice->LogicToPixel(aPageSize, aMapMode).Width()); + aMapMode.SetScaleX(aFracX); + + const Fraction aFracY(maSlideSize.Height(), + pDevice->LogicToPixel(aPageSize, aMapMode).Height()); + aMapMode.SetScaleY(aFracY); + + pDevice->SetMapMode(aMapMode); + + SdrView aView(mrModel, pDevice); + + aView.SetPageVisible(false); + aView.SetPageShadowVisible(false); + aView.SetPageBorderVisible(false); + aView.SetBordVisible(false); + aView.SetGridVisible(false); + aView.SetHlplVisible(false); + aView.SetGlueVisible(false); + aView.setHideBackground(true); + aView.ShowSdrPage(&mrPage); + + vcl::Region aRegion(::tools::Rectangle(aPoint, aPageSize)); + ObjectRedirector aRedirector({ .mbSkipMasterPageObjects = true }); + aView.CompleteRedraw(pDevice, aRegion, &aRedirector); + + ::tools::JsonWriter aJsonWriter; + aJsonWriter.put("group", "DrawPage"); + aJsonWriter.put("slideHash", GetInterfaceHash(GetXDrawPageForSdrPage(&mrPage))); + aJsonWriter.put("index", 0); + aJsonWriter.put("type", "bitmap"); + { + auto aContentNode = aJsonWriter.startNode("content"); + aJsonWriter.put("type", "%IMAGETYPE%"); + aJsonWriter.put("checksum", "%IMAGECHECKSUM%"); + } + rJsonMsg = aJsonWriter.finishAndGetAsOString(); + + rOutliner.SetControlWord(nOldControlBits); + + return true; +} + +bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) +{ + if (maRenderStages.empty()) + return false; + + auto eRenderStage = maRenderStages.front(); + maRenderStages.pop_front(); + + switch (eRenderStage) + { + case SlideRenderStage::Master: + return renderMaster(pBuffer, rJsonMsg); + case SlideRenderStage::Slide: + return renderSlide(pBuffer, rJsonMsg); + }; return true; } diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx index 845ee623e4af..347fc52f1e1f 100644 --- a/sd/source/ui/unoidl/unomodel.cxx +++ b/sd/source/ui/unoidl/unomodel.cxx @@ -4457,7 +4457,7 @@ bool SdXImpressDocument::createSlideRenderer( if (!pPage) return false; - mpSlideshowLayerRenderer.reset(new SlideshowLayerRenderer(pPage)); + mpSlideshowLayerRenderer.reset(new SlideshowLayerRenderer(*pPage)); Size aDesiredSize(nViewWidth, nViewHeight); Size aCalculatedSize = mpSlideshowLayerRenderer->calculateAndSetSizePixel(aDesiredSize); nViewWidth = aCalculatedSize.Width(); diff --git a/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx b/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx index baa039b1bb0f..2cd4b64c2fe8 100644 --- a/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx +++ b/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -78,12 +80,13 @@ namespace sdr::contact aPreprocessedLayers &= rDescriptor.GetVisibleLayers(); rDisplayInfo.SetProcessLayers(aPreprocessedLayers); rDisplayInfo.SetSubContentActive(true); - + const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView(); + bool bHideBackground = pSdrPageView ? pSdrPageView->GetView().getHideBackground() : false; // check layer visibility (traditionally was member of layer 1) if(aPreprocessedLayers.IsSet(SdrLayerID(1))) { // hide PageBackground for special DrawModes; historical reasons - if(!GetObjectContact().isDrawModeGray() && !GetObjectContact().isDrawModeHighContrast()) + if (!bHideBackground && !GetObjectContact().isDrawModeGray() && !GetObjectContact().isDrawModeHighContrast()) { // if visible, create the default background primitive sequence static_cast< ViewContactOfMasterPageDescriptor& >(GetViewContact()).getViewIndependentPrimitive2DContainer(rVisitor); diff --git a/svx/source/svdraw/svdpntv.cxx b/svx/source/svdraw/svdpntv.cxx index 5874acb1c63d..de1e42a5e6cb 100644 --- a/svx/source/svdraw/svdpntv.cxx +++ b/svx/source/svdraw/svdpntv.cxx @@ -165,6 +165,7 @@ SdrPaintView::SdrPaintView(SdrModel& rSdrModel, OutputDevice* pOut) , mbHideChart(false) , mbHideDraw(false) , mbHideFormControl(false) + , mbHideBackground(false) , mbPaintTextEdit(true) , maGridColor(COL_BLACK) {