diff --git a/svx/qa/unit/data/0-width-text-wrap.pptx b/svx/qa/unit/data/0-width-text-wrap.pptx new file mode 100644 index 000000000000..17349924d89b Binary files /dev/null and b/svx/qa/unit/data/0-width-text-wrap.pptx differ diff --git a/svx/qa/unit/sdr.cxx b/svx/qa/unit/sdr.cxx index 49f4baa7182c..f6eb74488797 100644 --- a/svx/qa/unit/sdr.cxx +++ b/svx/qa/unit/sdr.cxx @@ -51,8 +51,26 @@ public: test::BootstrapFixture::tearDown(); } uno::Reference& getComponent() { return mxComponent; } + + drawinglayer::primitive2d::Primitive2DContainer + renderPageToPrimitives(const uno::Reference& xDrawPage); }; +drawinglayer::primitive2d::Primitive2DContainer +SdrTest::renderPageToPrimitives(const uno::Reference& xDrawPage) +{ + auto pDrawPage = dynamic_cast(xDrawPage.get()); + CPPUNIT_ASSERT(pDrawPage); + SdrPage* pSdrPage = pDrawPage->GetSdrPage(); + ScopedVclPtrInstance aVirtualDevice; + sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice, + { pSdrPage->GetObj(0) }, nullptr); + const sdr::contact::ViewObjectContact& rDrawPageVOContact + = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact); + sdr::contact::DisplayInfo aDisplayInfo; + return rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo); +} + CPPUNIT_TEST_FIXTURE(SdrTest, testShadowScaleOrigin) { // Load a document containing a custom shape. @@ -62,19 +80,8 @@ CPPUNIT_TEST_FIXTURE(SdrTest, testShadowScaleOrigin) uno::Reference xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); uno::Reference xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); - - // Render it. - auto pDrawPage = dynamic_cast(xDrawPage.get()); - CPPUNIT_ASSERT(pDrawPage); - SdrPage* pSdrPage = pDrawPage->GetSdrPage(); - ScopedVclPtrInstance aVirtualDevice; - sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice, - { pSdrPage->GetObj(0) }, nullptr); - const sdr::contact::ViewObjectContact& rDrawPageVOContact - = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact); - sdr::contact::DisplayInfo aDisplayInfo; drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence - = rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo); + = renderPageToPrimitives(xDrawPage); // Examine the created primitives. drawinglayer::Primitive2dXmlDump aDumper; @@ -89,6 +96,28 @@ CPPUNIT_TEST_FIXTURE(SdrTest, testShadowScaleOrigin) CPPUNIT_ASSERT_EQUAL(-705., std::round(fShadowX)); CPPUNIT_ASSERT_EQUAL(-685., std::round(fShadowY)); } + +CPPUNIT_TEST_FIXTURE(SdrTest, testZeroWidthTextWrap) +{ + // Load a document containing a 0-width shape with text. + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/0-width-text-wrap.pptx"); + getComponent() = loadFromDesktop(aURL); + uno::Reference xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence + = renderPageToPrimitives(xDrawPage); + + // Examine the created primitives. + drawinglayer::Primitive2dXmlDump aDumper; + xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 12 + // i.e. the text on the only shape on the slide had 12 lines, not a single one. + assertXPath(pDocument, "//textsimpleportion", 1); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx index 0a720842a1e3..dd256654a8af 100644 --- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx +++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx @@ -277,12 +277,36 @@ namespace drawinglayer::primitive2d // create a range describing the wanted text position and size (aTextAnchorRange). This // means to use the text distance values here - const basegfx::B2DPoint aTopLeft(aSnapRange.getMinX() + rText.getTextLeftDistance(), aSnapRange.getMinY() + rText.getTextUpperDistance()); - const basegfx::B2DPoint aBottomRight(aSnapRange.getMaxX() - rText.getTextRightDistance(), aSnapRange.getMaxY() - rText.getTextLowerDistance()); + sal_Int32 nTextLeftDistance = rText.getTextLeftDistance(); + // If the margin is larger than the entire width of the text area, then limit the + // margin. + if (nTextLeftDistance > aSnapRange.getWidth()) + nTextLeftDistance = aSnapRange.getWidth(); + sal_Int32 nTextRightDistance = rText.getTextRightDistance(); + if (nTextRightDistance > aSnapRange.getWidth()) + nTextRightDistance = aSnapRange.getWidth(); + const basegfx::B2DPoint aTopLeft(aSnapRange.getMinX() + nTextLeftDistance, + aSnapRange.getMinY() + + rText.getTextUpperDistance()); + const basegfx::B2DPoint aBottomRight(aSnapRange.getMaxX() - nTextRightDistance, + aSnapRange.getMaxY() + - rText.getTextLowerDistance()); basegfx::B2DRange aTextAnchorRange; aTextAnchorRange.expand(aTopLeft); aTextAnchorRange.expand(aBottomRight); + if (aTextAnchorRange.getWidth() == 0) + { + // If the shape has no width, then don't attempt to break the text into multiple + // lines, not a single character would satisfy a zero width requirement. + // SdrTextObj::impDecomposeBlockTextPrimitive() uses the same constant to + // effectively set no limits. + aTextAnchorRange.expand( + basegfx::B2DPoint(aTopLeft.getX() - 1000000, aTopLeft.getY())); + aTextAnchorRange.expand( + basegfx::B2DPoint(aBottomRight.getX() + 1000000, aBottomRight.getY())); + } + // now create a transformation from this basic range (aTextAnchorRange) // #i121494# if we have no scale use at least 1.0 to have a carrier e.g. for // mirror values, else these will get lost