[Libreoffice-commits] core.git: Branch 'distro/collabora/co-2021' - desktop/qa desktop/source include/LibreOfficeKit include/tools include/vcl sw/inc sw/qa sw/source

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Thu Sep 2 06:39:13 UTC 2021


 desktop/qa/data/SearchIndexResultTest.odt         |binary
 desktop/qa/desktop_lib/test_desktop_lib.cxx       |   49 ++++++++++++++++++
 desktop/source/lib/init.cxx                       |   57 ++++++++++++++++++++++
 include/LibreOfficeKit/LibreOfficeKit.h           |    6 ++
 include/LibreOfficeKit/LibreOfficeKit.hxx         |   16 ++++++
 include/tools/UnitConversion.hxx                  |    2 
 include/vcl/ITiledRenderable.hxx                  |    9 +++
 sw/inc/unotxdoc.hxx                               |    3 +
 sw/qa/extras/indexing/SearchResultLocatorTest.cxx |    7 --
 sw/source/uibase/uno/unotxdoc.cxx                 |   25 +++++++++
 10 files changed, 168 insertions(+), 6 deletions(-)

New commits:
commit 494b562a69899fdad2d88c1ae2439971acdbee3c
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri Jul 9 14:41:21 2021 +0900
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Thu Sep 2 08:38:39 2021 +0200

    indexing: add LOKit API to render the search result into a bitmap
    
    This adds a new LOKit API to render the search result into a bitmap
    buffer. It combines the SearchResultLocator to get the location
    inside the document of the search result (a series of rectangles)
    and the existing LOKit paintTile API to render the result into
    a bitmap (byte) buffer.
    
    It also adds a LOKit test to show how the API is used and to render
    a search result of a example document.
    
    Change-Id: I4284d90188777fd28158d029daa04151e71022bb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118670
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    (cherry picked from commit e1511ce551f27a5560600029193f076fd65ece17)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121110
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>

diff --git a/desktop/qa/data/SearchIndexResultTest.odt b/desktop/qa/data/SearchIndexResultTest.odt
new file mode 100644
index 000000000000..58ed3a0f5447
Binary files /dev/null and b/desktop/qa/data/SearchIndexResultTest.odt differ
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 0d18b4c13eb6..913cfb600fad 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -56,6 +56,8 @@
 #include <svx/svxids.hrc>
 
 #include <cppunit/TestAssert.h>
+#include <vcl/BitmapTools.hxx>
+#include <vcl/pngwrite.hxx>
 
 using namespace com::sun::star;
 using namespace desktop;
@@ -196,6 +198,7 @@ public:
     void testMetricField();
     void testMultiDocuments();
     void testJumpCursor();
+    void testRenderSearchResult();
     void testABI();
 
     CPPUNIT_TEST_SUITE(DesktopLOKTest);
@@ -259,6 +262,7 @@ public:
     CPPUNIT_TEST(testMetricField);
     CPPUNIT_TEST(testMultiDocuments);
     CPPUNIT_TEST(testJumpCursor);
+    CPPUNIT_TEST(testRenderSearchResult);
     CPPUNIT_TEST(testABI);
     CPPUNIT_TEST_SUITE_END();
 
@@ -3078,6 +3082,48 @@ void DesktopLOKTest::testJumpCursor()
     comphelper::LibreOfficeKit::setTiledAnnotations(true);
 }
 
+void DesktopLOKTest::testRenderSearchResult()
+{
+    constexpr const bool bDumpBitmap = false;
+
+    LibLODocument_Impl* pDocument = loadDoc("SearchIndexResultTest.odt");
+    pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}");
+
+    Scheduler::ProcessEventsToIdle();
+
+    unsigned char* pBuffer = nullptr;
+    OString aJSON = "{ \"node_index\" : 19 }";
+
+    int nWidth = 0;
+    int nHeight = 0;
+    size_t nByteSize = 0;
+
+    bool bResult = pDocument->m_pDocumentClass->renderSearchResult(pDocument, aJSON.getStr(), &pBuffer, &nWidth, &nHeight, &nByteSize);
+
+    CPPUNIT_ASSERT(bResult);
+    CPPUNIT_ASSERT(pBuffer);
+
+    Scheduler::ProcessEventsToIdle();
+
+    CPPUNIT_ASSERT_EQUAL(642, nWidth);
+    CPPUNIT_ASSERT_EQUAL(561, nHeight);
+    CPPUNIT_ASSERT_EQUAL(size_t(1440648), nByteSize);
+
+    const sal_uInt8* pD = reinterpret_cast<const sal_uInt8*>(pBuffer);
+    BitmapEx aBitmap = vcl::bitmap::CreateFromData(pD, nWidth, nHeight, nWidth * 4, 32, true);
+
+    if (bDumpBitmap)
+    {
+        SvFileStream aStream("~/SearchResultBitmap.png", StreamMode::WRITE | StreamMode::TRUNC);
+        vcl::PNGWriter aPNGWriter(aBitmap);
+        aPNGWriter.Write(aStream);
+    }
+    CPPUNIT_ASSERT_EQUAL(tools::Long(642), aBitmap.GetSizePixel().Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(561), aBitmap.GetSizePixel().Height());
+
+    std::free(pBuffer);
+}
+
 namespace {
 
 constexpr size_t classOffset(int i)
@@ -3177,10 +3223,11 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(61), offsetof(struct _LibreOfficeKitDocumentClass, sendFormFieldEvent));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(62), offsetof(struct _LibreOfficeKitDocumentClass, setFreemiumDenyList));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(63), offsetof(struct _LibreOfficeKitDocumentClass, setFreemiumView));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(64), offsetof(struct _LibreOfficeKitDocumentClass, renderSearchResult));
 
     // Extending is fine, update this, and add new assert for the offsetof the
     // new method
-    CPPUNIT_ASSERT_EQUAL(documentClassOffset(64), sizeof(struct _LibreOfficeKitDocumentClass));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(65), sizeof(struct _LibreOfficeKitDocumentClass));
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 7bc76e42ab8a..cd2562be2a86 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -123,6 +123,7 @@
 #include <unotools/resmgr.hxx>
 #include <tools/fract.hxx>
 #include <tools/json_writer.hxx>
+#include <tools/UnitConversion.hxx>
 #include <svtools/ctrltool.hxx>
 #include <svtools/langtab.hxx>
 #include <vcl/floatwin.hxx>
@@ -1199,6 +1200,11 @@ static void doc_completeFunction(LibreOfficeKitDocument* pThis, const char*);
 
 static void doc_sendFormFieldEvent(LibreOfficeKitDocument* pThis,
                                    const char* pArguments);
+
+static bool doc_renderSearchResult(LibreOfficeKitDocument* pThis,
+                                 const char* pSearchResult, unsigned char** pBitmapBuffer,
+                                 int* pWidth, int* pHeight, size_t* pByteSize);
+
 } // extern "C"
 
 namespace {
@@ -1338,6 +1344,7 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
         m_pDocumentClass->completeFunction = doc_completeFunction;
 
         m_pDocumentClass->sendFormFieldEvent = doc_sendFormFieldEvent;
+        m_pDocumentClass->renderSearchResult = doc_renderSearchResult;
 
         m_pDocumentClass->setFreemiumDenyList = doc_setFreemiumDenyList;
         m_pDocumentClass->setFreemiumView = doc_setFreemiumView;
@@ -5755,6 +5762,56 @@ static void doc_sendFormFieldEvent(LibreOfficeKitDocument* pThis, const char* pA
     pDoc->executeFromFieldEvent(aMap);
 }
 
+static bool doc_renderSearchResult(LibreOfficeKitDocument* pThis,
+                                     const char* pSearchResult, unsigned char** pBitmapBuffer,
+                                     int* pWidth, int* pHeight, size_t* pByteSize)
+{
+    if (doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT)
+        return false;
+
+    if (pBitmapBuffer == nullptr)
+        return false;
+
+    if (!pSearchResult || pSearchResult[0] == '\0')
+        return false;
+
+    ITiledRenderable* pDoc = getTiledRenderable(pThis);
+    if (!pDoc)
+    {
+        SetLastExceptionMsg("Document doesn't support tiled rendering");
+        return false;
+    }
+
+    auto aRectangleVector = pDoc->getSearchResultRectangles(pSearchResult);
+
+    // combine into a rectangle union
+    basegfx::B2DRange aRangeUnion;
+    for (basegfx::B2DRange const & rRange : aRectangleVector)
+    {
+        aRangeUnion.expand(rRange);
+    }
+
+    int aPixelWidth = convertTwipToPixel(aRangeUnion.getWidth());
+    int aPixelHeight = convertTwipToPixel(aRangeUnion.getHeight());
+
+    size_t nByteSize = aPixelWidth * aPixelHeight * 4;
+
+    *pWidth = aPixelWidth;
+    *pHeight = aPixelHeight;
+    *pByteSize = nByteSize;
+
+    auto* pBuffer = static_cast<unsigned char*>(std::malloc(nByteSize));
+
+    doc_paintTile(pThis, pBuffer,
+        aPixelWidth, aPixelHeight,
+        aRangeUnion.getMinX(), aRangeUnion.getMinY(),
+        aRangeUnion.getWidth(), aRangeUnion.getHeight());
+
+    *pBitmapBuffer = pBuffer;
+
+    return true;
+}
+
 static char* lo_getError (LibreOfficeKit *pThis)
 {
     comphelper::ProfileZone aZone("lo_getError");
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h
index fddec94a22f4..b6073feaeeeb 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -467,6 +467,12 @@ struct _LibreOfficeKitDocumentClass
                             int nViewId,
                             bool isFreemium);
 
+    /// @see lok::Document::renderSearchResult
+    bool (*renderSearchResult) (LibreOfficeKitDocument* pThis,
+                                const char* pSearchResult,
+                                unsigned char** pBitmapBuffer,
+                                int* pWidth, int* pHeight, size_t* pByteSize);
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx
index aab8b94c8aae..ded1cc3da6a9 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -797,6 +797,22 @@ public:
         mpDoc->pClass->setFreemiumView(mpDoc, nViewId, isFreemium);
     }
 
+    /**
+     * Render input search result to a bitmap buffer.
+     *
+     * @param pSearchResult payload containing the search result data
+     * @param pBitmapBuffer contains the bitmap; use free to deallocate.
+     * @param nWidth output bitmap width
+     * @param nHeight output bitmap height
+     * @param nByteSize output bitmap byte size
+     * @return true if successful
+     */
+    bool renderSearchResult(const char* pSearchResult, unsigned char** pBitmapBuffer,
+                            int* pWidth, int* pHeight, size_t* pByteSize)
+    {
+        return mpDoc->pClass->renderSearchResult(mpDoc, pSearchResult, pBitmapBuffer, pWidth, pHeight, pByteSize);
+    }
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/tools/UnitConversion.hxx b/include/tools/UnitConversion.hxx
index e78ef315b432..b139af6d7bed 100644
--- a/include/tools/UnitConversion.hxx
+++ b/include/tools/UnitConversion.hxx
@@ -29,6 +29,8 @@ constexpr sal_Int64 convertPointToMm100(sal_Int64 nNumber)
     return convertTwipToMm100(convertPointToTwip(nNumber));
 }
 
+constexpr double convertTwipToPixel(double nNumber) { return nNumber / 15.0; }
+
 constexpr double convertPointToTwip(double fNumber) { return fNumber * 20.0; }
 
 constexpr double convertPointToMm100(double fNumber) { return fNumber * (2540.0 / 72.0); }
diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index cf609fa0d0a5..306623234776 100644
--- a/include/vcl/ITiledRenderable.hxx
+++ b/include/vcl/ITiledRenderable.hxx
@@ -18,6 +18,7 @@
 #include <vcl/vclptr.hxx>
 #include <map>
 #include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <basegfx/range/b2drange.hxx>
 
 namespace com::sun::star::beans { struct PropertyValue; }
 namespace com::sun::star::datatransfer::clipboard { class XClipboard; }
@@ -328,6 +329,14 @@ public:
     virtual void executeFromFieldEvent(const StringMap&)
     {
     }
+
+    /**
+     * Returns the rectangles of the input search result JSON
+     */
+    virtual std::vector<basegfx::B2DRange> getSearchResultRectangles(const char* /*pPayload*/)
+    {
+        return std::vector<basegfx::B2DRange>();
+    }
 };
 } // namespace vcl
 
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index d6d66ff3021f..e9bcc7eba36a 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -447,6 +447,9 @@ public:
     /// @see vcl::ITiledRenderable::executeFromFieldEvent().
     virtual void executeFromFieldEvent(const StringMap& aArguments) override;
 
+    /// @see vcl::ITiledRenderable::getSearchResultRectangles().
+    std::vector<basegfx::B2DRange> getSearchResultRectangles(const char* pPayload) override;
+
     // css::tiledrendering::XTiledRenderable
     virtual void SAL_CALL paintTile( const ::css::uno::Any& Parent, ::sal_Int32 nOutputWidth, ::sal_Int32 nOutputHeight, ::sal_Int32 nTilePosX, ::sal_Int32 nTilePosY, ::sal_Int32 nTileWidth, ::sal_Int32 nTileHeight ) override;
 
diff --git a/sw/qa/extras/indexing/SearchResultLocatorTest.cxx b/sw/qa/extras/indexing/SearchResultLocatorTest.cxx
index e93c36b7fa7a..07ccc8da1c58 100644
--- a/sw/qa/extras/indexing/SearchResultLocatorTest.cxx
+++ b/sw/qa/extras/indexing/SearchResultLocatorTest.cxx
@@ -47,10 +47,6 @@ SwDoc* SearchResultLocatorTest::createDoc(const char* pName)
 
 void SearchResultLocatorTest::testSearchResultLocator()
 {
-#if !defined(_WIN32) && !defined(MACOSX)
-    if (!IsDefaultDPI())
-        return;
-
     SwDoc* pDoc = createDoc("IndexingExport_VariousParagraphs.odt");
     CPPUNIT_ASSERT(pDoc);
 
@@ -60,8 +56,9 @@ void SearchResultLocatorTest::testSearchResultLocator()
 
     sw::LocationResult aResult = aLocator.find(aData);
     CPPUNIT_ASSERT_EQUAL(size_t(1), aResult.maRectangles.size());
-    auto aRectangle = aResult.maRectangles[0];
 
+#if !defined(_WIN32) && !defined(MACOSX)
+    auto aRectangle = aResult.maRectangles[0];
     CPPUNIT_ASSERT_DOUBLES_EQUAL(1418.0, aRectangle.getMinX(), 1e-4);
     CPPUNIT_ASSERT_DOUBLES_EQUAL(4444.0, aRectangle.getMinY(), 1e-4);
 
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index 53e7e3292b3e..8bff5487fc7d 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -162,6 +162,8 @@
 #include <xmloff/odffields.hxx>
 #include <tools/json_writer.hxx>
 
+#include <SearchResultLocator.hxx>
+#include <boost/property_tree/json_parser.hpp>
 #define TWIPS_PER_PIXEL 15
 
 using namespace ::com::sun::star;
@@ -3406,6 +3408,29 @@ void SwXTextDocument::executeFromFieldEvent(const StringMap& aArguments)
     }
 }
 
+std::vector<basegfx::B2DRange>
+SwXTextDocument::getSearchResultRectangles(const char* pPayload)
+{
+    std::vector<basegfx::B2DRange> aRectangles;
+
+    boost::property_tree::ptree aTree;
+    std::stringstream aStream(pPayload);
+    boost::property_tree::read_json(aStream, aTree);
+
+    sw::SearchIndexData aData;
+
+    aData.nNodeIndex = sal_uInt32(aTree.get<int>("node_index"));
+
+    SwDoc* pDoc = m_pDocShell->GetDoc();
+
+    sw::SearchResultLocator aLocator(pDoc);
+    sw::LocationResult aResult = aLocator.find(aData);
+    if (aResult.mbFound)
+        aRectangles = aResult.maRectangles;
+
+    return aRectangles;
+}
+
 int SwXTextDocument::getPart()
 {
     SolarMutexGuard aGuard;


More information about the Libreoffice-commits mailing list