diff options
author | Tor Lillqvist <tml@collabora.com> | 2023-02-21 13:19:42 +0200 |
---|---|---|
committer | Tor Lillqvist <tml@collabora.com> | 2023-02-22 08:14:30 +0000 |
commit | 1aa37ca99112c0760552600d7774ba7224581c5b (patch) | |
tree | 90fe0a1eee3280c6c7d1f8ccb85fa7e3d874022e | |
parent | bdc4dc93a9edd5f46bdede12514ac5f66bf43167 (diff) |
Extend LOKit API with functionality to extract a request and paint thumbnails
Original author was Mert Tümer.
Change-Id: I181a9955bcce1d5ee4c81e2a52445ef318dc4823
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147396
Tested-by: Jenkins
Reviewed-by: Tor Lillqvist <tml@collabora.com>
-rw-r--r-- | desktop/qa/desktop_lib/test_desktop_lib.cxx | 16 | ||||
-rw-r--r-- | desktop/source/lib/init.cxx | 175 | ||||
-rw-r--r-- | include/LibreOfficeKit/LibreOfficeKit.h | 10 | ||||
-rw-r--r-- | include/LibreOfficeKit/LibreOfficeKit.hxx | 10 |
4 files changed, 208 insertions, 3 deletions
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 3d2fc3c0d2fb..c143662d7dd4 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -3549,6 +3549,15 @@ void DesktopLOKTest::testABI() CPPUNIT_ASSERT_EQUAL(classOffset(9), offsetof(struct _LibreOfficeKitClass, getVersionInfo)); CPPUNIT_ASSERT_EQUAL(classOffset(10), offsetof(struct _LibreOfficeKitClass, runMacro)); CPPUNIT_ASSERT_EQUAL(classOffset(11), offsetof(struct _LibreOfficeKitClass, signDocument)); + CPPUNIT_ASSERT_EQUAL(classOffset(12), offsetof(struct _LibreOfficeKitClass, runLoop)); + CPPUNIT_ASSERT_EQUAL(classOffset(13), offsetof(struct _LibreOfficeKitClass, sendDialogEvent)); + CPPUNIT_ASSERT_EQUAL(classOffset(14), offsetof(struct _LibreOfficeKitClass, setOption)); + CPPUNIT_ASSERT_EQUAL(classOffset(15), offsetof(struct _LibreOfficeKitClass, dumpState)); + CPPUNIT_ASSERT_EQUAL(classOffset(16), offsetof(struct _LibreOfficeKitClass, extractRequest)); + + // When extending LibreOfficeKit with a new function pointer, add new assert for the offsetof the + // new function pointer and bump this assert for the size of the class. + CPPUNIT_ASSERT_EQUAL(classOffset(17), sizeof(struct _LibreOfficeKitClass)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct _LibreOfficeKitDocumentClass, destroy)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct _LibreOfficeKitDocumentClass, saveAs)); @@ -3626,10 +3635,11 @@ void DesktopLOKTest::testABI() CPPUNIT_ASSERT_EQUAL(documentClassOffset(67), offsetof(struct _LibreOfficeKitDocumentClass, getEditMode)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(68), offsetof(struct _LibreOfficeKitDocumentClass, setViewTimezone)); + CPPUNIT_ASSERT_EQUAL(documentClassOffset(69), offsetof(struct _LibreOfficeKitDocumentClass, paintThumbnail)); + - // Extending is fine, update this, and add new assert for the offsetof the - // new method - CPPUNIT_ASSERT_EQUAL(documentClassOffset(69), sizeof(struct _LibreOfficeKitDocumentClass)); + // As above + CPPUNIT_ASSERT_EQUAL(documentClassOffset(70), sizeof(struct _LibreOfficeKitDocumentClass)); } CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest); diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index ed601003d042..1a077ce19500 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -67,6 +67,7 @@ #include <cppuhelper/bootstrap.hxx> #include <comphelper/base64.hxx> #include <comphelper/dispatchcommand.hxx> +#include <comphelper/propertysequence.hxx> #include <comphelper/lok.hxx> #include <comphelper/processfactory.hxx> #include <comphelper/string.hxx> @@ -179,6 +180,7 @@ // Needed for getUndoManager() #include <com/sun/star/document/XUndoManager.hpp> #include <com/sun/star/document/XUndoManagerSupplier.hpp> +#include <com/sun/star/document/XLinkTargetSupplier.hpp> #include <editeng/sizeitem.hxx> #include <svx/rulritem.hxx> #include <svx/pageitem.hxx> @@ -399,6 +401,97 @@ std::vector<beans::PropertyValue> desktop::jsonToPropertyValuesVector(const char return aArguments; } +static bool extractLinks(const uno::Reference< container::XNameAccess >& xLinks, bool subcontent, OUStringBuffer& jsonText) +{ + const uno::Sequence< OUString > aNames( xLinks->getElementNames() ); + + const sal_uLong nLinks = aNames.getLength(); + const OUString* pNames = aNames.getConstArray(); + const OUString aProp_LinkDisplayName( "LinkDisplayName" ); + const OUString aProp_LinkTarget( "com.sun.star.document.LinkTarget" ); + bool bIsTarget = false; + for( sal_uLong i = 0; i < nLinks; i++ ) + { + uno::Any aAny; + OUString aLink( *pNames++ ); + + bool bError = false; + try + { + aAny = xLinks->getByName( aLink ); + } + catch(const uno::Exception&) + { + // if the name of the target was invalid (like empty headings) + // no object can be provided + bError = true; + } + if(bError) + continue; + + uno::Reference< beans::XPropertySet > xTarget; + if( aAny >>= xTarget ) + { + try + { + // get name to display + aAny = xTarget->getPropertyValue( aProp_LinkDisplayName ); + OUString aDisplayName; + aAny >>= aDisplayName; + OUString aStrDisplayname ( aDisplayName ); + + if (subcontent) + { + jsonText.append("\""); + jsonText.append(aStrDisplayname); + jsonText.append("\": \""); + jsonText.append(aLink); + jsonText.append("\""); + if (i < nLinks-1) + { + jsonText.append(", "); + } + } + else + { + uno::Reference< lang::XServiceInfo > xSI( xTarget, uno::UNO_QUERY ); + bIsTarget = xSI->supportsService( aProp_LinkTarget ); + if (i != 0) + { + if (!bIsTarget) + jsonText.append("}"); + if (i < nLinks) + { + jsonText.append(", "); + } + } + jsonText.append("\""); + jsonText.append(aStrDisplayname); + jsonText.append("\": "); + + if (bIsTarget) + { + jsonText.append("true"); + continue; + } + jsonText.append("{"); + } + + uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, uno::UNO_QUERY ); + if( xLTS.is() ) + { + extractLinks(xLTS->getLinks(), true, jsonText); + } + } + catch(...) + { + SAL_WARN("lok", "extractLinks: Exception"); + } + } + } + return bIsTarget; +} + static void unoAnyToJson(tools::JsonWriter& rJson, const char * pNodeName, const uno::Any& anyItem) { auto aNode = rJson.startNode(pNodeName); @@ -1022,6 +1115,7 @@ static void doc_paintTile(LibreOfficeKitDocument* pThis, const int nCanvasWidth, const int nCanvasHeight, const int nTilePosX, const int nTilePosY, const int nTileWidth, const int nTileHeight); +static void doc_paintThumbnail(LibreOfficeKitDocument* pThis, unsigned char* pBuffer, int x, int y); #ifdef IOS static void doc_paintTileToCGContext(LibreOfficeKitDocument* pThis, void* rCGContext, @@ -1295,6 +1389,7 @@ LibLODocument_Impl::LibLODocument_Impl(uno::Reference <css::lang::XComponent> xC m_pDocumentClass->setPartMode = doc_setPartMode; m_pDocumentClass->getEditMode = doc_getEditMode; m_pDocumentClass->paintTile = doc_paintTile; + m_pDocumentClass->paintThumbnail = doc_paintThumbnail; #ifdef IOS m_pDocumentClass->paintTileToCGContext = doc_paintTileToCGContext; #endif @@ -2428,6 +2523,9 @@ static bool lo_signDocument(LibreOfficeKit* pThis, const unsigned char* pPrivateKeyBinary, const int nPrivateKeyBinarySize); +static char* lo_extractRequest(LibreOfficeKit* pThis, + const char* pFilePath); + static void lo_runLoop(LibreOfficeKit* pThis, LibreOfficeKitPollCallback pPollCallback, LibreOfficeKitWakeCallback pWakeCallback, @@ -2468,6 +2566,7 @@ LibLibreOffice_Impl::LibLibreOffice_Impl() m_pOfficeClass->sendDialogEvent = lo_sendDialogEvent; m_pOfficeClass->setOption = lo_setOption; m_pOfficeClass->dumpState = lo_dumpState; + m_pOfficeClass->extractRequest = lo_extractRequest; gOfficeClass = m_pOfficeClass; } @@ -2983,6 +3082,69 @@ static bool lo_signDocument(LibreOfficeKit* /*pThis*/, return true; } + +static char* lo_extractRequest(LibreOfficeKit* /*pThis*/, const char* pFilePath) +{ + uno::Reference<frame::XDesktop2> xComponentLoader = frame::Desktop::create(xContext); + uno::Reference< css::lang::XComponent > xComp; + OUString aURL(getAbsoluteURL(pFilePath)); + OUString result; + if (!aURL.isEmpty()) + { + if (xComponentLoader.is()) + { + try + { + uno::Sequence<css::beans::PropertyValue> aFilterOptions(comphelper::InitPropertySequence( + { + {"Hidden", css::uno::Any(true)}, + {"ReadOnly", css::uno::Any(true)} + })); + xComp = xComponentLoader->loadComponentFromURL( aURL, "_blank", 0, aFilterOptions ); + } + catch ( const lang::IllegalArgumentException& ex ) + { + SAL_WARN("lok", "lo_extractRequest: IllegalArgumentException: " << ex.Message); + result = "{ }"; + return convertOUString(result); + } + catch (...) + { + SAL_WARN("lok", "lo_extractRequest: Exception on loadComponentFromURL, url= " << aURL); + result = "{ }"; + return convertOUString(result); + } + + if (xComp.is()) + { + uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, uno::UNO_QUERY ); + + if( xLTS.is() ) + { + OUStringBuffer jsonText; + jsonText.append("{ \"Targets\": { "); + bool lastParentheses = extractLinks(xLTS->getLinks(), false, jsonText); + jsonText.append("} }"); + if (!lastParentheses) + jsonText.append(" }"); + + OUString res(jsonText.makeStringAndClear()); + return convertOUString(res); + } + xComp->dispose(); + } + else + { + result = "{ }"; + return convertOUString(result); + } + + } + } + result = "{ }"; + return convertOUString(result); +} + static void lo_registerCallback (LibreOfficeKit* pThis, LibreOfficeKitCallback pCallback, void* pData) @@ -3849,6 +4011,19 @@ static void doc_paintTileToCGContext(LibreOfficeKitDocument* pThis, #endif +static void doc_paintThumbnail(LibreOfficeKitDocument* pThis, unsigned char* pBuffer, int x, int y) +{ + constexpr float zoom = 0.5f; + constexpr int pixelWidth = 120; + constexpr int pixelHeight = 120; + constexpr int pixelWidthTwips = pixelWidth * 15 / zoom; + constexpr int pixelHeightTwips = pixelHeight * 15 / zoom; + constexpr int offsetXTwips = 15 * 15; // start 15 px/twips before the target to get a clearer thumbnail + constexpr int offsetYTwips = 15 * 15; + + doc_paintTile(pThis, pBuffer, pixelWidth, pixelHeight, x-offsetXTwips, y-offsetYTwips, pixelWidthTwips, pixelHeightTwips); +} + static void doc_paintPartTile(LibreOfficeKitDocument* pThis, unsigned char* pBuffer, const int nPart, diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h index 74c2100ab18c..4de2380998b4 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.h +++ b/include/LibreOfficeKit/LibreOfficeKit.h @@ -122,6 +122,11 @@ struct _LibreOfficeKitClass /// @see lok::Document::dumpState /// @since LibreOffice 7.5 void (*dumpState) (LibreOfficeKit* pThis, const char* pOptions, char** pState); + + /** @see lok::Office::extractRequest. + */ + char* (*extractRequest) (LibreOfficeKit* pThis, + const char* pFilePath); }; #define LIBREOFFICEKIT_DOCUMENT_HAS(pDoc,member) LIBREOFFICEKIT_HAS_MEMBER(LibreOfficeKitDocumentClass,member,(pDoc)->pClass->nSize) @@ -496,6 +501,11 @@ struct _LibreOfficeKitDocumentClass /// @see lok::Document::setViewTimezone(). void (*setViewTimezone) (LibreOfficeKitDocument* pThis, int nId, const char* timezone); + void (*paintThumbnail) (LibreOfficeKitDocument* pThis, + unsigned char* pBuffer, + int x, + int y); + #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY }; diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx index 2ac398edd497..17fc518fbe13 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.hxx +++ b/include/LibreOfficeKit/LibreOfficeKit.hxx @@ -886,6 +886,11 @@ public: mpDoc->pClass->setViewTimezone(mpDoc, nId, timezone); } + void paintThumbnail(unsigned char* pBuffer, int x, int y) + { + return mpDoc->pClass->paintThumbnail(mpDoc, pBuffer, x, y); + } + #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY }; @@ -1141,6 +1146,11 @@ public: { mpThis->pClass->dumpState(mpThis, pOption, pState); } + + char* extractRequest(const char* pFilePath) + { + return mpThis->pClass->extractRequest(mpThis, pFilePath); + } }; /// Factory method to create a lok::Office instance. |