diff options
-rw-r--r-- | desktop/qa/data/SearchIndexResultTest.odt | bin | 0 -> 126871 bytes | |||
-rw-r--r-- | desktop/qa/desktop_lib/test_desktop_lib.cxx | 49 | ||||
-rw-r--r-- | desktop/source/lib/init.cxx | 57 | ||||
-rw-r--r-- | include/LibreOfficeKit/LibreOfficeKit.h | 6 | ||||
-rw-r--r-- | include/LibreOfficeKit/LibreOfficeKit.hxx | 16 | ||||
-rw-r--r-- | include/vcl/ITiledRenderable.hxx | 9 | ||||
-rw-r--r-- | sw/inc/unotxdoc.hxx | 3 | ||||
-rw-r--r-- | sw/source/uibase/uno/unotxdoc.cxx | 25 |
8 files changed, 164 insertions, 1 deletions
diff --git a/desktop/qa/data/SearchIndexResultTest.odt b/desktop/qa/data/SearchIndexResultTest.odt Binary files differnew file mode 100644 index 000000000000..58ed3a0f5447 --- /dev/null +++ b/desktop/qa/data/SearchIndexResultTest.odt 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; |