include/oox/drawingml/color.hxx | 3 ++ oox/source/drawingml/color.cxx | 8 +++++ oox/source/drawingml/fillproperties.cxx | 48 ++++++++++++++++++++++++++++---- sd/qa/unit/data/pptx/tdf94238.pptx |binary sd/qa/unit/import-tests.cxx | 33 ++++++++++++++++++++++ vcl/CppunitTest_vcl_outdev.mk | 1 vcl/qa/cppunit/outdev.cxx | 18 ++++++++++++ vcl/source/outdev/map.cxx | 4 +- vcl/source/outdev/outdev.cxx | 3 ++ 9 files changed, 110 insertions(+), 8 deletions(-)
New commits: commit cc678cbe2e9f8d1bd9b571e0c3af0a38d0d2a4ad Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed Jan 30 17:42:39 2019 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Jun 18 13:03:22 2019 +0200 Related: tdf#94238 PPTX import: handle subset of radial gradient fill Handle the case when the horizontal center is at 50%. Other cases are still unhandled, those are more complex. After fixing the style, center and border, the gradient fill looks similar to how PowerPoint renders it. Reviewed-on: https://gerrit.libreoffice.org/67168 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins (cherry picked from commit fa6d726a9369fd49ff2b6c00da682641a025ba50) Conflicts: sd/qa/unit/import-tests.cxx Change-Id: I419da70482de37031aa2c7fc735692019d7665f5 diff --git a/include/oox/drawingml/color.hxx b/include/oox/drawingml/color.hxx index 94d9050c5b42..2d33eb6e3136 100644 --- a/include/oox/drawingml/color.hxx +++ b/include/oox/drawingml/color.hxx @@ -103,6 +103,9 @@ public: /** Translates between color transformation token names and the corresponding token */ static sal_Int32 getColorTransformationToken( const OUString& sName ); + /// Compares this color with rOther. + bool equals(const Color& rOther, const GraphicHelper& rGraphicHelper, ::Color nPhClr) const; + private: /** Internal helper for getColor(). */ void setResolvedRgb( ::Color nRgb ) const; diff --git a/oox/source/drawingml/color.cxx b/oox/source/drawingml/color.cxx index 7008328c47ca..a41c9398c268 100644 --- a/oox/source/drawingml/color.cxx +++ b/oox/source/drawingml/color.cxx @@ -431,6 +431,14 @@ sal_Int32 Color::getColorTransformationToken( const OUString& sName ) return XML_TOKEN_INVALID; } +bool Color::equals(const Color& rOther, const GraphicHelper& rGraphicHelper, ::Color nPhClr) const +{ + if (getColor(rGraphicHelper, nPhClr) != rOther.getColor(rGraphicHelper, nPhClr)) + return false; + + return getTransparency() == rOther.getTransparency(); +} + void Color::clearTransparence() { mnAlpha = MAX_PERCENT; diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index be91daa81b92..9c5338ce8975 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -154,6 +154,30 @@ const awt::Size lclGetOriginalSize( const GraphicHelper& rGraphicHelper, const R return aSizeHmm; } +/** + * Looks for a last gradient transition and possibly sets a gradient border + * based on that. + */ +void extractGradientBorderFromStops(const GradientFillProperties& rGradientProps, + const GraphicHelper& rGraphicHelper, ::Color nPhClr, + awt::Gradient& rGradient) +{ + if (rGradientProps.maGradientStops.size() <= 1) + return; + + auto it = rGradientProps.maGradientStops.rbegin(); + double fLastPos = it->first; + Color aLastColor = it->second; + ++it; + double fLastButOnePos = it->first; + Color aLastButOneColor = it->second; + if (!aLastColor.equals(aLastButOneColor, rGraphicHelper, nPhClr)) + return; + + // Last transition has the same color, we can map that to a border. + rGradient.Border = rtl::math::round((fLastPos - fLastButOnePos) * 100); +} + } // namespace void GradientFillProperties::assignUsed( const GradientFillProperties& rSourceProps ) @@ -354,15 +378,28 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, if( maGradientProps.moGradientPath.has() ) { - aGradient.Style = (maGradientProps.moGradientPath.get() == XML_circle) ? awt::GradientStyle_ELLIPTICAL : awt::GradientStyle_RECT; - // position of gradient center (limited to [30%;70%], otherwise gradient is too hidden) + // position of gradient center (limited to [30%;100%], otherwise gradient is too hidden) IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.get( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) ); sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2; - aGradient.XOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterX / PER_PERCENT, 30, 70 ); + aGradient.XOffset = getLimitedValue<sal_Int16, sal_Int32>( + nCenterX / PER_PERCENT, 30, 100); + + // Style should be radial at least when the horizontal center is at 50%. + awt::GradientStyle eCircle = aGradient.XOffset == 50 + ? awt::GradientStyle_RADIAL + : awt::GradientStyle_ELLIPTICAL; + aGradient.Style = (maGradientProps.moGradientPath.get() == XML_circle) + ? eCircle + : awt::GradientStyle_RECT; + sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; - aGradient.YOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterY / PER_PERCENT, 30, 70 ); + aGradient.YOffset = getLimitedValue<sal_Int16, sal_Int32>( + nCenterY / PER_PERCENT, 30, 100); ::std::swap( aGradient.StartColor, aGradient.EndColor ); ::std::swap( nStartTrans, nEndTrans ); + + extractGradientBorderFromStops(maGradientProps, rGraphicHelper, nPhClr, + aGradient); } else if (!maGradientProps.maGradientStops.empty()) { @@ -394,8 +431,7 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, GradientFillProperties::GradientStopMap::const_iterator aItZ(std::prev(aGradientStops.end())); while( bSymmetric && aItA->first < aItZ->first ) { - if( aItA->second.getColor( rGraphicHelper, nPhClr ) != aItZ->second.getColor( rGraphicHelper, nPhClr ) || - aItA->second.getTransparency() != aItZ->second.getTransparency() ) + if (!aItA->second.equals(aItZ->second, rGraphicHelper, nPhClr)) bSymmetric = false; else { diff --git a/sd/qa/unit/data/pptx/tdf94238.pptx b/sd/qa/unit/data/pptx/tdf94238.pptx new file mode 100644 index 000000000000..cf35ecee8d12 Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf94238.pptx differ diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx index 362d67814d91..36d4806efdb2 100644 --- a/sd/qa/unit/import-tests.cxx +++ b/sd/qa/unit/import-tests.cxx @@ -194,6 +194,7 @@ public: void testTdf120028(); void testTdf120028b(); void testCropToShape(); + void testTdf94238(); CPPUNIT_TEST_SUITE(SdImportTest); @@ -280,6 +281,7 @@ public: CPPUNIT_TEST(testTdf120028); CPPUNIT_TEST(testTdf120028b); CPPUNIT_TEST(testCropToShape); + CPPUNIT_TEST(testTdf94238); CPPUNIT_TEST_SUITE_END(); }; @@ -2675,6 +2677,37 @@ void SdImportTest::testCropToShape() CPPUNIT_ASSERT_EQUAL(css::drawing::BitmapMode_STRETCH, bitmapmode); } +void SdImportTest::testTdf94238() +{ + // Assert how the gradient fill of the only shape in the document is + // imported. + ::sd::DrawDocShellRef xDocShRef + = loadURL(m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/tdf94238.pptx"), PPTX); + uno::Reference<drawing::XDrawPagesSupplier> xDoc(xDocShRef->GetDoc()->getUnoModel(), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xDoc.is()); + + uno::Reference<drawing::XDrawPage> xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xPage.is()); + + uno::Reference<beans::XPropertySet> xShape(getShape(0, xPage)); + CPPUNIT_ASSERT(xShape.is()); + + awt::Gradient aGradient; + CPPUNIT_ASSERT(xShape->getPropertyValue("FillGradient") >>= aGradient); + + // Without the accompanying fix in place, this test would have failed with + // the following details: + // - aGradient.Style was awt::GradientStyle_ELLIPTICAL + // - aGradient.YOffset was 70 + // - aGradient.Border was 0 + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RADIAL, aGradient.Style); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(100), aGradient.YOffset); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(39), aGradient.Border); + + xDocShRef->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTest); CPPUNIT_PLUGIN_IMPLEMENT(); commit 8842b1938bba44315b3c88e1accbaadcc2a6df09 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jan 15 17:31:16 2019 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Jun 18 13:03:22 2019 +0200 vcl: protect more outdev functions for disposed state This is similar to commit c612c3b0aed9ad7f7f42b4313f821b71995ead15 (protect more printer code-paths., 2015-03-20), but handles more OutputDevice member functions. The user-level problem was that in case a macro creates a dialog with an embedded Chart document and the user clicks on e.g. the chart title (so an sdr::overlay::OverlayManager is created), then it can happen during closing the dialog that the overlay manager calls these functions after the output device is disposed. Change-Id: I8021fb795704f19e52d70505804d68725c636ce0 Reviewed-on: https://gerrit.libreoffice.org/66403 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins (cherry picked from commit 8b461713c0c86bc19af739aada4b1345cfa5dfbe) diff --git a/vcl/CppunitTest_vcl_outdev.mk b/vcl/CppunitTest_vcl_outdev.mk index 183432fccfe6..f15d2e26d17d 100644 --- a/vcl/CppunitTest_vcl_outdev.mk +++ b/vcl/CppunitTest_vcl_outdev.mk @@ -21,6 +21,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,vcl_outdev, \ $(eval $(call gb_CppunitTest_use_externals,vcl_outdev,boost_headers)) $(eval $(call gb_CppunitTest_use_libraries,vcl_outdev, \ + basegfx \ comphelper \ cppu \ cppuhelper \ diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx index c50481cb0f5a..cf6ee60a486a 100644 --- a/vcl/qa/cppunit/outdev.cxx +++ b/vcl/qa/cppunit/outdev.cxx @@ -18,6 +18,7 @@ #include <tools/stream.hxx> #include <vcl/pngwrite.hxx> #include <sal/log.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> class VclOutdevTest : public test::BootstrapFixture { @@ -25,9 +26,11 @@ public: VclOutdevTest() : BootstrapFixture(true, false) {} void testVirtualDevice(); + void testUseAfterDispose(); CPPUNIT_TEST_SUITE(VclOutdevTest); CPPUNIT_TEST(testVirtualDevice); + CPPUNIT_TEST(testUseAfterDispose); CPPUNIT_TEST_SUITE_END(); }; @@ -80,6 +83,21 @@ void VclOutdevTest::testVirtualDevice() #endif } +void VclOutdevTest::testUseAfterDispose() +{ + // Create a virtual device, enable map mode then dispose it. + ScopedVclPtrInstance<VirtualDevice> pVDev; + + pVDev->EnableMapMode(); + + pVDev->disposeOnce(); + + // Make sure that these don't crash after dispose. + pVDev->GetInverseViewTransformation(); + + pVDev->GetViewTransformation(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(VclOutdevTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx index e3275b904a3e..9447bf80532c 100644 --- a/vcl/source/outdev/map.cxx +++ b/vcl/source/outdev/map.cxx @@ -854,7 +854,7 @@ void OutputDevice::SetRelativeMapMode( const MapMode& rNewMapMode ) // #i75163# basegfx::B2DHomMatrix OutputDevice::GetViewTransformation() const { - if(mbMap) + if(mbMap && mpOutDevData) { if(!mpOutDevData->mpViewTransform) { @@ -882,7 +882,7 @@ basegfx::B2DHomMatrix OutputDevice::GetViewTransformation() const // #i75163# basegfx::B2DHomMatrix OutputDevice::GetInverseViewTransformation() const { - if(mbMap) + if(mbMap && mpOutDevData) { if(!mpOutDevData->mpInverseViewTransform) { diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx index a8b4c1767058..07b05972c630 100644 --- a/vcl/source/outdev/outdev.cxx +++ b/vcl/source/outdev/outdev.cxx @@ -658,6 +658,9 @@ bool OutputDevice::HasMirroredGraphics() const bool OutputDevice::ImplIsRecordLayout() const { + if (!mpOutDevData) + return false; + return mpOutDevData->mpRecordLayout; } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits