[Libreoffice-commits] core.git: drawinglayer/source include/drawinglayer include/vcl offapi/com offapi/UnoApi_offapi.mk vcl/source

Michael Stahl mstahl at redhat.com
Mon Nov 7 18:52:43 UTC 2016


 drawinglayer/source/primitive2d/baseprimitive2d.cxx         |    6 ++
 drawinglayer/source/primitive2d/bitmapprimitive2d.cxx       |    6 ++
 drawinglayer/source/primitive2d/groupprimitive2d.cxx        |   15 +++++
 drawinglayer/source/primitive2d/patternfillprimitive2d.cxx  |   15 +++++
 include/drawinglayer/primitive2d/baseprimitive2d.hxx        |   12 +++-
 include/drawinglayer/primitive2d/bitmapprimitive2d.hxx      |    3 +
 include/drawinglayer/primitive2d/groupprimitive2d.hxx       |    3 +
 include/drawinglayer/primitive2d/patternfillprimitive2d.hxx |    3 +
 include/vcl/svgdata.hxx                                     |    3 +
 offapi/UnoApi_offapi.mk                                     |    1 
 offapi/com/sun/star/util/XAccounting.idl                    |   34 ++++++++++++
 vcl/source/gdi/impgraph.cxx                                 |    7 ++
 vcl/source/gdi/svgdata.cxx                                  |   29 ++++++++++
 13 files changed, 134 insertions(+), 3 deletions(-)

New commits:
commit f9028f1945e3ad87cda1b3001611632b1b424467
Author: Michael Stahl <mstahl at redhat.com>
Date:   Mon Nov 7 15:09:31 2016 +0100

    vcl: improve accounting of SVG images in graphics cache
    
    The problem is that the graphics cache only counts the size of the SVG
    text, which is stored in SvgData::maSvgDataArray.  However the
    SvgData::maSequence may use a lot more memory, as it may contain
    de-compressed bitmaps that are stored as base64-encoded PNGs in the SVG
    text.
    
    For example icon-themes/galaxy/brand/flat_logo.svg is 812 Ko but contains
    60 Mo of bitmaps.
    
    This may cause excessive memory usage and failure to export documents
    due to OOM; according to valgrind massif, the bitmap buffers use 90% of
    the heap.
    
    Add a new interface com::sun::star::util::XAccounting, and implement
    it in drawinglayer BasePrimitive2D.  VCL SvgData can't access
    drawinglayer via C++ directly so this looks like the best approach.
    
    Change-Id: I5a7c3147733e23473c1decabed24c1f79d951c7d
    Reviewed-on: https://gerrit.libreoffice.org/30669
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>

diff --git a/drawinglayer/source/primitive2d/baseprimitive2d.cxx b/drawinglayer/source/primitive2d/baseprimitive2d.cxx
index 6f89cf3..84833c3 100644
--- a/drawinglayer/source/primitive2d/baseprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/baseprimitive2d.cxx
@@ -71,6 +71,12 @@ namespace drawinglayer
             const geometry::ViewInformation2D aViewInformation(rViewParameters);
             return basegfx::unotools::rectangle2DFromB2DRectangle(getB2DRange(aViewInformation));
         }
+
+        sal_Int64 SAL_CALL BasePrimitive2D::estimateUsage()
+            throw (css::uno::RuntimeException)
+        {
+            return 0; // for now ignore the objects themselves
+        }
     } // end of namespace primitive2d
 } // end of namespace drawinglayer
 
diff --git a/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx b/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx
index 30d3cde..db75ba5 100644
--- a/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx
@@ -58,6 +58,12 @@ namespace drawinglayer
             return aRetval;
         }
 
+        sal_Int64 SAL_CALL BitmapPrimitive2D::estimateUsage()
+            throw (css::uno::RuntimeException)
+        {
+            return getBitmapEx().GetSizeBytes();
+        }
+
         // provide unique ID
         ImplPrimitive2DIDBlock(BitmapPrimitive2D, PRIMITIVE2D_ID_BITMAPPRIMITIVE2D)
 
diff --git a/drawinglayer/source/primitive2d/groupprimitive2d.cxx b/drawinglayer/source/primitive2d/groupprimitive2d.cxx
index d35f5b1..b5582a0 100644
--- a/drawinglayer/source/primitive2d/groupprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/groupprimitive2d.cxx
@@ -56,6 +56,21 @@ namespace drawinglayer
             return getChildren();
         }
 
+        sal_Int64 SAL_CALL GroupPrimitive2D::estimateUsage()
+            throw (css::uno::RuntimeException)
+        {
+            size_t nRet(0);
+            for (auto& it : getChildren())
+            {
+                uno::Reference<util::XAccounting> const xAcc(it, uno::UNO_QUERY);
+                if (xAcc.is())
+                {
+                    nRet += xAcc->estimateUsage();
+                }
+            }
+            return nRet;
+        }
+
         // provide unique ID
         ImplPrimitive2DIDBlock(GroupPrimitive2D, PRIMITIVE2D_ID_GROUPPRIMITIVE2D)
 
diff --git a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
index 5d1eec1..82d397d 100644
--- a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
@@ -314,6 +314,21 @@ namespace drawinglayer
             return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
         }
 
+        sal_Int64 SAL_CALL PatternFillPrimitive2D::estimateUsage()
+            throw (css::uno::RuntimeException)
+        {
+            size_t nRet(0);
+            for (auto& it : getChildren())
+            {
+                uno::Reference<util::XAccounting> const xAcc(it, uno::UNO_QUERY);
+                if (xAcc.is())
+                {
+                    nRet += xAcc->estimateUsage();
+                }
+            }
+            return nRet;
+        }
+
         // provide unique ID
         ImplPrimitive2DIDBlock(PatternFillPrimitive2D, PRIMITIVE2D_ID_PATTERNFILLPRIMITIVE2D)
 
diff --git a/include/drawinglayer/primitive2d/baseprimitive2d.hxx b/include/drawinglayer/primitive2d/baseprimitive2d.hxx
index 195de77..b6e3ecd 100644
--- a/include/drawinglayer/primitive2d/baseprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/baseprimitive2d.hxx
@@ -22,8 +22,9 @@
 
 #include <drawinglayer/drawinglayerdllapi.h>
 
-#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/compbase.hxx>
 #include <com/sun/star/graphic/XPrimitive2D.hpp>
+#include <com/sun/star/util/XAccounting.hpp>
 #include <cppuhelper/basemutex.hxx>
 #include <basegfx/range/b2drange.hxx>
 
@@ -49,7 +50,10 @@ namespace drawinglayer { namespace geometry {
 
 namespace drawinglayer { namespace primitive2d {
     /// typedefs for basePrimitive2DImplBase, Primitive2DSequence and Primitive2DReference
-    typedef cppu::WeakComponentImplHelper1< css::graphic::XPrimitive2D > BasePrimitive2DImplBase;
+    typedef cppu::WeakComponentImplHelper<
+                css::graphic::XPrimitive2D,
+                css::util::XAccounting
+            > BasePrimitive2DImplBase;
     typedef css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference;
     typedef css::uno::Sequence< Primitive2DReference > Primitive2DSequence;
 
@@ -200,6 +204,10 @@ namespace drawinglayer
                 will construct a ViewInformation2D from the ViewParameters for that purpose
              */
             virtual css::geometry::RealRectangle2D SAL_CALL getRange( const css::uno::Sequence< css::beans::PropertyValue >& rViewParameters ) throw ( css::uno::RuntimeException, std::exception ) override;
+
+            // XAccounting
+            virtual sal_Int64 SAL_CALL estimateUsage() throw (css::uno::RuntimeException) override;
+
         };
     } // end of namespace primitive2d
 } // end of namespace drawinglayer
diff --git a/include/drawinglayer/primitive2d/bitmapprimitive2d.hxx b/include/drawinglayer/primitive2d/bitmapprimitive2d.hxx
index c7eb9e3..a14fa68 100644
--- a/include/drawinglayer/primitive2d/bitmapprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/bitmapprimitive2d.hxx
@@ -69,6 +69,9 @@ namespace drawinglayer
 
             /// provide unique ID
             DeclPrimitive2DIDBlock()
+
+            // XAccounting
+            virtual sal_Int64 SAL_CALL estimateUsage() throw (css::uno::RuntimeException) override;
         };
     } // end of namespace primitive2d
 } // end of namespace drawinglayer
diff --git a/include/drawinglayer/primitive2d/groupprimitive2d.hxx b/include/drawinglayer/primitive2d/groupprimitive2d.hxx
index 67b39ed..5f63874 100644
--- a/include/drawinglayer/primitive2d/groupprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/groupprimitive2d.hxx
@@ -84,6 +84,9 @@ namespace drawinglayer
 
             /// provide unique ID
             DeclPrimitive2DIDBlock()
+
+            // XAccounting
+            virtual sal_Int64 SAL_CALL estimateUsage() throw (css::uno::RuntimeException) override;
         };
     } // end of namespace primitive2d
 } // end of namespace drawinglayer
diff --git a/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx b/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx
index 8e10564..8a64fdf 100644
--- a/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/patternfillprimitive2d.hxx
@@ -87,6 +87,9 @@ namespace drawinglayer
 
             /// provide unique ID
             DeclPrimitive2DIDBlock()
+
+            // XAccounting
+            virtual sal_Int64 SAL_CALL estimateUsage() throw (css::uno::RuntimeException) override;
         };
     } // end of namespace primitive2d
 } // end of namespace drawinglayer
diff --git a/include/vcl/svgdata.hxx b/include/vcl/svgdata.hxx
index 3615288..7401378 100644
--- a/include/vcl/svgdata.hxx
+++ b/include/vcl/svgdata.hxx
@@ -52,6 +52,7 @@ private:
     std::vector< css::uno::Reference< css::graphic::XPrimitive2D > >
                             maSequence;
     BitmapEx                maReplacement;
+    size_t mNestedBitmapSize;
 
     // on demand creators
     void ensureReplacement();
@@ -67,6 +68,8 @@ public:
     /// data read
     const SvgDataArray& getSvgDataArray() const { return maSvgDataArray; }
     sal_uInt32 getSvgDataArrayLength() const { return maSvgDataArray.getLength(); }
+    enum class State { UNPARSED, PARSED };
+    std::pair<State, size_t> getSizeBytes();
     const OUString& getPath() const { return maPath; }
 
     /// data read and evtl. on demand creation
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 9d44e99..a14aff6 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -4113,6 +4113,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/util,\
 	TriState \
 	URL \
 	VetoException \
+	XAccounting \
 	XAtomServer \
 	XBroadcaster \
 	XCancellable \
diff --git a/offapi/com/sun/star/util/XAccounting.idl b/offapi/com/sun/star/util/XAccounting.idl
new file mode 100644
index 0000000..545a16a
--- /dev/null
+++ b/offapi/com/sun/star/util/XAccounting.idl
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __com_sun_star_util_XAccounting_idl__
+#define __com_sun_star_util_XAccounting_idl__
+
+#include <com/sun/star/uno/XInterface.idl>
+
+module com { module sun { module star { module util {
+
+/** allows estimating the memory usage of a service.
+
+    @since LibreOffice 5.3
+ */
+interface XAccounting : com::sun::star::uno::XInterface
+{
+
+    /** @returns an estimate of the current memory usage, in octets.
+     */
+    hyper estimateUsage();
+
+};
+
+}; }; }; };
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
index ce3b42c..ef05e5c 100644
--- a/vcl/source/gdi/impgraph.cxx
+++ b/vcl/source/gdi/impgraph.cxx
@@ -766,7 +766,12 @@ sal_uLong ImpGraphic::ImplGetSizeBytes() const
         {
             if(maSvgData.get())
             {
-                mnSizeBytes = maSvgData->getSvgDataArrayLength();
+                std::pair<SvgData::State, size_t> tmp(maSvgData->getSizeBytes());
+                if (SvgData::State::UNPARSED == tmp.first)
+                {
+                    return tmp.second; // don't cache it until SVG is parsed
+                }
+                mnSizeBytes = tmp.second;
             }
             else
             {
diff --git a/vcl/source/gdi/svgdata.cxx b/vcl/source/gdi/svgdata.cxx
index cf85eeb..9fd84e6 100644
--- a/vcl/source/gdi/svgdata.cxx
+++ b/vcl/source/gdi/svgdata.cxx
@@ -24,6 +24,7 @@
 #include <com/sun/star/graphic/SvgTools.hpp>
 #include <com/sun/star/graphic/Primitive2DTools.hpp>
 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
+#include <com/sun/star/util/XAccounting.hpp>
 #include <vcl/canvastools.hxx>
 #include <comphelper/seqstream.hxx>
 #include <comphelper/sequence.hxx>
@@ -88,6 +89,19 @@ BitmapEx convertPrimitive2DSequenceToBitmapEx(
     return aRetval;
 }
 
+size_t estimateSize(
+    std::vector<uno::Reference<graphic::XPrimitive2D>> const& rSequence)
+{
+    size_t nRet(0);
+    for (auto& it : rSequence)
+    {
+        uno::Reference<util::XAccounting> const xAcc(it, uno::UNO_QUERY);
+        assert(xAcc.is()); // we expect only BasePrimitive2D from SVG parser
+        nRet += xAcc->estimateUsage();
+    }
+    return nRet;
+}
+
 void SvgData::ensureReplacement()
 {
     ensureSequenceAndRange();
@@ -149,6 +163,19 @@ void SvgData::ensureSequenceAndRange()
                 }
             }
         }
+        mNestedBitmapSize = estimateSize(maSequence);
+    }
+}
+
+auto SvgData::getSizeBytes() -> std::pair<State, size_t>
+{
+    if (maSequence.empty() && maSvgDataArray.hasElements())
+    {
+        return std::make_pair(State::UNPARSED, maSvgDataArray.getLength());
+    }
+    else
+    {
+        return std::make_pair(State::PARSED, maSvgDataArray.getLength() + mNestedBitmapSize);
     }
 }
 
@@ -158,6 +185,7 @@ SvgData::SvgData(const SvgDataArray& rSvgDataArray, const OUString& rPath)
     maRange(),
     maSequence(),
     maReplacement()
+,   mNestedBitmapSize(0)
 {
 }
 
@@ -167,6 +195,7 @@ SvgData::SvgData(const OUString& rPath):
     maRange(),
     maSequence(),
     maReplacement()
+,   mNestedBitmapSize(0)
 {
     SvFileStream rIStm(rPath, StreamMode::STD_READ);
     if(rIStm.GetError())


More information about the Libreoffice-commits mailing list