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

Reply via email to