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/vcl/ITiledRenderable.hxx | 9 ++++ sw/inc/unotxdoc.hxx | 3 + sw/source/uibase/uno/unotxdoc.cxx | 25 ++++++++++++ 8 files changed, 164 insertions(+), 1 deletion(-)
New commits: commit e1511ce551f27a5560600029193f076fd65ece17 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Fri Jul 9 14:41:21 2021 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Fri Jul 30 08:22:19 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 <qui...@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 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; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits