summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2021-07-09 14:41:21 +0900
committerTomaž Vajngerl <quikee@gmail.com>2021-07-30 08:22:19 +0200
commite1511ce551f27a5560600029193f076fd65ece17 (patch)
tree3f104ccdda4a63bbaf4d7745f56944ff4d0ad4b3
parenteb31491b2a419ba7e67cc0a59a9b295fe49526e5 (diff)
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@gmail.com>
-rw-r--r--desktop/qa/data/SearchIndexResultTest.odtbin0 -> 126871 bytes
-rw-r--r--desktop/qa/desktop_lib/test_desktop_lib.cxx49
-rw-r--r--desktop/source/lib/init.cxx57
-rw-r--r--include/LibreOfficeKit/LibreOfficeKit.h6
-rw-r--r--include/LibreOfficeKit/LibreOfficeKit.hxx16
-rw-r--r--include/vcl/ITiledRenderable.hxx9
-rw-r--r--sw/inc/unotxdoc.hxx3
-rw-r--r--sw/source/uibase/uno/unotxdoc.cxx25
8 files changed, 164 insertions, 1 deletions
diff --git a/desktop/qa/data/SearchIndexResultTest.odt b/desktop/qa/data/SearchIndexResultTest.odt
new file mode 100644
index 000000000000..58ed3a0f5447
--- /dev/null
+++ b/desktop/qa/data/SearchIndexResultTest.odt
Binary files differ
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 2a26b04dcfa0..dfbee77167b8 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -59,6 +59,8 @@
#include <svx/svxids.hrc>
#include <cppunit/TestAssert.h>
+#include <vcl/BitmapTools.hxx>
+#include <vcl/pngwrite.hxx>
#if USE_TLS_NSS
#include <nss.h>
@@ -205,6 +207,7 @@ public:
void testMetricField();
void testMultiDocuments();
void testJumpCursor();
+ void testRenderSearchResult();
void testABI();
CPPUNIT_TEST_SUITE(DesktopLOKTest);
@@ -268,6 +271,7 @@ public:
CPPUNIT_TEST(testMetricField);
CPPUNIT_TEST(testMultiDocuments);
CPPUNIT_TEST(testJumpCursor);
+ CPPUNIT_TEST(testRenderSearchResult);
CPPUNIT_TEST(testABI);
CPPUNIT_TEST_SUITE_END();
@@ -3103,6 +3107,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, vcl::PixelFormat::N32_BPP, true, 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)
@@ -3200,10 +3246,11 @@ void DesktopLOKTest::testABI()
CPPUNIT_ASSERT_EQUAL(documentClassOffset(59), offsetof(struct _LibreOfficeKitDocumentClass, completeFunction));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(60), offsetof(struct _LibreOfficeKitDocumentClass, setWindowTextSelection));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(61), offsetof(struct _LibreOfficeKitDocumentClass, sendFormFieldEvent));
+ CPPUNIT_ASSERT_EQUAL(documentClassOffset(62), offsetof(struct _LibreOfficeKitDocumentClass, renderSearchResult));
// Extending is fine, update this, and add new assert for the offsetof the
// new method
- CPPUNIT_ASSERT_EQUAL(documentClassOffset(62), sizeof(struct _LibreOfficeKitDocumentClass));
+ CPPUNIT_ASSERT_EQUAL(documentClassOffset(63), sizeof(struct _LibreOfficeKitDocumentClass));
}
CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index c9778d2b0f81..434b2bda81fa 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -43,6 +43,7 @@
#include <vcl/errinf.hxx>
#include <vcl/lok.hxx>
#include <o3tl/any.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <osl/thread.h>
@@ -1192,6 +1193,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 {
@@ -1331,6 +1337,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;
gDocumentClass = m_pDocumentClass;
}
@@ -5726,6 +5733,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 = o3tl::convert(aRangeUnion.getWidth(), o3tl::Length::twip, o3tl::Length::px);
+ int aPixelHeight = o3tl::convert(aRangeUnion.getHeight(), o3tl::Length::twip, o3tl::Length::px);
+
+ 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 82738d65ff93..8c9e0012552e 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -458,6 +458,12 @@ struct _LibreOfficeKitDocumentClass
void (*sendFormFieldEvent) (LibreOfficeKitDocument* pThis,
const char* pArguments);
+ /// @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 06fe5abc19e2..b1d579849cbd 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -787,6 +787,22 @@ public:
mpDoc->pClass->sendFormFieldEvent(mpDoc, pArguments);
}
+ /**
+ * 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/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index a1107e8a605a..c40c6f1cfb44 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 79044005530a..02e2d8efb365 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -443,6 +443,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/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index b8f81db2f58b..8ea3697192b4 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -163,6 +163,8 @@
#include <svx/svdpage.hxx>
#include <IDocumentOutlineNodes.hxx>
+#include <SearchResultLocator.hxx>
+#include <boost/property_tree/json_parser.hpp>
#define TWIPS_PER_PIXEL 15
@@ -3390,6 +3392,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;