comphelper/qa/unit/test_hash.cxx                                               
         |   26 ---
 comphelper/source/misc/hash.cxx                                                
         |   13 +
 include/comphelper/hash.hxx                                                    
         |    2 
 
sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations_DifferentKindOfTextBox.odp
 |binary
 sd/qa/unit/tiledrendering/tiledrendering.cxx                                   
         |   82 ++++++++++
 sd/source/ui/tools/SlideshowLayerRenderer.cxx                                  
         |   25 +--
 6 files changed, 118 insertions(+), 30 deletions(-)

New commits:
commit 9fef2827aa234c893ec5cc2d608181890e24cdd1
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Wed Oct 16 09:30:11 2024 +0200
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Oct 21 10:33:30 2024 +0200

    slideshow: fix para. rendering when using SdrBlockTextPrimitive2D
    
    If using an empty ViewInformation, it is possible that the prim.
    decomposition is redone, when a different ViewInformation is used.
    This removes all visibility flags for the paragraphs, so the whole
    text is rendered. This fixes the issue by using the same instance
    of the ViewInformation that is also used later for rendering the
    primitives to the VirtualDevice, so the buffered decomposition is
    used.
    
    Also a test is added - it checks the hash of the buffer, which
    should be different for all 3 layers. For this the tostring has
    to be moved to the common hash.hxx, so we can reuse it in out
    tests.
    
    Change-Id: I4c951215a52e302d3b7b60a30c1b995002e53a4b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174989
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>

diff --git a/comphelper/qa/unit/test_hash.cxx b/comphelper/qa/unit/test_hash.cxx
index 64815ee56dc8..d5e8be2646b0 100644
--- a/comphelper/qa/unit/test_hash.cxx
+++ b/comphelper/qa/unit/test_hash.cxx
@@ -13,7 +13,6 @@
 #include <comphelper/docpasswordhelper.hxx>
 
 #include <rtl/ustring.hxx>
-#include <iomanip>
 
 #include <cppunit/TestFixture.h>
 #include <cppunit/extensions/HelperMacros.h>
@@ -48,21 +47,6 @@ public:
     CPPUNIT_TEST_SUITE_END();
 };
 
-namespace {
-
-std::string tostring(const std::vector<unsigned char>& a)
-{
-    std::stringstream aStrm;
-    for (auto& i:a)
-    {
-        aStrm << std::setw(2) << std::setfill('0') << std::hex << 
static_cast<int>(i);
-    }
-
-    return aStrm.str();
-}
-
-}
-
 void TestHash::testMD5()
 {
     comphelper::Hash aHash(comphelper::HashType::MD5);
@@ -70,7 +54,7 @@ void TestHash::testMD5()
     aHash.update(reinterpret_cast<const unsigned char*>(pInput), 0);
     std::vector<unsigned char> calculate_hash = aHash.finalize();
     CPPUNIT_ASSERT_EQUAL(size_t(16), calculate_hash.size());
-    CPPUNIT_ASSERT_EQUAL(std::string("d41d8cd98f00b204e9800998ecf8427e"), 
tostring(calculate_hash));
+    CPPUNIT_ASSERT_EQUAL(std::string("d41d8cd98f00b204e9800998ecf8427e"), 
comphelper::hashToString(calculate_hash));
 }
 
 void TestHash::testSHA1()
@@ -80,7 +64,7 @@ void TestHash::testSHA1()
     aHash.update(reinterpret_cast<const unsigned char*>(pInput), 0);
     std::vector<unsigned char> calculate_hash = aHash.finalize();
     CPPUNIT_ASSERT_EQUAL(size_t(20), calculate_hash.size());
-    
CPPUNIT_ASSERT_EQUAL(std::string("da39a3ee5e6b4b0d3255bfef95601890afd80709"), 
tostring(calculate_hash));
+    
CPPUNIT_ASSERT_EQUAL(std::string("da39a3ee5e6b4b0d3255bfef95601890afd80709"), 
comphelper::hashToString(calculate_hash));
 }
 
 void TestHash::testSHA256()
@@ -90,7 +74,7 @@ void TestHash::testSHA256()
     aHash.update(reinterpret_cast<const unsigned char*>(pInput), 0);
     std::vector<unsigned char> calculate_hash = aHash.finalize();
     CPPUNIT_ASSERT_EQUAL(size_t(32), calculate_hash.size());
-    
CPPUNIT_ASSERT_EQUAL(std::string("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"),
 tostring(calculate_hash));
+    
CPPUNIT_ASSERT_EQUAL(std::string("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"),
 comphelper::hashToString(calculate_hash));
 }
 
 void TestHash::testSHA512()
@@ -101,7 +85,7 @@ void TestHash::testSHA512()
     std::vector<unsigned char> calculate_hash = aHash.finalize();
     CPPUNIT_ASSERT_EQUAL(size_t(64), calculate_hash.size());
     std::string 
aStr("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
-    CPPUNIT_ASSERT_EQUAL(aStr, tostring(calculate_hash));
+    CPPUNIT_ASSERT_EQUAL(aStr, comphelper::hashToString(calculate_hash));
 }
 
 // Must be identical to testSHA512()
@@ -113,7 +97,7 @@ void TestHash::testSHA512_NoSaltNoSpin()
                 nullptr, 0, 0, comphelper::Hash::IterCount::NONE, 
comphelper::HashType::SHA512);
     CPPUNIT_ASSERT_EQUAL(size_t(64), calculate_hash.size());
     std::string 
aStr("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
-    CPPUNIT_ASSERT_EQUAL(aStr, tostring(calculate_hash));
+    CPPUNIT_ASSERT_EQUAL(aStr, comphelper::hashToString(calculate_hash));
 }
 
 // Password, salt, hash and spin count taken from OOXML sheetProtection of
diff --git a/comphelper/source/misc/hash.cxx b/comphelper/source/misc/hash.cxx
index 25b93ad87e54..96e125cac23d 100644
--- a/comphelper/source/misc/hash.cxx
+++ b/comphelper/source/misc/hash.cxx
@@ -15,6 +15,8 @@
 #include <rtl/alloc.h>
 #include <osl/endian.h>
 #include <config_oox.h>
+#include <sstream>
+#include <iomanip>
 
 #if USE_TLS_NSS
 #include <nss.h>
@@ -27,6 +29,17 @@
 
 namespace comphelper {
 
+std::string hashToString(const std::vector<unsigned char>& rHash)
+{
+    std::stringstream aStringStream;
+    for (auto& i: rHash)
+    {
+        aStringStream << std::setw(2) << std::setfill('0') << std::hex << 
int(i);
+    }
+
+    return aStringStream.str();
+}
+
 struct HashImpl
 {
 
diff --git a/include/comphelper/hash.hxx b/include/comphelper/hash.hxx
index a3ad468d3eb5..1007e8dfa464 100644
--- a/include/comphelper/hash.hxx
+++ b/include/comphelper/hash.hxx
@@ -39,6 +39,8 @@ const sal_uInt32 SHA512_HASH_LENGTH = 64;
 
 struct HashImpl;
 
+COMPHELPER_DLLPUBLIC std::string hashToString(const std::vector<unsigned 
char>& rHash);
+
 class COMPHELPER_DLLPUBLIC Hash
 {
 private:
diff --git 
a/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations_DifferentKindOfTextBox.odp
 
b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations_DifferentKindOfTextBox.odp
new file mode 100644
index 000000000000..47777662805f
Binary files /dev/null and 
b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations_DifferentKindOfTextBox.odp
 differ
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx 
b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index 0003f5378d9a..8442f9332c79 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -18,6 +18,7 @@
 #include <comphelper/propertysequence.hxx>
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/string.hxx>
+#include <comphelper/hash.hxx>
 #include <editeng/eeitem.hxx>
 #include <editeng/editids.hrc>
 #include <editeng/editobj.hxx>
@@ -3801,6 +3802,87 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_Animati
     pXImpressDocument->postSlideshowCleanup();
 }
 
+namespace
+{
+template <typename T>
+bool is_unique(std::vector<T> vec)
+{
+    std::sort(vec.begin(), vec.end());
+    return std::unique(vec.begin(), vec.end()) == vec.end();
+}
+}
+
+CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_Animation_DifferentKindOfTextBox)
+{
+    SdXImpressDocument* pXImpressDocument = 
createDoc("SlideRenderingTest_Animations_DifferentKindOfTextBox.odp");
+    
pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    sd::ViewShell* pViewShell = 
pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+    sal_Int32 nViewWidth = 2000;
+    sal_Int32 nViewHeight = 2000;
+
+    std::string sHash = GetInterfaceHash(GetXDrawPageForSdrPage(pPage));
+    CPPUNIT_ASSERT(pXImpressDocument->createSlideRenderer(sHash.c_str(), 0, 
nViewWidth, nViewHeight, true, true));
+    CPPUNIT_ASSERT_EQUAL(2000, nViewWidth);
+    CPPUNIT_ASSERT_EQUAL(1500, nViewHeight);
+
+    std::vector<std::string> aHashes;
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+
+        // Remember the hash of the buffer for uniqueness check
+        auto aBufferHash = comphelper::Hash::calculateHash(pBuffer.data(), 
pBuffer.size(), comphelper::HashType::SHA1);
+        aHashes.push_back(comphelper::hashToString(aBufferHash));
+
+        debugWriteImageToFile(1, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
+    }
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+
+        // Remember the hash of the buffer for uniqueness check
+        auto aBufferHash = comphelper::Hash::calculateHash(pBuffer.data(), 
pBuffer.size(), comphelper::HashType::SHA1);
+        aHashes.push_back(comphelper::hashToString(aBufferHash));
+
+        debugWriteImageToFile(2, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
+    }
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+
+        // Remember the hash of the buffer for uniqueness check
+        auto aBufferHash = comphelper::Hash::calculateHash(pBuffer.data(), 
pBuffer.size(), comphelper::HashType::SHA1);
+        aHashes.push_back(comphelper::hashToString(aBufferHash));
+
+        debugWriteImageToFile(3, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
+    }
+
+    // check if all hashes are unique
+    CPPUNIT_ASSERT(is_unique(aHashes));
+
+    // Check we are done
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        CPPUNIT_ASSERT(pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+    }
+
+    pXImpressDocument->postSlideshowCleanup();
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/tools/SlideshowLayerRenderer.cxx 
b/sd/source/ui/tools/SlideshowLayerRenderer.cxx
index 39adde615331..6ec95a2030be 100644
--- a/sd/source/ui/tools/SlideshowLayerRenderer.cxx
+++ b/sd/source/ui/tools/SlideshowLayerRenderer.cxx
@@ -139,7 +139,8 @@ void 
changeBackground(drawinglayer::primitive2d::Primitive2DContainer const& rCo
 }
 
 drawinglayer::primitive2d::TextHierarchyBlockPrimitive2D*
-findTextBlock(drawinglayer::primitive2d::Primitive2DContainer const& 
rContainer)
+findTextBlock(drawinglayer::primitive2d::Primitive2DContainer const& 
rContainer,
+              drawinglayer::geometry::ViewInformation2D const& 
rViewInformation2D)
 {
     for (size_t i = 0; i < rContainer.size(); i++)
     {
@@ -158,7 +159,8 @@ 
findTextBlock(drawinglayer::primitive2d::Primitive2DContainer const& rContainer)
                 = 
dynamic_cast<drawinglayer::primitive2d::GroupPrimitive2D*>(pBasePrimitive);
             if (pGroupPrimitive)
             {
-                auto* pTextBlock = 
findTextBlock(pGroupPrimitive->getChildren());
+                auto* pTextBlock
+                    = findTextBlock(pGroupPrimitive->getChildren(), 
rViewInformation2D);
                 if (pTextBlock)
                     return pTextBlock;
             }
@@ -170,9 +172,8 @@ 
findTextBlock(drawinglayer::primitive2d::Primitive2DContainer const& rContainer)
             {
                 // try to decompose
                 drawinglayer::primitive2d::Primitive2DContainer 
aPrimitiveContainer;
-                pBasePrimitive->get2DDecomposition(aPrimitiveContainer,
-                                                   
drawinglayer::geometry::ViewInformation2D());
-                auto* pTextBlock = findTextBlock(aPrimitiveContainer);
+                pBasePrimitive->get2DDecomposition(aPrimitiveContainer, 
rViewInformation2D);
+                auto* pTextBlock = findTextBlock(aPrimitiveContainer, 
rViewInformation2D);
                 if (pTextBlock)
                     return pTextBlock;
             }
@@ -182,9 +183,10 @@ 
findTextBlock(drawinglayer::primitive2d::Primitive2DContainer const& rContainer)
 }
 
 void modifyParagraphs(drawinglayer::primitive2d::Primitive2DContainer& 
rContainer,
+                      drawinglayer::geometry::ViewInformation2D const& 
rViewInformation2D,
                       std::deque<sal_Int32> const& rPreserveIndices, bool 
bRenderObject)
 {
-    auto* pTextBlock = findTextBlock(rContainer);
+    auto* pTextBlock = findTextBlock(rContainer, rViewInformation2D);
 
     if (pTextBlock)
     {
@@ -244,6 +246,10 @@ public:
             return;
 
         SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
+
+        drawinglayer::geometry::ViewInformation2D const& rViewInformation2D
+            = rOriginal.GetObjectContact().getViewInformation2D();
+
         // Check if we are rendering an object that is valid to render 
(exists, and not empty)
         if (pObject == nullptr || pObject->IsEmptyPresObj())
             return;
@@ -339,7 +345,8 @@ public:
 
             if (bRenderOtherParagraphs)
             {
-                modifyParagraphs(rContainer, nOtherParagraphs, true); // 
render the object
+                modifyParagraphs(rContainer, rViewInformation2D, 
nOtherParagraphs,
+                                 true); // render the object
                 mrRenderState.mnCurrentTargetParagraph = -1;
             }
             else
@@ -349,8 +356,8 @@ public:
 
                 std::deque<sal_Int32> aPreserveParagraphs{ nParagraph };
                 mrRenderState.mnCurrentTargetParagraph = nParagraph;
-                modifyParagraphs(rContainer, aPreserveParagraphs,
-                                 false); // render only the paragraphs
+                // render only the paragraphs
+                modifyParagraphs(rContainer, rViewInformation2D, 
aPreserveParagraphs, false);
             }
         }
 

Reply via email to