1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <config_folders.h>
19 #include <unicode/udata.h>
20 #include <unicode/ucnv.h>
22 #import <Foundation/Foundation.h>
23 #import <CoreGraphics/CoreGraphics.h>
30 #include <boost/property_tree/json_parser.hpp>
31 #include <boost/algorithm/string.hpp>
33 #include <LibreOfficeKit/LibreOfficeKit.h>
34 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
36 #include <sal/log.hxx>
37 #include <vcl/errinf.hxx>
38 #include <osl/file.hxx>
39 #include <osl/process.h>
40 #include <osl/thread.h>
41 #include <rtl/bootstrap.hxx>
42 #include <rtl/strbuf.hxx>
43 #include <rtl/uri.hxx>
44 #include <cppuhelper/bootstrap.hxx>
45 #include <comphelper/dispatchcommand.hxx>
46 #include <comphelper/lok.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/string.hxx>
49 #include <comphelper/propertysequence.hxx>
50 #include <comphelper/scopeguard.hxx>
51 #include <comphelper/threadpool.hxx>
52 #include <comphelper/base64.hxx>
54 #include <com/sun/star/beans/XPropertySet.hpp>
55 #include <com/sun/star/container/XNameAccess.hpp>
56 #include <com/sun/star/frame/Desktop.hpp>
57 #include <com/sun/star/frame/DispatchResultEvent.hpp>
58 #include <com/sun/star/frame/DispatchResultState.hpp>
59 #include <com/sun/star/frame/XDispatchProvider.hpp>
60 #include <com/sun/star/frame/XDispatchResultListener.hpp>
61 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
62 #include <com/sun/star/frame/XStorable.hpp>
63 #include <com/sun/star/lang/Locale.hpp>
64 #include <com/sun/star/lang/XComponent.hpp>
65 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
66 #include <com/sun/star/reflection/theCoreReflection.hpp>
67 #include <com/sun/star/reflection/XIdlClass.hpp>
68 #include <com/sun/star/reflection/XIdlReflection.hpp>
69 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
70 #include <com/sun/star/ucb/XContentProvider.hpp>
71 #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
72 #include <com/sun/star/util/URLTransformer.hpp>
73 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
74 #include <com/sun/star/text/TextContentAnchorType.hpp>
75 #include <com/sun/star/document/XRedlinesSupplier.hpp>
76 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
78 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
79 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
80 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
81 #include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
82 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
83 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
84 #include <com/sun/star/security/XCertificate.hpp>
86 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
87 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
88 #include <com/sun/star/i18n/ScriptType.hpp>
90 #include <editeng/fontitem.hxx>
91 #include <editeng/flstitem.hxx>
92 #include <sfx2/objsh.hxx>
93 #include <sfx2/viewsh.hxx>
94 #include <sfx2/viewfrm.hxx>
95 #include <sfx2/msgpool.hxx>
96 #include <sfx2/dispatch.hxx>
97 #include <sfx2/DocumentSigner.hxx>
98 #include <svx/dialmgr.hxx>
99 #include <svx/dialogs.hrc>
100 #include <svx/strings.hrc>
101 #include <svx/ruler.hxx>
102 #include <svx/svxids.hrc>
103 #include <svx/ucsubset.hxx>
104 #include <vcl/vclevent.hxx>
105 #include <vcl/svapp.hxx>
106 #include <unotools/resmgr.hxx>
107 #include <tools/fract.hxx>
108 #include <svtools/ctrltool.hxx>
109 #include <svtools/langtab.hxx>
110 #include <vcl/floatwin.hxx>
111 #include <vcl/fontcharmap.hxx>
112 #include <vcl/graphicfilter.hxx>
113 #include <vcl/ptrstyle.hxx>
114 #include <vcl/sysdata.hxx>
115 #include <vcl/virdev.hxx>
116 #include <vcl/ImageTree.hxx>
117 #include <vcl/ITiledRenderable.hxx>
118 #include <vcl/IDialogRenderable.hxx>
119 #include <unicode/uchar.h>
120 #include <unotools/configmgr.hxx>
121 #include <unotools/syslocaleoptions.hxx>
122 #include <unotools/mediadescriptor.hxx>
123 #include <unotools/pathoptions.hxx>
124 #include <unotools/tempfile.hxx>
125 #include <unotools/streamwrap.hxx>
126 #include <osl/module.hxx>
127 #include <comphelper/sequence.hxx>
128 #include <sfx2/sfxbasemodel.hxx>
129 #include <svl/undo.hxx>
130 #include <unotools/datetime.hxx>
131 #include <i18nlangtag/mslangid.hxx>
132 #include <i18nlangtag/languagetag.hxx>
133 #include <vcl/builder.hxx>
134 #include <vcl/abstdlg.hxx>
138 #include "../app/cmdlineargs.hxx"
139 // We also need to hackily be able to start the main libreoffice thread:
140 #include "../app/sofficemain.h"
141 #include "../app/officeipcthread.hxx"
142 #include <lib/init.hxx>
144 #include "lokinteractionhandler.hxx"
145 #include "lokclipboard.hxx"
149 using namespace desktop
;
152 static LibLibreOffice_Impl
*gImpl
= nullptr;
153 static std::weak_ptr
< LibreOfficeKitClass
> gOfficeClass
;
154 static std::weak_ptr
< LibreOfficeKitDocumentClass
> gDocumentClass
;
159 const char *filterName
;
162 static const ExtensionMap aWriterExtensionMap
[] =
164 { "doc", "MS Word 97" },
165 { "docm", "MS Word 2007 XML VBA" },
166 { "docx", "MS Word 2007 XML" },
167 { "fodt", "OpenDocument Text Flat XML" },
168 { "html", "HTML (StarWriter)" },
169 { "odt", "writer8" },
170 { "ott", "writer8_template" },
171 { "pdf", "writer_pdf_Export" },
173 { "rtf", "Rich Text Format" },
175 { "xhtml", "XHTML Writer File" },
176 { "png", "writer_png_Export" },
180 static const ExtensionMap aCalcExtensionMap
[] =
182 { "csv", "Text - txt - csv (StarCalc)" },
183 { "fods", "OpenDocument Spreadsheet Flat XML" },
184 { "html", "HTML (StarCalc)" },
186 { "ots", "calc8_template" },
187 { "pdf", "calc_pdf_Export" },
188 { "xhtml", "XHTML Calc File" },
189 { "xls", "MS Excel 97" },
190 { "xlsm", "Calc MS Excel 2007 VBA XML" },
191 { "xlsx", "Calc MS Excel 2007 XML" },
192 { "png", "calc_png_Export" },
196 static const ExtensionMap aImpressExtensionMap
[] =
198 { "fodp", "OpenDocument Presentation Flat XML" },
199 { "html", "impress_html_Export" },
200 { "odg", "impress8_draw" },
201 { "odp", "impress8" },
202 { "otp", "impress8_template" },
203 { "pdf", "impress_pdf_Export" },
204 { "potm", "Impress MS PowerPoint 2007 XML Template" },
205 { "pot", "MS PowerPoint 97 Vorlage" },
206 { "pptm", "Impress MS PowerPoint 2007 XML VBA" },
207 { "pptx", "Impress MS PowerPoint 2007 XML" },
208 { "pps", "MS PowerPoint 97 Autoplay" },
209 { "ppt", "MS PowerPoint 97" },
210 { "svg", "impress_svg_Export" },
211 { "swf", "impress_flash_Export" },
212 { "xhtml", "XHTML Impress File" },
213 { "png", "impress_png_Export"},
217 static const ExtensionMap aDrawExtensionMap
[] =
219 { "fodg", "draw_ODG_FlatXML" },
220 { "html", "draw_html_Export" },
222 { "pdf", "draw_pdf_Export" },
223 { "svg", "draw_svg_Export" },
224 { "swf", "draw_flash_Export" },
225 { "xhtml", "XHTML Draw File" },
226 { "png", "draw_png_Export"},
230 static OUString
getUString(const char* pString
)
232 if (pString
== nullptr)
235 OString
sString(pString
, strlen(pString
));
236 return OStringToOUString(sString
, RTL_TEXTENCODING_UTF8
);
239 /// Try to convert a relative URL to an absolute one, unless it already looks like an URL.
240 static OUString
getAbsoluteURL(const char* pURL
)
242 OUString
aURL(getUString(pURL
));
246 // convert relative paths to absolute ones
247 OUString aWorkingDir
;
248 osl_getProcessWorkingDir(&aWorkingDir
.pData
);
249 if (!aWorkingDir
.endsWith("/"))
254 return rtl::Uri::convertRelToAbs(aWorkingDir
, aURL
);
256 catch (const rtl::MalformedUriException
&)
263 static uno::Any
jsonToUnoAny(const boost::property_tree::ptree
& aTree
)
268 uno::TypeClass aTypeClass
;
269 uno::Reference
< reflection::XIdlField
> aField
;
270 boost::property_tree::ptree aNodeNull
, aNodeValue
, aNodeField
;
271 const std::string
& rType
= aTree
.get
<std::string
>("type", "");
272 const std::string
& rValue
= aTree
.get
<std::string
>("value", "");
273 uno::Sequence
< uno::Reference
< reflection::XIdlField
> > aFields
;
274 uno::Reference
< reflection:: XIdlClass
> xIdlClass
=
275 css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())->forName(OUString::fromUtf8(rType
.c_str()));
278 aTypeClass
= xIdlClass
->getTypeClass();
279 xIdlClass
->createObject(aAny
);
280 aFields
= xIdlClass
->getFields();
281 nFields
= aFields
.getLength();
282 aNodeValue
= aTree
.get_child("value", aNodeNull
);
283 if (nFields
> 0 && aNodeValue
!= aNodeNull
)
285 for (sal_Int32 itField
= 0; itField
< nFields
; ++itField
)
287 aField
= aFields
[itField
];
288 aNodeField
= aNodeValue
.get_child(aField
->getName().toUtf8().getStr(), aNodeNull
);
289 if (aNodeField
!= aNodeNull
)
291 aValue
= jsonToUnoAny(aNodeField
);
292 aField
->set(aAny
, aValue
);
296 else if (!rValue
.empty())
298 if (aTypeClass
== uno::TypeClass_VOID
)
300 else if (aTypeClass
== uno::TypeClass_BYTE
)
301 aAny
<<= static_cast<sal_Int8
>(OString(rValue
.c_str()).toInt32());
302 else if (aTypeClass
== uno::TypeClass_BOOLEAN
)
303 aAny
<<= OString(rValue
.c_str()).toBoolean();
304 else if (aTypeClass
== uno::TypeClass_SHORT
)
305 aAny
<<= static_cast<sal_Int16
>(OString(rValue
.c_str()).toInt32());
306 else if (aTypeClass
== uno::TypeClass_UNSIGNED_SHORT
)
307 aAny
<<= static_cast<sal_uInt16
>(OString(rValue
.c_str()).toUInt32());
308 else if (aTypeClass
== uno::TypeClass_LONG
)
309 aAny
<<= OString(rValue
.c_str()).toInt32();
310 else if (aTypeClass
== uno::TypeClass_UNSIGNED_LONG
)
311 aAny
<<= static_cast<sal_uInt32
>(OString(rValue
.c_str()).toInt32());
312 else if (aTypeClass
== uno::TypeClass_FLOAT
)
313 aAny
<<= OString(rValue
.c_str()).toFloat();
314 else if (aTypeClass
== uno::TypeClass_DOUBLE
)
315 aAny
<<= OString(rValue
.c_str()).toDouble();
316 else if (aTypeClass
== uno::TypeClass_STRING
)
317 aAny
<<= OUString::fromUtf8(rValue
.c_str());
323 std::vector
<beans::PropertyValue
> desktop::jsonToPropertyValuesVector(const char* pJSON
)
325 std::vector
<beans::PropertyValue
> aArguments
;
326 if (pJSON
&& pJSON
[0] != '\0')
328 boost::property_tree::ptree aTree
, aNodeNull
, aNodeValue
;
329 std::stringstream
aStream(pJSON
);
330 boost::property_tree::read_json(aStream
, aTree
);
332 for (const auto& rPair
: aTree
)
334 const std::string
& rType
= rPair
.second
.get
<std::string
>("type", "");
335 const std::string
& rValue
= rPair
.second
.get
<std::string
>("value", "");
337 beans::PropertyValue aValue
;
338 aValue
.Name
= OUString::fromUtf8(rPair
.first
.c_str());
339 if (rType
== "string")
340 aValue
.Value
<<= OUString::fromUtf8(rValue
.c_str());
341 else if (rType
== "boolean")
342 aValue
.Value
<<= OString(rValue
.c_str()).toBoolean();
343 else if (rType
== "float")
344 aValue
.Value
<<= OString(rValue
.c_str()).toFloat();
345 else if (rType
== "long")
346 aValue
.Value
<<= OString(rValue
.c_str()).toInt32();
347 else if (rType
== "short")
348 aValue
.Value
<<= static_cast<sal_Int16
>(OString(rValue
.c_str()).toInt32());
349 else if (rType
== "unsigned short")
350 aValue
.Value
<<= static_cast<sal_uInt16
>(OString(rValue
.c_str()).toUInt32());
351 else if (rType
== "[]any")
353 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
354 if (aNodeValue
!= aNodeNull
&& !aNodeValue
.empty())
357 uno::Sequence
< uno::Any
> aSeq(aNodeValue
.size());
358 for (const auto& rSeqPair
: aNodeValue
)
359 aSeq
[itSeq
++] = jsonToUnoAny(rSeqPair
.second
);
360 aValue
.Value
<<= aSeq
;
364 SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled type '"<<rType
<<"'");
365 aArguments
.push_back(aValue
);
371 static boost::property_tree::ptree
unoAnyToPropertyTree(const uno::Any
& anyItem
)
373 boost::property_tree::ptree aTree
;
374 OUString aType
= anyItem
.getValueTypeName();
375 aTree
.put("type", aType
.toUtf8().getStr());
377 if (aType
== "string")
378 aTree
.put("value", anyItem
.get
<OUString
>().toUtf8().getStr());
379 else if (aType
== "unsigned long")
380 aTree
.put("value", OString::number(anyItem
.get
<sal_uInt32
>()).getStr());
381 else if (aType
== "long")
382 aTree
.put("value", OString::number(anyItem
.get
<sal_Int32
>()).getStr());
383 else if (aType
== "[]any")
385 uno::Sequence
<uno::Any
> aSeq
;
386 if (anyItem
>>= aSeq
)
388 boost::property_tree::ptree aSubTree
;
390 for (auto i
= 0; i
< aSeq
.getLength(); ++i
)
392 aSubTree
.add_child(OString::number(i
).getStr(), unoAnyToPropertyTree(aSeq
[i
]));
394 aTree
.add_child("value", aSubTree
);
398 // TODO: Add more as required
405 RectangleAndPart
RectangleAndPart::Create(const std::string
& rPayload
)
407 RectangleAndPart aRet
;
408 if (rPayload
.compare(0, 5, "EMPTY") == 0) // payload starts with "EMPTY"
410 aRet
.m_aRectangle
= tools::Rectangle(0, 0, SfxLokHelper::MaxTwips
, SfxLokHelper::MaxTwips
);
411 if (comphelper::LibreOfficeKit::isPartInInvalidation())
412 aRet
.m_nPart
= std::stol(rPayload
.substr(6));
417 std::istringstream
aStream(rPayload
);
418 long nLeft
, nTop
, nWidth
, nHeight
;
419 long nPart
= INT_MIN
;
421 if (comphelper::LibreOfficeKit::isPartInInvalidation())
423 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
>> nComma
>> nPart
;
427 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
430 if (nWidth
> 0 && nHeight
> 0)
432 // The top-left corner starts at (0, 0).
433 // Anything negative is invalid.
446 if (nWidth
> 0 && nHeight
> 0)
448 aRet
.m_aRectangle
= tools::Rectangle(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
451 // else leave empty rect.
453 aRet
.m_nPart
= nPart
;
457 RectangleAndPart
& CallbackFlushHandler::CallbackData::setRectangleAndPart(const std::string
& payload
)
459 setRectangleAndPart(RectangleAndPart::Create(payload
));
461 // Return reference to the cached object.
462 return boost::get
<RectangleAndPart
>(PayloadObject
);
465 void CallbackFlushHandler::CallbackData::setRectangleAndPart(const RectangleAndPart
& rRectAndPart
)
467 PayloadString
= rRectAndPart
.toString().getStr();
468 PayloadObject
= rRectAndPart
;
471 const RectangleAndPart
& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
473 assert(PayloadObject
.which() == 1);
474 return boost::get
<RectangleAndPart
>(PayloadObject
);
477 boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::setJson(const std::string
& payload
)
479 boost::property_tree::ptree aTree
;
480 std::stringstream
aStream(payload
);
481 boost::property_tree::read_json(aStream
, aTree
);
483 // Let boost normalize the payload so it always matches the cache.
486 // Return reference to the cached object.
487 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
490 void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree
& rTree
)
492 std::stringstream aJSONStream
;
493 constexpr bool bPretty
= false; // Don't waste time and bloat logs.
494 boost::property_tree::write_json(aJSONStream
, rTree
, bPretty
);
495 PayloadString
= boost::trim_copy(aJSONStream
.str());
497 PayloadObject
= rTree
;
500 const boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::getJson() const
502 assert(PayloadObject
.which() == 2);
503 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
506 bool CallbackFlushHandler::CallbackData::validate() const
508 switch (PayloadObject
.which())
516 return getRectangleAndPart().toString().getStr() == PayloadString
;
521 std::stringstream aJSONStream
;
522 boost::property_tree::write_json(aJSONStream
, getJson(), false);
523 const std::string aExpected
= boost::trim_copy(aJSONStream
.str());
524 return aExpected
== PayloadString
;
528 assert(!"Unknown variant type; please add an entry to validate.");
538 bool lcl_isViewCallbackType(const int type
)
542 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
543 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
544 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
545 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
546 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
554 int lcl_getViewId(const std::string
& payload
)
556 // this is a cheap way how to get the viewId from a JSON message; proper
557 // parsing is terribly expensive, and we just need the viewId here
558 size_t viewIdPos
= payload
.find("viewId");
559 if (viewIdPos
== std::string::npos
)
562 size_t numberPos
= payload
.find(":", viewIdPos
+ 6);
563 if (numberPos
== std::string::npos
)
566 for (++numberPos
; numberPos
< payload
.length(); ++numberPos
)
568 if (payload
[numberPos
] == ',' || payload
[numberPos
] == '}' || (payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9'))
572 if (numberPos
< payload
.length() && payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9')
573 return strtol(payload
.substr(numberPos
).c_str(), nullptr, 10);
578 std::string
extractCertificate(const std::string
& certificate
)
580 const std::string
header("-----BEGIN CERTIFICATE-----");
581 const std::string
footer("-----END CERTIFICATE-----");
585 size_t pos1
= certificate
.find(header
);
586 if (pos1
== std::string::npos
)
589 size_t pos2
= certificate
.find(footer
, pos1
+ 1);
590 if (pos2
== std::string::npos
)
593 pos1
= pos1
+ header
.length();
596 return certificate
.substr(pos1
, pos2
);
599 std::string
extractPrivateKey(const std::string
& privateKey
)
601 const std::string
header("-----BEGIN PRIVATE KEY-----");
602 const std::string
footer("-----END PRIVATE KEY-----");
606 size_t pos1
= privateKey
.find(header
);
607 if (pos1
== std::string::npos
)
610 size_t pos2
= privateKey
.find(footer
, pos1
+ 1);
611 if (pos2
== std::string::npos
)
614 pos1
= pos1
+ header
.length();
617 return privateKey
.substr(pos1
, pos2
);
620 } // end anonymous namespace
622 // Could be anonymous in principle, but for the unit testing purposes, we
623 // declare it in init.hxx.
624 OUString
desktop::extractParameter(OUString
& rOptions
, const OUString
& rName
)
628 OUString
aNameEquals(rName
+ "=");
629 OUString
aCommaNameEquals("," + rName
+ "=");
632 if (rOptions
.startsWith(aNameEquals
))
634 size_t nLen
= aNameEquals
.getLength();
635 int nComma
= rOptions
.indexOf(",", nLen
);
638 aValue
= rOptions
.copy(nLen
, nComma
- nLen
);
639 rOptions
= rOptions
.copy(nComma
+ 1);
643 aValue
= rOptions
.copy(nLen
);
647 else if ((nIndex
= rOptions
.indexOf(aCommaNameEquals
)) >= 0)
649 size_t nLen
= aCommaNameEquals
.getLength();
650 int nComma
= rOptions
.indexOf(",", nIndex
+ nLen
);
653 aValue
= rOptions
.copy(nIndex
+ nLen
, nComma
- nIndex
- nLen
);
654 rOptions
= rOptions
.copy(0, nIndex
) + rOptions
.copy(nComma
);
658 aValue
= rOptions
.copy(nIndex
+ nLen
);
659 rOptions
= rOptions
.copy(0, nIndex
);
669 static void doc_destroy(LibreOfficeKitDocument
* pThis
);
670 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* pUrl
, const char* pFormat
, const char* pFilterOptions
);
671 static int doc_getDocumentType(LibreOfficeKitDocument
* pThis
);
672 static int doc_getParts(LibreOfficeKitDocument
* pThis
);
673 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
);
674 static int doc_getPart(LibreOfficeKitDocument
* pThis
);
675 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
);
676 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
);
677 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
, int nPartMode
);
678 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
679 unsigned char* pBuffer
,
680 const int nCanvasWidth
, const int nCanvasHeight
,
681 const int nTilePosX
, const int nTilePosY
,
682 const int nTileWidth
, const int nTileHeight
);
684 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
686 const int nCanvasWidth
, const int nCanvasHeight
,
687 const int nTilePosX
, const int nTilePosY
,
688 const int nTileWidth
, const int nTileHeight
);
690 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
691 unsigned char* pBuffer
,
693 const int nCanvasWidth
, const int nCanvasHeight
,
694 const int nTilePosX
, const int nTilePosY
,
695 const int nTileWidth
, const int nTileHeight
);
696 static int doc_getTileMode(LibreOfficeKitDocument
* pThis
);
697 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
700 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
701 const char* pArguments
);
703 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
704 LibreOfficeKitCallback pCallback
,
706 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
,
710 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
,
714 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* pThis
,
715 unsigned nLOKWindowId
,
719 static void doc_postMouseEvent (LibreOfficeKitDocument
* pThis
,
726 static void doc_postWindowMouseEvent (LibreOfficeKitDocument
* pThis
,
727 unsigned nLOKWindowId
,
734 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
,
735 const char* pCommand
,
736 const char* pArguments
,
737 bool bNotifyWhenFinished
);
738 static void doc_setTextSelection (LibreOfficeKitDocument
* pThis
,
742 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
,
743 const char* pMimeType
,
744 char** pUsedMimeType
);
745 static bool doc_paste(LibreOfficeKitDocument
* pThis
,
746 const char* pMimeType
,
749 static void doc_setGraphicSelection (LibreOfficeKitDocument
* pThis
,
753 static void doc_resetSelection (LibreOfficeKitDocument
* pThis
);
754 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
);
755 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
,
757 int nTilePixelHeight
,
759 int nTileTwipHeight
);
760 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
);
761 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
);
762 static int doc_createView(LibreOfficeKitDocument
* pThis
);
763 static void doc_destroyView(LibreOfficeKitDocument
* pThis
, int nId
);
764 static void doc_setView(LibreOfficeKitDocument
* pThis
, int nId
);
765 static int doc_getView(LibreOfficeKitDocument
* pThis
);
766 static int doc_getViewsCount(LibreOfficeKitDocument
* pThis
);
767 static bool doc_getViewIds(LibreOfficeKitDocument
* pThis
, int* pArray
, size_t nSize
);
768 static void doc_setViewLanguage(LibreOfficeKitDocument
* pThis
, int nId
, const char* language
);
769 static unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
770 const char *pFontName
,
774 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
);
776 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
777 const int nX
, const int nY
,
778 const int nWidth
, const int nHeight
);
780 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
781 const int nX
, const int nY
,
782 const int nWidth
, const int nHeight
,
783 const double fDPIScale
);
785 static void doc_postWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, int nAction
);
787 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
);
789 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
790 const unsigned char* pCertificateBinary
,
791 const int nCertificateBinarySize
,
792 const unsigned char* pPrivateKeyBinary
,
793 const int nPrivateKeyBinarySize
);
795 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
796 const unsigned char* pCertificateBinary
,
797 const int nCertificateBinarySize
);
799 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
);
801 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
);
803 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference
<css::lang::XComponent
> &xComponent
)
804 : mxComponent(xComponent
)
806 if (!(m_pDocumentClass
= gDocumentClass
.lock()))
808 m_pDocumentClass
.reset(new LibreOfficeKitDocumentClass
);
810 m_pDocumentClass
->nSize
= sizeof(LibreOfficeKitDocumentClass
);
812 m_pDocumentClass
->destroy
= doc_destroy
;
813 m_pDocumentClass
->saveAs
= doc_saveAs
;
814 m_pDocumentClass
->getDocumentType
= doc_getDocumentType
;
815 m_pDocumentClass
->getParts
= doc_getParts
;
816 m_pDocumentClass
->getPartPageRectangles
= doc_getPartPageRectangles
;
817 m_pDocumentClass
->getPart
= doc_getPart
;
818 m_pDocumentClass
->setPart
= doc_setPart
;
819 m_pDocumentClass
->getPartName
= doc_getPartName
;
820 m_pDocumentClass
->setPartMode
= doc_setPartMode
;
821 m_pDocumentClass
->paintTile
= doc_paintTile
;
823 m_pDocumentClass
->paintTileToCGContext
= doc_paintTileToCGContext
;
825 m_pDocumentClass
->paintPartTile
= doc_paintPartTile
;
826 m_pDocumentClass
->getTileMode
= doc_getTileMode
;
827 m_pDocumentClass
->getDocumentSize
= doc_getDocumentSize
;
828 m_pDocumentClass
->initializeForRendering
= doc_initializeForRendering
;
829 m_pDocumentClass
->registerCallback
= doc_registerCallback
;
830 m_pDocumentClass
->postKeyEvent
= doc_postKeyEvent
;
831 m_pDocumentClass
->postWindowExtTextInputEvent
= doc_postWindowExtTextInputEvent
;
832 m_pDocumentClass
->postWindowKeyEvent
= doc_postWindowKeyEvent
;
833 m_pDocumentClass
->postMouseEvent
= doc_postMouseEvent
;
834 m_pDocumentClass
->postWindowMouseEvent
= doc_postWindowMouseEvent
;
835 m_pDocumentClass
->postUnoCommand
= doc_postUnoCommand
;
836 m_pDocumentClass
->setTextSelection
= doc_setTextSelection
;
837 m_pDocumentClass
->getTextSelection
= doc_getTextSelection
;
838 m_pDocumentClass
->paste
= doc_paste
;
839 m_pDocumentClass
->setGraphicSelection
= doc_setGraphicSelection
;
840 m_pDocumentClass
->resetSelection
= doc_resetSelection
;
841 m_pDocumentClass
->getCommandValues
= doc_getCommandValues
;
842 m_pDocumentClass
->setClientZoom
= doc_setClientZoom
;
843 m_pDocumentClass
->setClientVisibleArea
= doc_setClientVisibleArea
;
844 m_pDocumentClass
->setOutlineState
= doc_setOutlineState
;
846 m_pDocumentClass
->createView
= doc_createView
;
847 m_pDocumentClass
->destroyView
= doc_destroyView
;
848 m_pDocumentClass
->setView
= doc_setView
;
849 m_pDocumentClass
->getView
= doc_getView
;
850 m_pDocumentClass
->getViewsCount
= doc_getViewsCount
;
851 m_pDocumentClass
->getViewIds
= doc_getViewIds
;
853 m_pDocumentClass
->renderFont
= doc_renderFont
;
854 m_pDocumentClass
->getPartHash
= doc_getPartHash
;
856 m_pDocumentClass
->paintWindow
= doc_paintWindow
;
857 m_pDocumentClass
->paintWindowDPI
= doc_paintWindowDPI
;
858 m_pDocumentClass
->postWindow
= doc_postWindow
;
860 m_pDocumentClass
->setViewLanguage
= doc_setViewLanguage
;
862 m_pDocumentClass
->getPartInfo
= doc_getPartInfo
;
864 m_pDocumentClass
->insertCertificate
= doc_insertCertificate
;
865 m_pDocumentClass
->addCertificate
= doc_addCertificate
;
866 m_pDocumentClass
->getSignatureState
= doc_getSignatureState
;
868 m_pDocumentClass
->renderShapeSelection
= doc_renderShapeSelection
;
870 gDocumentClass
= m_pDocumentClass
;
872 pClass
= m_pDocumentClass
.get();
875 LibLODocument_Impl::~LibLODocument_Impl()
877 mxComponent
->dispose();
880 CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument
* pDocument
, LibreOfficeKitCallback pCallback
, void* pData
)
881 : Idle( "lokit timer callback" ),
882 m_pDocument(pDocument
),
883 m_pCallback(pCallback
),
885 m_bPartTilePainting(false),
888 SetPriority(TaskPriority::POST_PAINT
);
890 // Add the states that are safe to skip duplicates on,
891 // even when not consequent.
892 m_states
.emplace(LOK_CALLBACK_TEXT_SELECTION
, "NIL");
893 m_states
.emplace(LOK_CALLBACK_GRAPHIC_SELECTION
, "NIL");
894 m_states
.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
, "NIL");
895 m_states
.emplace(LOK_CALLBACK_STATE_CHANGED
, "NIL");
896 m_states
.emplace(LOK_CALLBACK_MOUSE_POINTER
, "NIL");
897 m_states
.emplace(LOK_CALLBACK_CELL_CURSOR
, "NIL");
898 m_states
.emplace(LOK_CALLBACK_CELL_FORMULA
, "NIL");
899 m_states
.emplace(LOK_CALLBACK_CELL_ADDRESS
, "NIL");
900 m_states
.emplace(LOK_CALLBACK_CURSOR_VISIBLE
, "NIL");
901 m_states
.emplace(LOK_CALLBACK_SET_PART
, "NIL");
906 CallbackFlushHandler::~CallbackFlushHandler()
911 void CallbackFlushHandler::callback(const int type
, const char* payload
, void* data
)
913 CallbackFlushHandler
* self
= static_cast<CallbackFlushHandler
*>(data
);
916 self
->queue(type
, payload
);
920 void CallbackFlushHandler::queue(const int type
, const char* data
)
922 CallbackData
aCallbackData(type
, (data
? data
: "(nil)"));
923 const std::string
& payload
= aCallbackData
.PayloadString
;
924 SAL_INFO("lok", "Queue: " << type
<< " : " << payload
);
928 // Dump the queue state and validate cached data.
930 std::ostringstream oss
;
932 for (const CallbackData
& c
: m_queue
)
933 oss
<< i
++ << ": [" << c
.Type
<< "] [" << c
.PayloadString
<< "].\n";
934 const std::string aQueued
= oss
.str();
935 SAL_INFO("lok", "Current Queue: " << (aQueued
.empty() ? "Empty" : aQueued
));
936 for (const CallbackData
& c
: m_queue
)
937 assert(c
.validate());
941 if (m_bPartTilePainting
)
943 // We drop notifications when this is set, except for important ones.
944 // When we issue a complex command (such as .uno:InsertAnnotation)
945 // there will be multiple notifications. On the first invalidation
946 // we will start painting, but other events will get fired
947 // while the complex command in question executes.
948 // We don't want to suppress everything here on the wrong assumption
949 // that no new events are fired during painting.
950 if (type
!= LOK_CALLBACK_STATE_CHANGED
&&
951 type
!= LOK_CALLBACK_INVALIDATE_TILES
&&
952 type
!= LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
953 type
!= LOK_CALLBACK_CURSOR_VISIBLE
&&
954 type
!= LOK_CALLBACK_VIEW_CURSOR_VISIBLE
&&
955 type
!= LOK_CALLBACK_TEXT_SELECTION
)
957 SAL_INFO("lok", "Skipping while painting [" << type
<< "]: [" << payload
<< "].");
961 // In Writer we drop all notifications during painting.
962 if (doc_getDocumentType(m_pDocument
) == LOK_DOCTYPE_TEXT
)
966 // Suppress invalid payloads.
967 if (type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
968 payload
.find(", 0, 0, ") != std::string::npos
)
970 // The cursor position is often the relative coordinates of the widget
971 // issuing it, instead of the absolute one that we expect.
972 // This is temporary however, and, once the control is created and initialized
973 // correctly, it eventually emits the correct absolute coordinates.
974 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
978 std::unique_lock
<std::mutex
> lock(m_mutex
);
980 // drop duplicate callbacks for the listed types
983 case LOK_CALLBACK_TEXT_SELECTION_START
:
984 case LOK_CALLBACK_TEXT_SELECTION_END
:
985 case LOK_CALLBACK_TEXT_SELECTION
:
986 case LOK_CALLBACK_GRAPHIC_SELECTION
:
987 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
988 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
989 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
990 case LOK_CALLBACK_STATE_CHANGED
:
991 case LOK_CALLBACK_MOUSE_POINTER
:
992 case LOK_CALLBACK_CELL_CURSOR
:
993 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
994 case LOK_CALLBACK_CELL_FORMULA
:
995 case LOK_CALLBACK_CELL_ADDRESS
:
996 case LOK_CALLBACK_CURSOR_VISIBLE
:
997 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
998 case LOK_CALLBACK_SET_PART
:
999 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1000 case LOK_CALLBACK_INVALIDATE_HEADER
:
1001 case LOK_CALLBACK_WINDOW
:
1003 const auto& pos
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1004 [type
] (const queue_type::value_type
& elem
) { return (elem
.Type
== type
); });
1006 if (pos
!= m_queue
.rend() && pos
->PayloadString
== payload
)
1008 SAL_INFO("lok", "Skipping queue duplicate [" << type
<< + "]: [" << payload
<< "].");
1015 if (type
== LOK_CALLBACK_TEXT_SELECTION
&& payload
.empty())
1017 const auto& posStart
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1018 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_START
); });
1019 if (posStart
!= m_queue
.rend())
1020 posStart
->PayloadString
.clear();
1022 const auto& posEnd
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1023 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_END
); });
1024 if (posEnd
!= m_queue
.rend())
1025 posEnd
->PayloadString
.clear();
1028 // When payload is empty discards any previous state.
1029 if (payload
.empty())
1033 case LOK_CALLBACK_TEXT_SELECTION_START
:
1034 case LOK_CALLBACK_TEXT_SELECTION_END
:
1035 case LOK_CALLBACK_TEXT_SELECTION
:
1036 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1037 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1038 case LOK_CALLBACK_INVALIDATE_TILES
:
1039 SAL_INFO("lok", "Removing dups of [" << type
<< "]: [" << payload
<< "].");
1040 removeAll([type
] (const queue_type::value_type
& elem
) { return (elem
.Type
== type
); });
1048 // These are safe to use the latest state and ignore previous
1049 // ones (if any) since the last overrides previous ones.
1050 case LOK_CALLBACK_TEXT_SELECTION_START
:
1051 case LOK_CALLBACK_TEXT_SELECTION_END
:
1052 case LOK_CALLBACK_TEXT_SELECTION
:
1053 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1054 case LOK_CALLBACK_MOUSE_POINTER
:
1055 case LOK_CALLBACK_CELL_CURSOR
:
1056 case LOK_CALLBACK_CELL_FORMULA
:
1057 case LOK_CALLBACK_CELL_ADDRESS
:
1058 case LOK_CALLBACK_CURSOR_VISIBLE
:
1059 case LOK_CALLBACK_SET_PART
:
1060 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
:
1061 case LOK_CALLBACK_RULER_UPDATE
:
1063 removeAll([type
] (const queue_type::value_type
& elem
) { return (elem
.Type
== type
); });
1067 // These are safe to use the latest state and ignore previous
1068 // ones (if any) since the last overrides previous ones,
1069 // but only if the view is the same.
1070 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1071 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1072 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1073 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1074 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1076 const int nViewId
= lcl_getViewId(payload
);
1078 [type
, nViewId
] (const queue_type::value_type
& elem
) {
1079 return (elem
.Type
== type
&& nViewId
== lcl_getViewId(elem
.PayloadString
));
1085 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1088 [type
, &payload
] (const queue_type::value_type
& elem
) {
1089 return (elem
.Type
== type
&& elem
.PayloadString
== payload
);
1095 case LOK_CALLBACK_INVALIDATE_TILES
:
1097 RectangleAndPart
& rcNew
= aCallbackData
.setRectangleAndPart(payload
);
1098 if (rcNew
.isEmpty())
1100 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
1104 // If we have to invalidate all tiles, we can skip any new tile invalidation.
1105 // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
1106 const auto& pos
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1107 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
); });
1108 if (pos
!= m_queue
.rend())
1110 const RectangleAndPart
& rcOld
= pos
->getRectangleAndPart();
1111 if (rcOld
.isInfinite() && (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
))
1113 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
<< "] since all tiles need to be invalidated.");
1117 if (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
)
1119 // If fully overlapping.
1120 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1122 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
<< "] since overlaps existing all-parts.");
1128 if (rcNew
.isInfinite())
1130 SAL_INFO("lok", "Have Empty [" << type
<< "]: [" << payload
<< "] so removing all with part " << rcNew
.m_nPart
<< ".");
1132 [&rcNew
] (const queue_type::value_type
& elem
) {
1133 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1135 // Remove exiting if new is all-encompassing, or if of the same part.
1136 const RectangleAndPart rcOld
= RectangleAndPart::Create(elem
.PayloadString
);
1137 return (rcNew
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
);
1147 const auto rcOrig
= rcNew
;
1149 SAL_INFO("lok", "Have [" << type
<< "]: [" << payload
<< "] so merging overlapping.");
1151 [&rcNew
] (const queue_type::value_type
& elem
) {
1152 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1154 const RectangleAndPart
& rcOld
= elem
.getRectangleAndPart();
1155 if (rcNew
.m_nPart
!= -1 && rcOld
.m_nPart
!= -1 && rcOld
.m_nPart
!= rcNew
.m_nPart
)
1157 SAL_INFO("lok", "Nothing to merge between new: " << rcNew
.toString() << ", and old: " << rcOld
.toString());
1161 if (rcNew
.m_nPart
== -1)
1163 // Don't merge unless fully overlapped.
1164 SAL_INFO("lok", "New " << rcNew
.toString() << " has " << rcOld
.toString() << "?");
1165 if (rcNew
.m_aRectangle
.IsInside(rcOld
.m_aRectangle
))
1167 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old " << rcOld
.toString() << ".");
1171 else if (rcOld
.m_nPart
== -1)
1173 // Don't merge unless fully overlapped.
1174 SAL_INFO("lok", "Old " << rcOld
.toString() << " has " << rcNew
.toString() << "?");
1175 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1177 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old " << rcOld
.toString() << ".");
1183 const tools::Rectangle rcOverlap
= rcNew
.m_aRectangle
.GetIntersection(rcOld
.m_aRectangle
);
1184 const bool bOverlap
= !rcOverlap
.IsEmpty();
1185 SAL_INFO("lok", "Merging " << rcNew
.toString() << " & " << rcOld
.toString() << " => " <<
1186 rcOverlap
.toString() << " Overlap: " << bOverlap
);
1189 rcNew
.m_aRectangle
.Union(rcOld
.m_aRectangle
);
1190 SAL_INFO("lok", "Merged: " << rcNew
.toString());
1201 if (rcNew
.m_aRectangle
!= rcOrig
.m_aRectangle
)
1203 SAL_INFO("lok", "Replacing: " << rcOrig
.toString() << " by " << rcNew
.toString());
1204 if (rcNew
.m_aRectangle
.GetWidth() < rcOrig
.m_aRectangle
.GetWidth() ||
1205 rcNew
.m_aRectangle
.GetHeight() < rcOrig
.m_aRectangle
.GetHeight())
1207 SAL_WARN("lok", "Error: merged rect smaller.");
1212 aCallbackData
.setRectangleAndPart(rcNew
);
1216 // State changes with same name override previous ones with a different value.
1217 // Ex. ".uno:PageStatus=Slide 20 of 83" overwrites any previous PageStatus.
1218 case LOK_CALLBACK_STATE_CHANGED
:
1220 // Compare the state name=value and overwrite earlier entries with same name.
1221 const auto pos
= payload
.find('=');
1222 if (pos
!= std::string::npos
)
1224 const std::string name
= payload
.substr(0, pos
+ 1);
1226 [type
, &name
] (const queue_type::value_type
& elem
) {
1227 return (elem
.Type
== type
) && (elem
.PayloadString
.compare(0, name
.size(), name
) == 0);
1234 case LOK_CALLBACK_WINDOW
:
1236 // reading JSON by boost might be slow?
1237 boost::property_tree::ptree
& aTree
= aCallbackData
.setJson(payload
);
1238 const unsigned nLOKWindowId
= aTree
.get
<unsigned>("id", 0);
1239 if (aTree
.get
<std::string
>("action", "") == "invalidate")
1241 std::string aRectStr
= aTree
.get
<std::string
>("rectangle", "");
1242 // no 'rectangle' field => invalidate all of the window =>
1243 // remove all previous window part invalidations
1244 if (aRectStr
.empty())
1246 removeAll([&nLOKWindowId
] (const queue_type::value_type
& elem
) {
1247 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1249 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1250 const unsigned nOldDialogId
= aOldTree
.get
<unsigned>("id", 0);
1251 if (aOldTree
.get
<std::string
>("action", "") == "invalidate" &&
1252 nLOKWindowId
== nOldDialogId
)
1262 // if we have to invalidate all of the window, ignore
1263 // any part invalidation message
1264 const auto invAllExist
= std::any_of(m_queue
.rbegin(), m_queue
.rend(),
1265 [&nLOKWindowId
] (const queue_type::value_type
& elem
)
1267 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1270 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1271 const unsigned nOldDialogId
= aOldTree
.get
<unsigned>("id", 0);
1272 return aOldTree
.get
<std::string
>("action", "") == "invalidate" &&
1273 nLOKWindowId
== nOldDialogId
&&
1274 aOldTree
.get
<std::string
>("rectangle", "").empty();
1277 // we found a invalidate-all window callback
1280 SAL_INFO("lok.dialog", "Skipping queue [" << type
<< "]: [" << payload
<< "] since whole window needs to be invalidated.");
1284 std::istringstream
aRectStream(aRectStr
);
1285 long nLeft
, nTop
, nWidth
, nHeight
;
1287 aRectStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
1288 tools::Rectangle aNewRect
= tools::Rectangle(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
1289 bool currentIsRedundant
= false;
1290 removeAll([&aNewRect
, &nLOKWindowId
, ¤tIsRedundant
] (const queue_type::value_type
& elem
) {
1291 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1294 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1295 if (aOldTree
.get
<std::string
>("action", "") == "invalidate")
1297 const unsigned nOldDialogId
= aOldTree
.get
<unsigned>("id", 0);
1298 std::string aOldRectStr
= aOldTree
.get
<std::string
>("rectangle", "");
1299 // not possible that we encounter an empty
1300 // rectangle here; we already handled this
1302 std::istringstream
aOldRectStream(aOldRectStr
);
1303 long nOldLeft
, nOldTop
, nOldWidth
, nOldHeight
;
1305 aOldRectStream
>> nOldLeft
>> nOldComma
>> nOldTop
>> nOldComma
>> nOldWidth
>> nOldComma
>> nOldHeight
;
1306 tools::Rectangle aOldRect
= tools::Rectangle(nOldLeft
, nOldTop
, nOldLeft
+ nOldWidth
, nOldTop
+ nOldHeight
);
1308 if (nLOKWindowId
== nOldDialogId
)
1310 // new one engulfs the old one?
1311 if (aNewRect
.IsInside(aOldRect
))
1313 SAL_INFO("lok.dialog", "New " << aNewRect
.toString() << " engulfs old " << aOldRect
.toString() << ".");
1316 // old one engulfs the new one?
1317 else if (aOldRect
.IsInside(aNewRect
))
1319 SAL_INFO("lok.dialog", "Old " << aOldRect
.toString() << " engulfs new " << aNewRect
.toString() << ".");
1320 // we have a rectangle in the queue
1321 // already that makes the current
1323 currentIsRedundant
= true;
1328 SAL_INFO("lok.dialog", "Merging " << aNewRect
.toString() << " & " << aOldRect
.toString());
1329 aNewRect
.Union(aOldRect
);
1330 SAL_INFO("lok.dialog", "Merged: " << aNewRect
.toString());
1340 if (currentIsRedundant
)
1342 SAL_INFO("lok.dialog", "Current payload is engulfed by one already in the queue. Skipping redundant payload: " << aNewRect
.toString());
1346 aTree
.put("rectangle", aNewRect
.toString().getStr());
1347 aCallbackData
.setJson(aTree
);
1348 assert(aCallbackData
.validate() && "Validation after setJson failed!");
1356 // Validate that the cached data and the payload string are identical.
1357 assert(aCallbackData
.validate() && "Cached callback payload object and string mismatch!");
1358 m_queue
.emplace_back(aCallbackData
);
1359 SAL_INFO("lok", "Queued #" << (m_queue
.size() - 1) <<
1360 " [" << type
<< "]: [" << payload
<< "] to have " << m_queue
.size() << " entries.");
1369 void CallbackFlushHandler::Invoke()
1371 if (m_pCallback
&& !m_bEventLatch
)
1373 std::unique_lock
<std::mutex
> lock(m_mutex
);
1375 SAL_INFO("lok", "Flushing " << m_queue
.size() << " elements.");
1376 for (auto& pair
: m_queue
)
1378 const int type
= pair
.Type
;
1379 const auto& payload
= pair
.PayloadString
;
1380 const int viewId
= lcl_isViewCallbackType(type
) ? lcl_getViewId(payload
) : -1;
1384 const auto stateIt
= m_states
.find(type
);
1385 if (stateIt
!= m_states
.end())
1387 // If the state didn't change, it's safe to ignore.
1388 if (stateIt
->second
== payload
)
1390 SAL_INFO("lok", "Skipping duplicate [" << type
<< "]: [" << payload
<< "].");
1394 stateIt
->second
= payload
;
1399 const auto statesIt
= m_viewStates
.find(viewId
);
1400 if (statesIt
!= m_viewStates
.end())
1402 auto& states
= statesIt
->second
;
1403 const auto stateIt
= states
.find(type
);
1404 if (stateIt
!= states
.end())
1406 // If the state didn't change, it's safe to ignore.
1407 if (stateIt
->second
== payload
)
1409 SAL_INFO("lok", "Skipping view duplicate [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
1413 SAL_INFO("lok", "Replacing an element in view states [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
1414 stateIt
->second
= payload
;
1418 SAL_INFO("lok", "Inserted a new element in view states: [" << type
<< ',' << viewId
<< "]: [" << payload
<< "]");
1419 states
.emplace(type
, payload
);
1425 m_pCallback(type
, payload
.c_str(), m_pData
);
1432 void CallbackFlushHandler::removeAll(const std::function
<bool (const CallbackFlushHandler::queue_type::value_type
&)>& rTestFunc
)
1434 auto newEnd
= std::remove_if(m_queue
.begin(), m_queue
.end(), rTestFunc
);
1435 m_queue
.erase(newEnd
, m_queue
.end());
1438 void CallbackFlushHandler::addViewStates(int viewId
)
1440 const auto& result
= m_viewStates
.emplace(viewId
, decltype(m_viewStates
)::mapped_type());
1441 if (!result
.second
&& result
.first
!= m_viewStates
.end())
1443 result
.first
->second
.clear();
1447 void CallbackFlushHandler::removeViewStates(int viewId
)
1449 m_viewStates
.erase(viewId
);
1453 static void doc_destroy(LibreOfficeKitDocument
*pThis
)
1455 SolarMutexGuard aGuard
;
1457 LibLODocument_Impl
*pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1461 static void lo_destroy (LibreOfficeKit
* pThis
);
1462 static int lo_initialize (LibreOfficeKit
* pThis
, const char* pInstallPath
, const char* pUserProfilePath
);
1463 static LibreOfficeKitDocument
* lo_documentLoad (LibreOfficeKit
* pThis
, const char* pURL
);
1464 static char * lo_getError (LibreOfficeKit
* pThis
);
1465 static void lo_freeError (char* pFree
);
1466 static LibreOfficeKitDocument
* lo_documentLoadWithOptions (LibreOfficeKit
* pThis
,
1468 const char* pOptions
);
1469 static void lo_registerCallback (LibreOfficeKit
* pThis
,
1470 LibreOfficeKitCallback pCallback
,
1472 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
);
1473 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long features
);
1474 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
1476 const char* pPassword
);
1477 static char* lo_getVersionInfo(LibreOfficeKit
* pThis
);
1478 static int lo_runMacro (LibreOfficeKit
* pThis
, const char* pURL
);
1480 static bool lo_signDocument(LibreOfficeKit
* pThis
,
1482 const unsigned char* pCertificateBinary
,
1483 const int nCertificateBinarySize
,
1484 const unsigned char* pPrivateKeyBinary
,
1485 const int nPrivateKeyBinarySize
);
1487 LibLibreOffice_Impl::LibLibreOffice_Impl()
1488 : m_pOfficeClass( gOfficeClass
.lock() )
1490 , mpCallback(nullptr)
1491 , mpCallbackData(nullptr)
1492 , mOptionalFeatures(0)
1494 if(!m_pOfficeClass
) {
1495 m_pOfficeClass
.reset(new LibreOfficeKitClass
);
1496 m_pOfficeClass
->nSize
= sizeof(LibreOfficeKitClass
);
1498 m_pOfficeClass
->destroy
= lo_destroy
;
1499 m_pOfficeClass
->documentLoad
= lo_documentLoad
;
1500 m_pOfficeClass
->getError
= lo_getError
;
1501 m_pOfficeClass
->freeError
= lo_freeError
;
1502 m_pOfficeClass
->documentLoadWithOptions
= lo_documentLoadWithOptions
;
1503 m_pOfficeClass
->registerCallback
= lo_registerCallback
;
1504 m_pOfficeClass
->getFilterTypes
= lo_getFilterTypes
;
1505 m_pOfficeClass
->setOptionalFeatures
= lo_setOptionalFeatures
;
1506 m_pOfficeClass
->setDocumentPassword
= lo_setDocumentPassword
;
1507 m_pOfficeClass
->getVersionInfo
= lo_getVersionInfo
;
1508 m_pOfficeClass
->runMacro
= lo_runMacro
;
1509 m_pOfficeClass
->signDocument
= lo_signDocument
;
1511 gOfficeClass
= m_pOfficeClass
;
1514 pClass
= m_pOfficeClass
.get();
1517 LibLibreOffice_Impl::~LibLibreOffice_Impl()
1524 ITiledRenderable
* getTiledRenderable(LibreOfficeKitDocument
* pThis
)
1526 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1527 return dynamic_cast<ITiledRenderable
*>(pDocument
->mxComponent
.get());
1530 } // anonymous namespace
1532 // Wonder global state ...
1533 static uno::Reference
<css::uno::XComponentContext
> xContext
;
1534 static uno::Reference
<css::lang::XMultiServiceFactory
> xSFactory
;
1535 static uno::Reference
<css::lang::XMultiComponentFactory
> xFactory
;
1537 static LibreOfficeKitDocument
* lo_documentLoad(LibreOfficeKit
* pThis
, const char* pURL
)
1539 return lo_documentLoadWithOptions(pThis
, pURL
, nullptr);
1542 static LibreOfficeKitDocument
* lo_documentLoadWithOptions(LibreOfficeKit
* pThis
, const char* pURL
, const char* pOptions
)
1544 SolarMutexGuard aGuard
;
1546 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
1547 pLib
->maLastExceptionMsg
.clear();
1549 OUString
aURL(getAbsoluteURL(pURL
));
1552 pLib
->maLastExceptionMsg
= "Filename to load was not provided.";
1553 SAL_INFO("lok", "URL for load is empty");
1557 pLib
->maLastExceptionMsg
.clear();
1561 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
1562 SAL_INFO("lok", "ComponentContext is not available");
1566 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
1568 if (!xComponentLoader
.is())
1570 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
1571 SAL_INFO("lok", "ComponentLoader is not available");
1577 // 'Language=...' is an option that LOK consumes by itself, and does
1578 // not pass it as a parameter to the filter
1579 OUString aOptions
= getUString(pOptions
);
1580 OUString aLanguage
= extractParameter(aOptions
, "Language");
1582 if (!aLanguage
.isEmpty())
1584 // use with care - it sets it for the entire core, not just the
1586 SvtSysLocaleOptions aSysLocaleOptions
;
1587 aSysLocaleOptions
.SetLocaleConfigString(aLanguage
);
1588 aSysLocaleOptions
.SetUILocaleConfigString(aLanguage
);
1591 uno::Sequence
<css::beans::PropertyValue
> aFilterOptions(2);
1592 aFilterOptions
[0] = css::beans::PropertyValue( "FilterOptions",
1594 uno::makeAny(aOptions
),
1595 beans::PropertyState_DIRECT_VALUE
);
1597 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
1598 new LOKInteractionHandler("load", pLib
));
1599 auto const pair(pLib
->mInteractionMap
.insert(std::make_pair(aURL
.toUtf8(), pInteraction
)));
1600 comphelper::ScopeGuard
const g([&] () {
1603 pLib
->mInteractionMap
.erase(aURL
.toUtf8());
1606 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
1607 aFilterOptions
[1].Name
= "InteractionHandler";
1608 aFilterOptions
[1].Value
<<= xInteraction
;
1611 sal_Int16 nMacroExecMode = document::MacroExecMode::USE_CONFIG;
1612 aFilterOptions[2].Name = "MacroExecutionMode";
1613 aFilterOptions[2].Value <<= nMacroExecMode;
1615 sal_Int16 nUpdateDoc = document::UpdateDocMode::ACCORDING_TO_CONFIG;
1616 aFilterOptions[3].Name = "UpdateDocMode";
1617 aFilterOptions[3].Value <<= nUpdateDoc;
1620 uno::Reference
<lang::XComponent
> xComponent
;
1621 xComponent
= xComponentLoader
->loadComponentFromURL(
1625 assert(!xComponent
.is() || pair
.second
); // concurrent loading of same URL ought to fail
1627 if (!xComponent
.is())
1629 pLib
->maLastExceptionMsg
= "loadComponentFromURL returned an empty reference";
1630 SAL_INFO("lok", "Document can't be loaded - " << pLib
->maLastExceptionMsg
);
1634 LibLODocument_Impl
* pDocument
= new LibLODocument_Impl(xComponent
);
1635 if (pLib
->mpCallback
)
1637 int nState
= doc_getSignatureState(pDocument
);
1638 pLib
->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS
, OString::number(nState
).getStr(), pLib
->mpCallbackData
);
1642 catch (const uno::Exception
& exception
)
1644 pLib
->maLastExceptionMsg
= exception
.Message
;
1645 SAL_INFO("lok", "Document can't be loaded: " << exception
);
1651 static int lo_runMacro(LibreOfficeKit
* pThis
, const char *pURL
)
1653 SolarMutexGuard aGuard
;
1655 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
1656 pLib
->maLastExceptionMsg
.clear();
1658 OUString
sURL( pURL
, strlen(pURL
), RTL_TEXTENCODING_UTF8
);
1661 pLib
->maLastExceptionMsg
= "Macro to run was not provided.";
1662 SAL_INFO("lok", "Macro URL is empty");
1666 if (!sURL
.startsWith("macro://"))
1668 pLib
->maLastExceptionMsg
= "This doesn't look like macro URL";
1669 SAL_INFO("lok", "Macro URL is invalid");
1673 pLib
->maLastExceptionMsg
.clear();
1677 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
1678 SAL_INFO("lok", "ComponentContext is not available");
1683 aURL
.Complete
= sURL
;
1685 uno::Reference
< util::XURLTransformer
> xParser( util::URLTransformer::create( xContext
) );
1688 xParser
->parseStrict( aURL
);
1690 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
1692 if (!xComponentLoader
.is())
1694 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
1695 SAL_INFO("lok", "ComponentLoader is not available");
1699 xFactory
= xContext
->getServiceManager();
1703 uno::Reference
<frame::XDispatchProvider
> xDP
;
1704 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
1705 xDP
.set( xSFactory
->createInstance("com.sun.star.comp.sfx2.SfxMacroLoader"), uno::UNO_QUERY
);
1706 uno::Reference
<frame::XDispatch
> xD
= xDP
->queryDispatch( aURL
, OUString(), 0);
1710 pLib
->maLastExceptionMsg
= "Macro loader is not available";
1711 SAL_INFO("lok", "Macro loader is not available");
1715 uno::Reference
< frame::XSynchronousDispatch
> xSyncDisp( xD
, uno::UNO_QUERY_THROW
);
1716 uno::Sequence
<css::beans::PropertyValue
> aEmpty
;
1717 css::beans::PropertyValue aErr
;
1720 aRet
= xSyncDisp
->dispatchWithReturnValue( aURL
, aEmpty
);
1723 if (aErr
.Name
== "ErrorCode")
1725 sal_uInt32 nErrCode
= 0; // ERRCODE_NONE
1726 aErr
.Value
>>= nErrCode
;
1728 pLib
->maLastExceptionMsg
= "An error occurred running macro (error code: " + OUString::number( nErrCode
) + ")";
1729 SAL_INFO("lok", "Macro execution terminated with error code " << nErrCode
);
1740 static bool lo_signDocument(LibreOfficeKit
* /*pThis*/,
1742 const unsigned char* pCertificateBinary
,
1743 const int nCertificateBinarySize
,
1744 const unsigned char* pPrivateKeyBinary
,
1745 const int nPrivateKeyBinarySize
)
1747 OUString
aURL(getAbsoluteURL(pURL
));
1754 uno::Sequence
<sal_Int8
> aCertificateSequence
;
1756 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
1757 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
1758 if (!aCertificateBase64String
.empty())
1760 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
1761 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
1765 aCertificateSequence
.realloc(nCertificateBinarySize
);
1766 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
1769 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
1770 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeyBinarySize
);
1771 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
1772 if (!aPrivateKeyBase64String
.empty())
1774 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
1775 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
1779 aPrivateKeySequence
.realloc(nPrivateKeyBinarySize
);
1780 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeyBinarySize
, aPrivateKeySequence
.begin());
1783 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
1784 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
;
1785 xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
1786 if (!xSecurityContext
.is())
1789 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
;
1790 xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
1791 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
1793 if (!xCertificateCreator
.is())
1796 uno::Reference
<security::XCertificate
> xCertificate
;
1797 xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
1799 if (!xCertificate
.is())
1802 sfx2::DocumentSigner
aDocumentSigner(aURL
);
1803 if (!aDocumentSigner
.signDocument(xCertificate
))
1809 static void lo_registerCallback (LibreOfficeKit
* pThis
,
1810 LibreOfficeKitCallback pCallback
,
1813 SolarMutexGuard aGuard
;
1815 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
1816 pLib
->maLastExceptionMsg
.clear();
1818 pLib
->mpCallback
= pCallback
;
1819 pLib
->mpCallbackData
= pData
;
1822 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* sUrl
, const char* pFormat
, const char* pFilterOptions
)
1824 SolarMutexGuard aGuard
;
1826 gImpl
->maLastExceptionMsg
.clear();
1828 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1830 OUString sFormat
= getUString(pFormat
);
1831 OUString
aURL(getAbsoluteURL(sUrl
));
1834 gImpl
->maLastExceptionMsg
= "Filename to save to was not provided.";
1835 SAL_INFO("lok", "URL for save is empty");
1841 const ExtensionMap
* pMap
;
1843 switch (doc_getDocumentType(pThis
))
1845 case LOK_DOCTYPE_SPREADSHEET
:
1846 pMap
= aCalcExtensionMap
;
1848 case LOK_DOCTYPE_PRESENTATION
:
1849 pMap
= aImpressExtensionMap
;
1851 case LOK_DOCTYPE_DRAWING
:
1852 pMap
= aDrawExtensionMap
;
1854 case LOK_DOCTYPE_TEXT
:
1855 pMap
= aWriterExtensionMap
;
1857 case LOK_DOCTYPE_OTHER
:
1859 SAL_INFO("lok", "Can't save document - unsupported document type.");
1863 if (pFormat
== nullptr)
1865 // sniff from the extension
1866 sal_Int32 idx
= aURL
.lastIndexOf(".");
1869 sFormat
= aURL
.copy( idx
+ 1 );
1873 gImpl
->maLastExceptionMsg
= "input filename without a suffix";
1878 OUString aFilterName
;
1879 for (sal_Int32 i
= 0; pMap
[i
].extn
; ++i
)
1881 if (sFormat
.equalsIgnoreAsciiCaseAscii(pMap
[i
].extn
))
1883 aFilterName
= getUString(pMap
[i
].filterName
);
1887 if (aFilterName
.isEmpty())
1889 gImpl
->maLastExceptionMsg
= "no output filter found for provided suffix";
1893 OUString aFilterOptions
= getUString(pFilterOptions
);
1895 // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
1896 // gets a new name). When this is not provided, the meaning of
1897 // saveAs() is more like save-a-copy, which allows saving to any
1898 // random format like PDF or PNG.
1899 // It is not a real filter option, so we have to filter it out.
1900 uno::Sequence
<OUString
> aOptionSeq
= comphelper::string::convertCommaSeparated(aFilterOptions
);
1901 std::vector
<OUString
> aFilteredOptionVec
;
1902 bool bTakeOwnership
= false;
1903 MediaDescriptor aSaveMediaDescriptor
;
1904 for (const auto& rOption
: aOptionSeq
)
1906 if (rOption
== "TakeOwnership")
1907 bTakeOwnership
= true;
1908 else if (rOption
== "NoFileSync")
1909 aSaveMediaDescriptor
["NoFileSync"] <<= true;
1911 aFilteredOptionVec
.push_back(rOption
);
1914 aSaveMediaDescriptor
["Overwrite"] <<= true;
1915 aSaveMediaDescriptor
["FilterName"] <<= aFilterName
;
1917 auto aFilteredOptionSeq
= comphelper::containerToSequence
<OUString
>(aFilteredOptionVec
);
1918 aFilterOptions
= comphelper::string::convertCommaSeparated(aFilteredOptionSeq
);
1919 aSaveMediaDescriptor
[MediaDescriptor::PROP_FILTEROPTIONS()] <<= aFilterOptions
;
1921 // add interaction handler too
1924 // gImpl does not have to exist when running from a unit test
1925 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
1926 new LOKInteractionHandler("saveas", gImpl
, pDocument
));
1927 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
1929 aSaveMediaDescriptor
[MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteraction
;
1932 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
1935 xStorable
->storeAsURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
1937 xStorable
->storeToURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
1941 catch (const uno::Exception
& exception
)
1943 gImpl
->maLastExceptionMsg
= "exception: " + exception
.Message
;
1948 static void doc_iniUnoCommands ()
1950 SolarMutexGuard aGuard
;
1952 gImpl
->maLastExceptionMsg
.clear();
1954 OUString sUnoCommands
[] =
1956 OUString(".uno:AlignLeft"),
1957 OUString(".uno:AlignHorizontalCenter"),
1958 OUString(".uno:AlignRight"),
1959 OUString(".uno:BackColor"),
1960 OUString(".uno:BackgroundColor"),
1961 OUString(".uno:TableCellBackgroundColor"),
1962 OUString(".uno:Bold"),
1963 OUString(".uno:CenterPara"),
1964 OUString(".uno:CharBackColor"),
1965 OUString(".uno:CharBackgroundExt"),
1966 OUString(".uno:CharFontName"),
1967 OUString(".uno:Color"),
1968 OUString(".uno:ControlCodes"),
1969 OUString(".uno:DecrementIndent"),
1970 OUString(".uno:DefaultBullet"),
1971 OUString(".uno:DefaultNumbering"),
1972 OUString(".uno:FontColor"),
1973 OUString(".uno:FontHeight"),
1974 OUString(".uno:IncrementIndent"),
1975 OUString(".uno:Italic"),
1976 OUString(".uno:JustifyPara"),
1977 OUString(".uno:OutlineFont"),
1978 OUString(".uno:LeftPara"),
1979 OUString(".uno:LanguageStatus"),
1980 OUString(".uno:RightPara"),
1981 OUString(".uno:Shadowed"),
1982 OUString(".uno:SubScript"),
1983 OUString(".uno:SuperScript"),
1984 OUString(".uno:Strikeout"),
1985 OUString(".uno:StyleApply"),
1986 OUString(".uno:Underline"),
1987 OUString(".uno:ModifiedStatus"),
1988 OUString(".uno:Undo"),
1989 OUString(".uno:Redo"),
1990 OUString(".uno:InsertPage"),
1991 OUString(".uno:DeletePage"),
1992 OUString(".uno:DuplicatePage"),
1993 OUString(".uno:Cut"),
1994 OUString(".uno:Copy"),
1995 OUString(".uno:Paste"),
1996 OUString(".uno:SelectAll"),
1997 OUString(".uno:InsertAnnotation"),
1998 OUString(".uno:DeleteAnnotation"),
1999 OUString(".uno:ReplyComment"),
2000 OUString(".uno:InsertRowsBefore"),
2001 OUString(".uno:InsertRowsAfter"),
2002 OUString(".uno:InsertColumnsBefore"),
2003 OUString(".uno:InsertColumnsAfter"),
2004 OUString(".uno:DeleteRows"),
2005 OUString(".uno:DeleteColumns"),
2006 OUString(".uno:DeleteTable"),
2007 OUString(".uno:SelectTable"),
2008 OUString(".uno:EntireRow"),
2009 OUString(".uno:EntireColumn"),
2010 OUString(".uno:EntireCell"),
2011 OUString(".uno:AssignLayout"),
2012 OUString(".uno:StatusDocPos"),
2013 OUString(".uno:RowColSelCount"),
2014 OUString(".uno:StatusPageStyle"),
2015 OUString(".uno:InsertMode"),
2016 OUString(".uno:SpellOnline"),
2017 OUString(".uno:StatusSelectionMode"),
2018 OUString(".uno:StateTableCell"),
2019 OUString(".uno:StatusBarFunc"),
2020 OUString(".uno:StatePageNumber"),
2021 OUString(".uno:StateWordCount"),
2022 OUString(".uno:SelectionMode"),
2023 OUString(".uno:PageStatus"),
2024 OUString(".uno:LayoutStatus"),
2025 OUString(".uno:Context"),
2026 OUString(".uno:WrapText"),
2027 OUString(".uno:ToggleMergeCells"),
2028 OUString(".uno:NumberFormatCurrency"),
2029 OUString(".uno:NumberFormatPercent"),
2030 OUString(".uno:NumberFormatDate"),
2031 OUString(".uno:SortAscending"),
2032 OUString(".uno:SortDescending"),
2033 OUString(".uno:TrackChanges"),
2034 OUString(".uno:ShowTrackedChanges"),
2035 OUString(".uno:NextTrackedChange"),
2036 OUString(".uno:PreviousTrackedChange"),
2037 OUString(".uno:AcceptAllTrackedChanges"),
2038 OUString(".uno:RejectAllTrackedChanges"),
2039 OUString(".uno:TableDialog"),
2040 OUString(".uno:FormatCellDialog"),
2041 OUString(".uno:FontDialog"),
2042 OUString(".uno:ParagraphDialog"),
2043 OUString(".uno:OutlineBullet"),
2044 OUString(".uno:InsertIndexesEntry"),
2045 OUString(".uno:DocumentRepair"),
2046 OUString(".uno:TransformDialog"),
2047 OUString(".uno:InsertPageHeader"),
2048 OUString(".uno:InsertPageFooter"),
2049 OUString(".uno:OnlineAutoFormat"),
2050 OUString(".uno:InsertSymbol"),
2051 OUString(".uno:EditRegion")
2054 util::URL aCommandURL
;
2055 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2056 SfxViewFrame
* pViewFrame
= pViewShell
? pViewShell
->GetViewFrame(): nullptr;
2058 // check if Frame-Controller were created.
2059 if (!pViewShell
&& !pViewFrame
)
2061 SAL_WARN("lok", "iniUnoCommands: No Frame-Controller created.");
2066 xContext
= comphelper::getProcessComponentContext();
2069 SAL_WARN("lok", "iniUnoCommands: Component context is not available");
2073 SfxSlotPool
& rSlotPool
= SfxSlotPool::GetSlotPool(pViewFrame
);
2074 uno::Reference
<util::XURLTransformer
> xParser(util::URLTransformer::create(xContext
));
2076 for (const auto & sUnoCommand
: sUnoCommands
)
2078 const SfxSlot
* pSlot
= nullptr;
2080 aCommandURL
.Complete
= sUnoCommand
;
2081 xParser
->parseStrict(aCommandURL
);
2082 pSlot
= rSlotPool
.GetUnoSlot(aCommandURL
.Path
);
2084 // when null, this command is not supported by the given component
2085 // (like eg. Calc does not have ".uno:DefaultBullet" etc.)
2088 // Initialize slot to dispatch .uno: Command.
2089 pViewFrame
->GetBindings().GetDispatch(pSlot
, aCommandURL
, false);
2094 static int doc_getDocumentType (LibreOfficeKitDocument
* pThis
)
2096 SolarMutexGuard aGuard
;
2098 gImpl
->maLastExceptionMsg
.clear();
2100 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2104 uno::Reference
<lang::XServiceInfo
> xDocument(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2106 if (xDocument
->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
2108 return LOK_DOCTYPE_SPREADSHEET
;
2110 else if (xDocument
->supportsService("com.sun.star.presentation.PresentationDocument"))
2112 return LOK_DOCTYPE_PRESENTATION
;
2114 else if (xDocument
->supportsService("com.sun.star.drawing.DrawingDocument"))
2116 return LOK_DOCTYPE_DRAWING
;
2118 else if (xDocument
->supportsService("com.sun.star.text.TextDocument") || xDocument
->supportsService("com.sun.star.text.WebDocument"))
2120 return LOK_DOCTYPE_TEXT
;
2124 gImpl
->maLastExceptionMsg
= "unknown document type";
2127 catch (const uno::Exception
& exception
)
2129 gImpl
->maLastExceptionMsg
= "exception: " + exception
.Message
;
2131 return LOK_DOCTYPE_OTHER
;
2134 static int doc_getParts (LibreOfficeKitDocument
* pThis
)
2136 SolarMutexGuard aGuard
;
2138 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2141 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2145 return pDoc
->getParts();
2148 static int doc_getPart (LibreOfficeKitDocument
* pThis
)
2150 SolarMutexGuard aGuard
;
2152 gImpl
->maLastExceptionMsg
.clear();
2154 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2157 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2161 return pDoc
->getPart();
2164 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
)
2166 SolarMutexGuard aGuard
;
2168 gImpl
->maLastExceptionMsg
.clear();
2170 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2173 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2177 pDoc
->setPart( nPart
);
2180 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
)
2182 SolarMutexGuard aGuard
;
2183 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2186 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2190 OUString aPartInfo
= pDoc
->getPartInfo( nPart
);
2191 OString aString
= OUStringToOString(aPartInfo
, RTL_TEXTENCODING_UTF8
);
2193 char* pMemory
= static_cast<char*>(malloc(aString
.getLength() + 1));
2194 strcpy(pMemory
, aString
.getStr());
2198 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
)
2200 SolarMutexGuard aGuard
;
2202 gImpl
->maLastExceptionMsg
.clear();
2204 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2207 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2211 OUString sRectangles
= pDoc
->getPartPageRectangles();
2212 OString aString
= OUStringToOString(sRectangles
, RTL_TEXTENCODING_UTF8
);
2213 char* pMemory
= static_cast<char*>(malloc(aString
.getLength() + 1));
2214 strcpy(pMemory
, aString
.getStr());
2219 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
)
2221 SolarMutexGuard aGuard
;
2223 gImpl
->maLastExceptionMsg
.clear();
2225 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2228 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2232 OUString sName
= pDoc
->getPartName( nPart
);
2233 OString aString
= OUStringToOString(sName
, RTL_TEXTENCODING_UTF8
);
2234 char* pMemory
= static_cast<char*>(malloc(aString
.getLength() + 1));
2235 strcpy(pMemory
, aString
.getStr());
2240 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
)
2242 SolarMutexGuard aGuard
;
2244 gImpl
->maLastExceptionMsg
.clear();
2246 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2249 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2253 OUString sHash
= pDoc
->getPartHash(nPart
);
2254 OString aString
= OUStringToOString(sHash
, RTL_TEXTENCODING_UTF8
);
2255 char* pMemory
= static_cast<char*>(malloc(aString
.getLength() + 1));
2256 strcpy(pMemory
, aString
.getStr());
2261 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
,
2264 SolarMutexGuard aGuard
;
2266 gImpl
->maLastExceptionMsg
.clear();
2268 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2271 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2276 int nCurrentPart
= pDoc
->getPart();
2278 pDoc
->setPartMode(nPartMode
);
2280 // We need to make sure the internal state is updated, just changing the mode
2281 // might not update the relevant shells (i.e. impress will keep rendering the
2282 // previous mode unless we do this).
2283 // TODO: we might want to do this within the relevant components rather than
2284 // here, but that's also dependent on how we implement embedded object
2285 // rendering I guess?
2286 // TODO: we could be clever and e.g. set to 0 when we change to/from
2287 // embedded object mode, and not when changing between slide/notes/combined
2289 if ( nCurrentPart
< pDoc
->getParts() )
2291 pDoc
->setPart( nCurrentPart
);
2299 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
2300 unsigned char* pBuffer
,
2301 const int nCanvasWidth
, const int nCanvasHeight
,
2302 const int nTilePosX
, const int nTilePosY
,
2303 const int nTileWidth
, const int nTileHeight
)
2305 SolarMutexGuard aGuard
;
2307 gImpl
->maLastExceptionMsg
.clear();
2309 SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth
<< "x" << nTileHeight
<<
2310 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
2311 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2313 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2316 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2320 #if defined(UNX) && !defined(MACOSX) && !defined(ENABLE_HEADLESS)
2322 // Painting of zoomed or hi-dpi spreadsheets is special, we actually draw everything at 100%,
2323 // and only set cairo's (or CoreGraphic's, in the iOS case) scale factor accordingly, so that
2324 // everything is painted bigger or smaller. This is different to what Calc's internal scaling
2325 // would do - because that one is trying to fit the lines between cells to integer multiples of
2327 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
2328 double fDPIScaleX
= 1;
2329 if (doc_getDocumentType(pThis
) == LOK_DOCTYPE_SPREADSHEET
)
2331 fDPIScaleX
= (nCanvasWidth
* 3840.0) / (256.0 * nTileWidth
);
2332 assert(fabs(fDPIScaleX
- ((nCanvasHeight
* 3840.0) / (256.0 * nTileHeight
))) < 0.0001);
2333 comphelper::LibreOfficeKit::setDPIScale(fDPIScaleX
);
2337 CGContextRef cgc
= CGBitmapContextCreate(pBuffer
, nCanvasWidth
, nCanvasHeight
, 8, nCanvasWidth
*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst
| kCGImageByteOrder32Little
);
2339 CGContextTranslateCTM(cgc
, 0, nCanvasHeight
);
2340 CGContextScaleCTM(cgc
, fDPIScaleX
, -fDPIScaleX
);
2342 doc_paintTileToCGContext(pThis
, (void*) cgc
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2344 CGContextRelease(cgc
);
2347 ScopedVclPtrInstance
< VirtualDevice
> pDevice(nullptr, Size(1, 1), DeviceFormat::DEFAULT
) ;
2349 #if !defined(ANDROID)
2350 // Set background to transparent by default.
2351 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
2354 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
2355 Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(),
2358 pDoc
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
,
2359 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2361 static bool bDebug
= getenv("LOK_DEBUG_TILES") != nullptr;
2364 // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
2365 tools::Rectangle
aRect(0, 0, 5, 5);
2366 aRect
= pDevice
->PixelToLogic(aRect
);
2367 pDevice
->Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
2368 pDevice
->SetFillColor(COL_LIGHTRED
);
2369 pDevice
->SetLineColor();
2370 pDevice
->DrawRect(aRect
);
2382 // This function is separate only to be used by LibreOfficeLight. If that app can be retired, this
2383 // function's code can be inlined into the iOS part of doc_paintTile().
2385 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
2387 const int nCanvasWidth
, const int nCanvasHeight
,
2388 const int nTilePosX
, const int nTilePosY
,
2389 const int nTileWidth
, const int nTileHeight
)
2391 SolarMutexGuard aGuard
;
2393 gImpl
->maLastExceptionMsg
.clear();
2395 SAL_INFO( "lok.tiledrendering", "paintTileToCGContext: painting [" << nTileWidth
<< "x" << nTileHeight
<<
2396 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
2397 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2399 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2402 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2406 SystemGraphicsData aData
;
2407 aData
.rCGContext
= reinterpret_cast<CGContextRef
>(rCGContext
);
2408 // the Size argument is irrelevant, I hope
2409 ScopedVclPtrInstance
<VirtualDevice
> pDevice(&aData
, Size(1, 1), DeviceFormat::DEFAULT
);
2411 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
2413 pDevice
->SetOutputSizePixel(Size(nCanvasWidth
, nCanvasHeight
));
2415 pDoc
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
,
2416 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2422 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
2423 unsigned char* pBuffer
,
2425 const int nCanvasWidth
, const int nCanvasHeight
,
2426 const int nTilePosX
, const int nTilePosY
,
2427 const int nTileWidth
, const int nTileHeight
)
2429 SolarMutexGuard aGuard
;
2431 gImpl
->maLastExceptionMsg
.clear();
2433 SAL_INFO( "lok.tiledrendering", "paintPartTile: painting @ " << nPart
<< " ["
2434 << nTileWidth
<< "x" << nTileHeight
<< "]@("
2435 << nTilePosX
<< ", " << nTilePosY
<< ") to ["
2436 << nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2438 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2439 int nOrigViewId
= doc_getView(pThis
);
2441 if (nOrigViewId
< 0)
2443 // tile painting always needs a SfxViewShell::Current(), but actually
2444 // it does not really matter which one - all of them should paint the
2446 int viewCount
= doc_getViewsCount(pThis
);
2450 std::vector
<int> viewIds(viewCount
);
2451 doc_getViewIds(pThis
, viewIds
.data(), viewCount
);
2453 nOrigViewId
= viewIds
[0];
2454 doc_setView(pThis
, nOrigViewId
);
2457 // Disable callbacks while we are painting.
2458 if (nOrigViewId
>= 0 && pDocument
->mpCallbackFlushHandlers
[nOrigViewId
])
2459 pDocument
->mpCallbackFlushHandlers
[nOrigViewId
]->setPartTilePainting(true);
2463 // Text documents have a single coordinate system; don't change part.
2465 const bool isText
= (doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
);
2466 int nViewId
= nOrigViewId
;
2469 // Check if just switching to another view is enough, that has
2470 // less side-effects.
2471 if (nPart
!= doc_getPart(pThis
))
2473 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
2476 if (pViewShell
->getPart() == nPart
)
2478 nViewId
= static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
2479 doc_setView(pThis
, nViewId
);
2482 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
2486 nOrigPart
= doc_getPart(pThis
);
2487 if (nPart
!= nOrigPart
)
2489 doc_setPart(pThis
, nPart
);
2493 doc_paintTile(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2495 if (!isText
&& nPart
!= nOrigPart
)
2497 doc_setPart(pThis
, nOrigPart
);
2499 if (!isText
&& nViewId
!= nOrigViewId
)
2501 doc_setView(pThis
, nOrigViewId
);
2504 catch (const std::exception
&)
2506 // Nothing to do but restore the PartTilePainting flag.
2509 if (nOrigViewId
>= 0 && pDocument
->mpCallbackFlushHandlers
[nOrigViewId
])
2510 pDocument
->mpCallbackFlushHandlers
[nOrigViewId
]->setPartTilePainting(false);
2513 static int doc_getTileMode(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
2516 gImpl
->maLastExceptionMsg
.clear();
2517 return LOK_TILEMODE_BGRA
;
2520 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
2524 SolarMutexGuard aGuard
;
2526 gImpl
->maLastExceptionMsg
.clear();
2528 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2531 Size aDocumentSize
= pDoc
->getDocumentSize();
2532 *pWidth
= aDocumentSize
.Width();
2533 *pHeight
= aDocumentSize
.Height();
2537 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2541 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
2542 const char* pArguments
)
2544 SolarMutexGuard aGuard
;
2546 gImpl
->maLastExceptionMsg
.clear();
2548 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2551 doc_iniUnoCommands();
2552 pDoc
->initializeForTiledRendering(
2553 comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments
)));
2557 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
2558 LibreOfficeKitCallback pCallback
,
2561 SolarMutexGuard aGuard
;
2563 gImpl
->maLastExceptionMsg
.clear();
2565 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2567 int nView
= SfxLokHelper::getView();
2571 if (pCallback
!= nullptr)
2574 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
2576 if (pair
.first
== nId
)
2579 pair
.second
->addViewStates(nView
);
2585 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
2587 if (pair
.first
== nId
)
2590 pair
.second
->removeViewStates(nView
);
2594 pDocument
->mpCallbackFlushHandlers
[nView
].reset(new CallbackFlushHandler(pThis
, pCallback
, pData
));
2596 if (pCallback
!= nullptr)
2599 for (const auto& pair
: pDocument
->mpCallbackFlushHandlers
)
2601 if (pair
.first
== nId
)
2604 pDocument
->mpCallbackFlushHandlers
[nView
]->addViewStates(pair
.first
);
2608 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
2610 pViewShell
->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback
, pDocument
->mpCallbackFlushHandlers
[nView
].get());
2614 /// Returns the JSON representation of all the comments in the document
2615 static char* getPostIts(LibreOfficeKitDocument
* pThis
)
2618 gImpl
->maLastExceptionMsg
.clear();
2619 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2622 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2625 OUString aComments
= pDoc
->getPostIts();
2626 return strdup(aComments
.toUtf8().getStr());
2629 /// Returns the JSON representation of the positions of all the comments in the document
2630 static char* getPostItsPos(LibreOfficeKitDocument
* pThis
)
2633 gImpl
->maLastExceptionMsg
.clear();
2634 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2637 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2640 OUString aComments
= pDoc
->getPostItsPos();
2641 return strdup(aComments
.toUtf8().getStr());
2644 static char* getRulerState(LibreOfficeKitDocument
* pThis
)
2647 gImpl
->maLastExceptionMsg
.clear();
2648 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2651 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2654 OUString state
= pDoc
->getRulerState();
2655 return strdup(state
.toUtf8().getStr());
2658 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nCharCode
, int nKeyCode
)
2660 SolarMutexGuard aGuard
;
2662 gImpl
->maLastExceptionMsg
.clear();
2664 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2667 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2671 pDoc
->postKeyEvent(nType
, nCharCode
, nKeyCode
);
2674 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
, unsigned nWindowId
, int nType
, const char* pText
)
2676 SolarMutexGuard aGuard
;
2677 VclPtr
<vcl::Window
> pWindow
;
2680 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2683 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2686 pWindow
= pDoc
->getDocWindow();
2690 pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
2695 gImpl
->maLastExceptionMsg
= "No window found for window id: " + OUString::number(nWindowId
);
2701 case LOK_EXT_TEXTINPUT
:
2702 pWindow
->PostExtTextInputEvent(VclEventId::ExtTextInput
,
2703 OUString::fromUtf8(OString(pText
, strlen(pText
))));
2705 case LOK_EXT_TEXTINPUT_END
:
2706 pWindow
->PostExtTextInputEvent(VclEventId::EndExtTextInput
, "");
2709 assert(false && "Unhandled External Text input event!");
2713 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nCharCode
, int nKeyCode
)
2715 SolarMutexGuard aGuard
;
2717 gImpl
->maLastExceptionMsg
.clear();
2719 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
2722 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
2726 KeyEvent
aEvent(nCharCode
, nKeyCode
, 0);
2730 case LOK_KEYEVENT_KEYINPUT
:
2731 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
2733 case LOK_KEYEVENT_KEYUP
:
2734 Application::PostKeyEvent(VclEventId::WindowKeyUp
, pWindow
, &aEvent
);
2742 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
)
2744 SolarMutexGuard aGuard
;
2746 gImpl
->maLastExceptionMsg
.clear();
2750 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2752 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2754 SvMemoryStream aOutStream
;
2755 uno::Reference
<io::XOutputStream
> xOut
= new utl::OOutputStreamWrapper(aOutStream
);
2757 utl::MediaDescriptor aMediaDescriptor
;
2758 switch (doc_getDocumentType(pThis
))
2760 case LOK_DOCTYPE_PRESENTATION
:
2761 aMediaDescriptor
["FilterName"] <<= OUString("impress_svg_Export");
2763 case LOK_DOCTYPE_TEXT
:
2764 aMediaDescriptor
["FilterName"] <<= OUString("writer_svg_Export");
2766 case LOK_DOCTYPE_SPREADSHEET
:
2767 aMediaDescriptor
["FilterName"] <<= OUString("calc_svg_Export");
2770 SAL_WARN("lok", "Failed to render shape selection: Document type is not supported");
2772 aMediaDescriptor
["SelectionOnly"] <<= true;
2773 aMediaDescriptor
["OutputStream"] <<= xOut
;
2775 xStorable
->storeToURL("private:stream", aMediaDescriptor
.getAsConstPropertyValueList());
2779 const size_t nOutputSize
= aOutStream
.GetEndOfData();
2780 *pOutput
= static_cast<char*>(malloc(nOutputSize
));
2783 std::memcpy(*pOutput
, aOutStream
.GetData(), nOutputSize
);
2788 catch (const uno::Exception
& exception
)
2791 gImpl
->maLastExceptionMsg
= exception
.Message
;
2792 SAL_WARN("lok", "Failed to render shape selection: " << exception
);
2798 /** Class to react on finishing of a dispatched command.
2800 This will call a LOK_COMMAND_FINISHED callback when postUnoCommand was
2801 called with the parameter requesting the notification.
2803 @see LibreOfficeKitCallbackType::LOK_CALLBACK_UNO_COMMAND_RESULT.
2805 class DispatchResultListener
: public cppu::WeakImplHelper
<css::frame::XDispatchResultListener
>
2807 OString maCommand
; ///< Command for which this is the result.
2808 std::shared_ptr
<CallbackFlushHandler
> mpCallback
; ///< Callback to call.
2811 DispatchResultListener(const char* pCommand
, std::shared_ptr
<CallbackFlushHandler
> const & pCallback
)
2812 : maCommand(pCommand
)
2813 , mpCallback(pCallback
)
2818 virtual void SAL_CALL
dispatchFinished(const css::frame::DispatchResultEvent
& rEvent
) override
2820 boost::property_tree::ptree aTree
;
2821 aTree
.put("commandName", maCommand
.getStr());
2823 if (rEvent
.State
!= frame::DispatchResultState::DONTKNOW
)
2825 bool bSuccess
= (rEvent
.State
== frame::DispatchResultState::SUCCESS
);
2826 aTree
.put("success", bSuccess
);
2829 aTree
.add_child("result", unoAnyToPropertyTree(rEvent
.Result
));
2831 std::stringstream aStream
;
2832 boost::property_tree::write_json(aStream
, aTree
);
2833 OString aPayload
= aStream
.str().c_str();
2834 mpCallback
->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
2837 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
{}
2840 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
, const char* pCommand
, const char* pArguments
, bool bNotifyWhenFinished
)
2842 SolarMutexGuard aGuard
;
2844 gImpl
->maLastExceptionMsg
.clear();
2846 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
2847 OUString
aCommand(pCommand
, strlen(pCommand
), RTL_TEXTENCODING_UTF8
);
2848 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2850 std::vector
<beans::PropertyValue
> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments
));
2852 beans::PropertyValue aSynchronMode
;
2853 aSynchronMode
.Name
= "SynchronMode";
2854 aSynchronMode
.Value
<<= false;
2855 aPropertyValuesVector
.push_back(aSynchronMode
);
2857 int nView
= SfxLokHelper::getView();
2861 // handle potential interaction
2862 if (gImpl
&& aCommand
== ".uno:Save")
2864 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
2865 new LOKInteractionHandler("save", gImpl
, pDocument
));
2866 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
2868 beans::PropertyValue aValue
;
2869 aValue
.Name
= "InteractionHandler";
2870 aValue
.Value
<<= xInteraction
;
2871 aPropertyValuesVector
.push_back(aValue
);
2873 bool bDontSaveIfUnmodified
= false;
2874 aPropertyValuesVector
.erase(std::remove_if(aPropertyValuesVector
.begin(),
2875 aPropertyValuesVector
.end(),
2876 [&bDontSaveIfUnmodified
](const beans::PropertyValue
& aItem
){
2877 if (aItem
.Name
== "DontSaveIfUnmodified")
2879 bDontSaveIfUnmodified
= aItem
.Value
.get
<bool>();
2883 }), aPropertyValuesVector
.end());
2885 // skip saving and tell the result via UNO_COMMAND_RESULT
2886 if (bDontSaveIfUnmodified
&& !pDocSh
->IsModified())
2888 boost::property_tree::ptree aTree
;
2889 aTree
.put("commandName", pCommand
);
2890 aTree
.put("success", false);
2892 // Add the reason for not saving
2893 const uno::Any aResultValue
= uno::makeAny(OUString("unmodified"));
2894 aTree
.add_child("result", unoAnyToPropertyTree(aResultValue
));
2896 std::stringstream aStream
;
2897 boost::property_tree::write_json(aStream
, aTree
);
2898 OString aPayload
= aStream
.str().c_str();
2899 pDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
2904 bool bResult
= false;
2905 if (bNotifyWhenFinished
&& pDocument
->mpCallbackFlushHandlers
[nView
])
2907 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
),
2908 new DispatchResultListener(pCommand
, pDocument
->mpCallbackFlushHandlers
[nView
]));
2911 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
));
2915 gImpl
->maLastExceptionMsg
= "Failed to dispatch the .uno: command";
2919 static void doc_postMouseEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
2921 SolarMutexGuard aGuard
;
2923 gImpl
->maLastExceptionMsg
.clear();
2925 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2928 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2932 pDoc
->postMouseEvent(nType
, nX
, nY
, nCount
, nButtons
, nModifier
);
2935 static void doc_postWindowMouseEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
2937 SolarMutexGuard aGuard
;
2939 gImpl
->maLastExceptionMsg
.clear();
2941 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
2944 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
2949 MouseEvent
aEvent(aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
, nButtons
, nModifier
);
2951 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
2953 pDialog
->EnableInput();
2958 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN
:
2959 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown
, pWindow
, &aEvent
);
2961 case LOK_MOUSEEVENT_MOUSEBUTTONUP
:
2962 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp
, pWindow
, &aEvent
);
2964 case LOK_MOUSEEVENT_MOUSEMOVE
:
2965 Application::PostMouseEvent(VclEventId::WindowMouseMove
, pWindow
, &aEvent
);
2973 static void doc_setTextSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
2975 SolarMutexGuard aGuard
;
2977 gImpl
->maLastExceptionMsg
.clear();
2979 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2982 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2986 pDoc
->setTextSelection(nType
, nX
, nY
);
2989 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, char** pUsedMimeType
)
2991 SolarMutexGuard aGuard
;
2993 gImpl
->maLastExceptionMsg
.clear();
2995 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2998 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3002 OString aUsedMimeType
;
3003 OString aRet
= pDoc
->getTextSelection(pMimeType
, aUsedMimeType
);
3004 if (aUsedMimeType
.isEmpty())
3005 aRet
= pDoc
->getTextSelection("text/plain;charset=utf-8", aUsedMimeType
);
3007 char* pMemory
= static_cast<char*>(malloc(aRet
.getLength() + 1));
3008 strcpy(pMemory
, aRet
.getStr());
3012 *pUsedMimeType
= static_cast<char*>(malloc(aUsedMimeType
.getLength() + 1));
3013 strcpy(*pUsedMimeType
, aUsedMimeType
.getStr());
3019 static bool doc_paste(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, const char* pData
, size_t nSize
)
3021 SolarMutexGuard aGuard
;
3023 gImpl
->maLastExceptionMsg
.clear();
3025 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3028 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3032 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(pMimeType
, pData
, nSize
));
3033 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(new LOKClipboard
);
3034 xClipboard
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
3035 pDoc
->setClipboard(xClipboard
);
3036 if (!pDoc
->isMimeTypeSupported())
3039 gImpl
->maLastExceptionMsg
= "Document doesn't support this mime type";
3043 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
3045 {"AnchorType", uno::makeAny(static_cast<sal_uInt16
>(text::TextContentAnchorType_AS_CHARACTER
))},
3047 if (!comphelper::dispatchCommand(".uno:Paste", aPropertyValues
))
3049 gImpl
->maLastExceptionMsg
= "Failed to dispatch the .uno: command";
3056 static void doc_setGraphicSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
3058 SolarMutexGuard aGuard
;
3060 gImpl
->maLastExceptionMsg
.clear();
3062 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3065 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3069 pDoc
->setGraphicSelection(nType
, nX
, nY
);
3072 static void doc_resetSelection(LibreOfficeKitDocument
* pThis
)
3074 SolarMutexGuard aGuard
;
3076 gImpl
->maLastExceptionMsg
.clear();
3078 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3081 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3085 pDoc
->resetSelection();
3088 static char* getLanguages(const char* pCommand
)
3090 css::uno::Sequence
< css::lang::Locale
> aLocales
;
3094 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
3097 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell(xLangSrv
->getSpellChecker(), css::uno::UNO_QUERY
);
3098 css::uno::Reference
<css::linguistic2::XSupportedLocales
> xLocales(xSpell
, css::uno::UNO_QUERY
);
3101 aLocales
= xLocales
->getLocales();
3105 boost::property_tree::ptree aTree
;
3106 aTree
.put("commandName", pCommand
);
3107 boost::property_tree::ptree aValues
;
3108 boost::property_tree::ptree aChild
;
3110 for ( sal_Int32 itLocale
= 0; itLocale
< aLocales
.getLength(); itLocale
++ )
3112 sLanguage
= SvtLanguageTable::GetLanguageString(LanguageTag::convertToLanguageType(aLocales
[itLocale
]));
3113 if (sLanguage
.startsWith("{") && sLanguage
.endsWith("}"))
3116 aChild
.put("", sLanguage
.toUtf8());
3117 aValues
.push_back(std::make_pair("", aChild
));
3119 aTree
.add_child("commandValues", aValues
);
3120 std::stringstream aStream
;
3121 boost::property_tree::write_json(aStream
, aTree
);
3122 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
3123 strcpy(pJson
, aStream
.str().c_str());
3124 pJson
[aStream
.str().size()] = '\0';
3128 static char* getFonts (const char* pCommand
)
3130 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
3131 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
3132 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
3133 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
3135 boost::property_tree::ptree aTree
;
3136 aTree
.put("commandName", pCommand
);
3137 boost::property_tree::ptree aValues
;
3140 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
3141 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
3143 boost::property_tree::ptree aChildren
;
3144 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
3145 const sal_IntPtr
* pAry
= pList
->GetSizeAry(rFontMetric
);
3146 sal_uInt16 nSizeCount
= 0;
3147 while (pAry
[nSizeCount
])
3149 boost::property_tree::ptree aChild
;
3150 aChild
.put("", static_cast<float>(pAry
[nSizeCount
]) / 10);
3151 aChildren
.push_back(std::make_pair("", aChild
));
3154 aValues
.add_child(rFontMetric
.GetFamilyName().toUtf8().getStr(), aChildren
);
3157 aTree
.add_child("commandValues", aValues
);
3158 std::stringstream aStream
;
3159 boost::property_tree::write_json(aStream
, aTree
);
3160 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
3161 strcpy(pJson
, aStream
.str().c_str());
3162 pJson
[aStream
.str().size()] = '\0';
3166 static char* getFontSubset (const OString
& aFontName
)
3168 OUString
aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName
, RTL_TEXTENCODING_UTF8
), rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
));
3169 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
3170 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
3171 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
3172 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
3174 boost::property_tree::ptree aTree
;
3175 aTree
.put("commandName", ".uno:FontSubset");
3176 boost::property_tree::ptree aValues
;
3178 if ( pList
&& !aFoundFont
.isEmpty() )
3180 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
3181 sal_uInt16 nItFont
= 0;
3182 for (; nItFont
< nFontCount
; ++nItFont
)
3184 if (aFoundFont
== pList
->GetFontName(nItFont
).GetFamilyName())
3190 if ( nItFont
< nFontCount
)
3192 FontCharMapRef
xFontCharMap (new FontCharMap());
3193 auto aDevice(VclPtr
<VirtualDevice
>::Create(nullptr, Size(1, 1), DeviceFormat::DEFAULT
));
3194 const vcl::Font
& aFont(pList
->GetFontName(nItFont
));
3196 aDevice
->SetFont(aFont
);
3197 aDevice
->GetFontCharMap(xFontCharMap
);
3198 SubsetMap
aSubMap(xFontCharMap
);
3200 for (auto const& subset
: aSubMap
.GetSubsetMap())
3202 boost::property_tree::ptree aChild
;
3203 aChild
.put("", static_cast<int>(ublock_getCode(subset
.GetRangeMin())));
3204 aValues
.push_back(std::make_pair("", aChild
));
3209 aTree
.add_child("commandValues", aValues
);
3210 std::stringstream aStream
;
3211 boost::property_tree::write_json(aStream
, aTree
);
3212 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
3213 strcpy(pJson
, aStream
.str().c_str());
3214 pJson
[aStream
.str().size()] = '\0';
3218 static char* getStyles(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
3220 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3222 boost::property_tree::ptree aTree
;
3223 aTree
.put("commandName", pCommand
);
3224 uno::Reference
<css::style::XStyleFamiliesSupplier
> xStyleFamiliesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
3225 uno::Reference
<container::XNameAccess
> xStyleFamilies(xStyleFamiliesSupplier
->getStyleFamilies(), uno::UNO_QUERY
);
3226 uno::Sequence
<OUString
> aStyleFamilies
= xStyleFamilies
->getElementNames();
3228 static const std::vector
<OUString
> aWriterStyles
=
3239 // We need to keep a list of the default style names
3240 // in order to filter these out later when processing
3241 // the full list of styles.
3242 std::set
<OUString
> aDefaultStyleNames
;
3244 boost::property_tree::ptree aValues
;
3245 for (sal_Int32 nStyleFam
= 0; nStyleFam
< aStyleFamilies
.getLength(); ++nStyleFam
)
3247 boost::property_tree::ptree aChildren
;
3248 OUString sStyleFam
= aStyleFamilies
[nStyleFam
];
3249 uno::Reference
<container::XNameAccess
> xStyleFamily(xStyleFamilies
->getByName(sStyleFam
), uno::UNO_QUERY
);
3251 // Writer provides a huge number of styles, we have a list of 7 "default" styles which
3252 // should be shown in the normal dropdown, which we should add to the start of the list
3253 // to simplify their selection.
3254 if (sStyleFam
== "ParagraphStyles"
3255 && doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
)
3257 for (const OUString
& rStyle
: aWriterStyles
)
3259 aDefaultStyleNames
.insert( rStyle
);
3261 boost::property_tree::ptree aChild
;
3262 aChild
.put("", rStyle
.toUtf8());
3263 aChildren
.push_back(std::make_pair("", aChild
));
3267 uno::Sequence
<OUString
> aStyles
= xStyleFamily
->getElementNames();
3268 for (const OUString
& rStyle
: aStyles
)
3270 // Filter out the default styles - they are already at the top
3272 if (aDefaultStyleNames
.find(rStyle
) == aDefaultStyleNames
.end() ||
3273 (sStyleFam
!= "ParagraphStyles" || doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
) )
3275 boost::property_tree::ptree aChild
;
3276 aChild
.put("", rStyle
.toUtf8());
3277 aChildren
.push_back(std::make_pair("", aChild
));
3280 aValues
.add_child(sStyleFam
.toUtf8().getStr(), aChildren
);
3283 // Header & Footer Styles
3286 boost::property_tree::ptree aChild
;
3287 boost::property_tree::ptree aChildren
;
3288 const OUString
sPageStyles("PageStyles");
3289 uno::Reference
<beans::XPropertySet
> xProperty
;
3290 uno::Reference
<container::XNameContainer
> xContainer
;
3292 if (xStyleFamilies
->hasByName(sPageStyles
) && (xStyleFamilies
->getByName(sPageStyles
) >>= xContainer
))
3294 uno::Sequence
<OUString
> aSeqNames
= xContainer
->getElementNames();
3295 for (sal_Int32 itName
= 0; itName
< aSeqNames
.getLength(); itName
++)
3298 sName
= aSeqNames
[itName
];
3299 xProperty
.set(xContainer
->getByName(sName
), uno::UNO_QUERY
);
3300 if (xProperty
.is() && (xProperty
->getPropertyValue("IsPhysical") >>= bIsPhysical
) && bIsPhysical
)
3302 xProperty
->getPropertyValue("DisplayName") >>= sName
;
3303 aChild
.put("", sName
.toUtf8());
3304 aChildren
.push_back(std::make_pair("", aChild
));
3307 aValues
.add_child("HeaderFooter", aChildren
);
3312 boost::property_tree::ptree aCommandList
;
3315 boost::property_tree::ptree aChild
;
3317 OUString sClearFormat
= SvxResId(RID_SVXSTR_CLEARFORM
);
3319 boost::property_tree::ptree aName
;
3320 aName
.put("", sClearFormat
.toUtf8());
3321 aChild
.push_back(std::make_pair("text", aName
));
3323 boost::property_tree::ptree aCommand
;
3324 aCommand
.put("", ".uno:ResetAttributes");
3325 aChild
.push_back(std::make_pair("id", aCommand
));
3327 aCommandList
.push_back(std::make_pair("", aChild
));
3330 aValues
.add_child("Commands", aCommandList
);
3333 aTree
.add_child("commandValues", aValues
);
3334 std::stringstream aStream
;
3335 boost::property_tree::write_json(aStream
, aTree
);
3336 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
3337 strcpy(pJson
, aStream
.str().c_str());
3338 pJson
[aStream
.str().size()] = '\0';
3342 enum class UndoOrRedo
3348 /// Returns the JSON representation of either an undo or a redo stack.
3349 static char* getUndoOrRedo(LibreOfficeKitDocument
* pThis
, UndoOrRedo eCommand
)
3351 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3353 auto pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
3357 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
3361 SfxUndoManager
* pUndoManager
= pObjectShell
->GetUndoManager();
3366 if (eCommand
== UndoOrRedo::UNDO
)
3367 aString
= pUndoManager
->GetUndoActionsInfo();
3369 aString
= pUndoManager
->GetRedoActionsInfo();
3370 char* pJson
= strdup(aString
.toUtf8().getStr());
3374 /// Returns the JSON representation of the redline stack.
3375 static char* getTrackedChanges(LibreOfficeKitDocument
* pThis
)
3377 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3379 uno::Reference
<document::XRedlinesSupplier
> xRedlinesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
3380 std::stringstream aStream
;
3381 // We want positions of the track changes also which is not possible from
3382 // UNO. Enable positioning information for text documents only for now, so
3383 // construct the tracked changes JSON from inside the sw/, not here using UNO
3384 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
&& xRedlinesSupplier
.is())
3386 uno::Reference
<container::XEnumeration
> xRedlines
= xRedlinesSupplier
->getRedlines()->createEnumeration();
3387 boost::property_tree::ptree aRedlines
;
3388 for (size_t nIndex
= 0; xRedlines
->hasMoreElements(); ++nIndex
)
3390 uno::Reference
<beans::XPropertySet
> xRedline(xRedlines
->nextElement(), uno::UNO_QUERY
);
3391 boost::property_tree::ptree aRedline
;
3392 aRedline
.put("index", nIndex
);
3395 xRedline
->getPropertyValue("RedlineAuthor") >>= sAuthor
;
3396 aRedline
.put("author", sAuthor
.toUtf8().getStr());
3399 xRedline
->getPropertyValue("RedlineType") >>= sType
;
3400 aRedline
.put("type", sType
.toUtf8().getStr());
3403 xRedline
->getPropertyValue("RedlineComment") >>= sComment
;
3404 aRedline
.put("comment", sComment
.toUtf8().getStr());
3406 OUString sDescription
;
3407 xRedline
->getPropertyValue("RedlineDescription") >>= sDescription
;
3408 aRedline
.put("description", sDescription
.toUtf8().getStr());
3410 util::DateTime aDateTime
;
3411 xRedline
->getPropertyValue("RedlineDateTime") >>= aDateTime
;
3412 OUString sDateTime
= utl::toISO8601(aDateTime
);
3413 aRedline
.put("dateTime", sDateTime
.toUtf8().getStr());
3415 aRedlines
.push_back(std::make_pair("", aRedline
));
3418 boost::property_tree::ptree aTree
;
3419 aTree
.add_child("redlines", aRedlines
);
3420 boost::property_tree::write_json(aStream
, aTree
);
3424 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3427 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3430 OUString aTrackedChanges
= pDoc
->getTrackedChanges();
3431 aStream
<< aTrackedChanges
.toUtf8();
3434 char* pJson
= strdup(aStream
.str().c_str());
3439 /// Returns the JSON representation of the redline author table.
3440 static char* getTrackedChangeAuthors(LibreOfficeKitDocument
* pThis
)
3442 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3445 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3448 OUString aAuthors
= pDoc
->getTrackedChangeAuthors();
3449 return strdup(aAuthors
.toUtf8().getStr());
3452 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
3454 SolarMutexGuard aGuard
;
3456 gImpl
->maLastExceptionMsg
.clear();
3458 OString
aCommand(pCommand
);
3459 static const OString
aViewRowColumnHeaders(".uno:ViewRowColumnHeaders");
3460 static const OString
aCellCursor(".uno:CellCursor");
3461 static const OString
aFontSubset(".uno:FontSubset&name=");
3463 if (!strcmp(pCommand
, ".uno:LanguageStatus"))
3465 return getLanguages(pCommand
);
3467 else if (!strcmp(pCommand
, ".uno:CharFontName"))
3469 return getFonts(pCommand
);
3471 else if (!strcmp(pCommand
, ".uno:StyleApply"))
3473 return getStyles(pThis
, pCommand
);
3475 else if (aCommand
== ".uno:Undo")
3477 return getUndoOrRedo(pThis
, UndoOrRedo::UNDO
);
3479 else if (aCommand
== ".uno:Redo")
3481 return getUndoOrRedo(pThis
, UndoOrRedo::REDO
);
3483 else if (aCommand
== ".uno:AcceptTrackedChanges")
3485 return getTrackedChanges(pThis
);
3487 else if (aCommand
== ".uno:TrackedChangeAuthors")
3489 return getTrackedChangeAuthors(pThis
);
3491 else if (aCommand
== ".uno:ViewAnnotations")
3493 return getPostIts(pThis
);
3495 else if (aCommand
== ".uno:ViewAnnotationsPosition")
3497 return getPostItsPos(pThis
);
3499 else if (aCommand
== ".uno:RulerState")
3501 return getRulerState(pThis
);
3503 else if (aCommand
.startsWith(aViewRowColumnHeaders
))
3505 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3508 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3512 tools::Rectangle aRectangle
;
3513 if (aCommand
.getLength() > aViewRowColumnHeaders
.getLength())
3515 // Command has parameters.
3520 OString aArguments
= aCommand
.copy(aViewRowColumnHeaders
.getLength() + 1);
3521 sal_Int32 nParamIndex
= 0;
3524 OString aParamToken
= aArguments
.getToken(0, '&', nParamIndex
);
3525 sal_Int32 nIndex
= 0;
3530 OString aToken
= aParamToken
.getToken(0, '=', nIndex
);
3531 if (!aKey
.getLength())
3536 while (nIndex
>= 0);
3538 nX
= aValue
.toInt32();
3539 else if (aKey
== "y")
3540 nY
= aValue
.toInt32();
3541 else if (aKey
== "width")
3542 nWidth
= aValue
.toInt32();
3543 else if (aKey
== "height")
3544 nHeight
= aValue
.toInt32();
3546 while (nParamIndex
>= 0);
3548 aRectangle
= tools::Rectangle(nX
, nY
, nX
+ nWidth
, nY
+ nHeight
);
3551 OUString aHeaders
= pDoc
->getRowColumnHeaders(aRectangle
);
3552 OString aString
= OUStringToOString(aHeaders
, RTL_TEXTENCODING_UTF8
);
3554 char* pMemory
= static_cast<char*>(malloc(aString
.getLength() + 1));
3555 strcpy(pMemory
, aString
.getStr());
3558 else if (aCommand
.startsWith(aCellCursor
))
3560 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3563 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3567 // Command has parameters.
3568 int nOutputWidth
= 0;
3569 int nOutputHeight
= 0;
3570 long nTileWidth
= 0;
3571 long nTileHeight
= 0;
3572 if (aCommand
.getLength() > aCellCursor
.getLength())
3574 OString aArguments
= aCommand
.copy(aCellCursor
.getLength() + 1);
3575 sal_Int32 nParamIndex
= 0;
3578 OString aParamToken
= aArguments
.getToken(0, '&', nParamIndex
);
3579 sal_Int32 nIndex
= 0;
3584 OString aToken
= aParamToken
.getToken(0, '=', nIndex
);
3585 if (!aKey
.getLength())
3590 while (nIndex
>= 0);
3591 if (aKey
== "outputWidth")
3592 nOutputWidth
= aValue
.toInt32();
3593 else if (aKey
== "outputHeight")
3594 nOutputHeight
= aValue
.toInt32();
3595 else if (aKey
== "tileWidth")
3596 nTileWidth
= aValue
.toInt64();
3597 else if (aKey
== "tileHeight")
3598 nTileHeight
= aValue
.toInt64();
3600 while (nParamIndex
>= 0);
3603 OString aString
= pDoc
->getCellCursor(nOutputWidth
, nOutputHeight
, nTileWidth
, nTileHeight
);
3605 char* pMemory
= static_cast<char*>(malloc(aString
.getLength() + 1));
3606 strcpy(pMemory
, aString
.getStr());
3609 else if (aCommand
.startsWith(aFontSubset
))
3611 return getFontSubset(OString(pCommand
+ aFontSubset
.getLength()));
3615 gImpl
->maLastExceptionMsg
= "Unknown command, no values returned";
3620 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
, int nTilePixelWidth
, int nTilePixelHeight
,
3621 int nTileTwipWidth
, int nTileTwipHeight
)
3623 SolarMutexGuard aGuard
;
3625 gImpl
->maLastExceptionMsg
.clear();
3627 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3630 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3634 pDoc
->setClientZoom(nTilePixelWidth
, nTilePixelHeight
, nTileTwipWidth
, nTileTwipHeight
);
3637 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
)
3639 SolarMutexGuard aGuard
;
3641 gImpl
->maLastExceptionMsg
.clear();
3643 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3646 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3650 tools::Rectangle
aRectangle(Point(nX
, nY
), Size(nWidth
, nHeight
));
3651 pDoc
->setClientVisibleArea(aRectangle
);
3654 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
)
3656 SolarMutexGuard aGuard
;
3658 gImpl
->maLastExceptionMsg
.clear();
3660 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3663 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3667 pDoc
->setOutlineState(bColumn
, nLevel
, nIndex
, bHidden
);
3670 static int doc_createView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
3672 SolarMutexGuard aGuard
;
3674 gImpl
->maLastExceptionMsg
.clear();
3676 return SfxLokHelper::createView();
3679 static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
)
3681 SolarMutexGuard aGuard
;
3683 gImpl
->maLastExceptionMsg
.clear();
3685 SfxLokHelper::destroyView(nId
);
3688 static void doc_setView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
)
3690 SolarMutexGuard aGuard
;
3692 gImpl
->maLastExceptionMsg
.clear();
3694 SfxLokHelper::setView(nId
);
3697 static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
3699 SolarMutexGuard aGuard
;
3701 gImpl
->maLastExceptionMsg
.clear();
3703 return SfxLokHelper::getView();
3706 static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
3708 SolarMutexGuard aGuard
;
3710 gImpl
->maLastExceptionMsg
.clear();
3712 return SfxLokHelper::getViewsCount();
3715 static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int* pArray
, size_t nSize
)
3717 SolarMutexGuard aGuard
;
3719 gImpl
->maLastExceptionMsg
.clear();
3721 return SfxLokHelper::getViewIds(pArray
, nSize
);
3724 static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
, const char* language
)
3726 SolarMutexGuard aGuard
;
3728 gImpl
->maLastExceptionMsg
.clear();
3730 SfxLokHelper::setViewLanguage(nId
, OStringToOUString(language
, RTL_TEXTENCODING_UTF8
));
3733 unsigned char* doc_renderFont(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/,
3734 const char* pFontName
,
3739 SolarMutexGuard aGuard
;
3741 gImpl
->maLastExceptionMsg
.clear();
3743 OString
aSearchedFontName(pFontName
);
3744 OUString
aText(OStringToOUString(pChar
, RTL_TEXTENCODING_UTF8
));
3745 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
3746 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
3747 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
3748 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
3750 const int nDefaultFontSize
= 25;
3754 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
3755 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
3757 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
3758 const OUString
& aFontName
= rFontMetric
.GetFamilyName();
3759 if (aSearchedFontName
!= aFontName
.toUtf8())
3762 if (aText
.isEmpty())
3763 aText
= rFontMetric
.GetFamilyName();
3766 VclPtr
<VirtualDevice
>::Create(
3767 nullptr, Size(1, 1), DeviceFormat::DEFAULT
));
3768 ::tools::Rectangle aRect
;
3769 vcl::Font
aFont(rFontMetric
);
3770 aFont
.SetFontSize(Size(0, nDefaultFontSize
));
3771 aDevice
->SetFont(aFont
);
3772 aDevice
->GetTextBoundRect(aRect
, aText
);
3773 if (aRect
.IsEmpty())
3776 int nFontWidth
= aRect
.BottomRight().X() + 1;
3777 int nFontHeight
= aRect
.BottomRight().Y() + 1;
3779 if (!(nFontWidth
> 0 && nFontHeight
> 0))
3782 if (*pFontWidth
> 0 && *pFontHeight
> 0)
3784 double fScaleX
= *pFontWidth
/ static_cast<double>(nFontWidth
);
3785 double fScaleY
= *pFontHeight
/ static_cast<double>(nFontHeight
);
3787 double fScale
= std::min(fScaleX
, fScaleY
);
3791 int nFontSize
= fScale
* nDefaultFontSize
;
3792 aFont
.SetFontSize(Size(0, nFontSize
));
3793 aDevice
->SetFont(aFont
);
3796 aRect
= tools::Rectangle(0, 0, *pFontWidth
, *pFontHeight
);
3798 nFontWidth
= *pFontWidth
;
3799 nFontHeight
= *pFontHeight
;
3803 unsigned char* pBuffer
= static_cast<unsigned char*>(malloc(4 * nFontWidth
* nFontHeight
));
3807 memset(pBuffer
, 0, nFontWidth
* nFontHeight
* 4);
3808 aDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
3809 aDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
3810 Size(nFontWidth
, nFontHeight
), Fraction(1.0), Point(),
3813 if (*pFontWidth
> 0 && *pFontHeight
> 0)
3815 DrawTextFlags
const nStyle
=
3816 DrawTextFlags::Center
3817 | DrawTextFlags::VCenter
3818 | DrawTextFlags::MultiLine
3819 | DrawTextFlags::WordBreakHyphenation
;// | DrawTextFlags::WordBreak ;
3821 aDevice
->DrawText(aRect
, aText
, nStyle
);
3825 *pFontWidth
= nFontWidth
;
3826 *pFontHeight
= nFontHeight
;
3828 aDevice
->DrawText(Point(0,0), aText
);
3838 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
3839 unsigned char* pBuffer
,
3840 const int nX
, const int nY
,
3841 const int nWidth
, const int nHeight
)
3843 doc_paintWindowDPI(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, 1.0);
3846 static void doc_paintWindowDPI(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
,
3847 unsigned char* pBuffer
,
3848 const int nX
, const int nY
,
3849 const int nWidth
, const int nHeight
,
3850 const double fDPIScale
)
3852 SolarMutexGuard aGuard
;
3854 gImpl
->maLastExceptionMsg
.clear();
3856 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3859 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
3863 // Setup cairo (or CoreGraphics, in the iOS case) to draw with the changed DPI scale (and return
3864 // back to 1.0 when the painting finishes)
3865 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
3866 comphelper::LibreOfficeKit::setDPIScale(fDPIScale
);
3870 CGContextRef cgc
= CGBitmapContextCreate(pBuffer
, nWidth
, nHeight
, 8, nWidth
*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst
| kCGImageByteOrder32Little
);
3872 CGContextTranslateCTM(cgc
, 0, nHeight
);
3873 CGContextScaleCTM(cgc
, fDPIScale
, -fDPIScale
);
3875 SystemGraphicsData aData
;
3876 aData
.rCGContext
= cgc
;
3878 ScopedVclPtrInstance
<VirtualDevice
> pDevice(&aData
, Size(1, 1), DeviceFormat::DEFAULT
);
3879 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
3881 pDevice
->SetOutputSizePixel(Size(nWidth
, nHeight
));
3883 MapMode
aMapMode(pDevice
->GetMapMode());
3884 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
3885 pDevice
->SetMapMode(aMapMode
);
3887 comphelper::LibreOfficeKit::setDialogPainting(true);
3888 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0), Size());
3889 comphelper::LibreOfficeKit::setDialogPainting(false);
3891 CGContextRelease(cgc
);
3895 ScopedVclPtrInstance
<VirtualDevice
> pDevice(nullptr, Size(1, 1), DeviceFormat::DEFAULT
);
3896 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
3898 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(Size(nWidth
, nHeight
), Fraction(1.0), Point(), pBuffer
);
3900 MapMode
aMapMode(pDevice
->GetMapMode());
3901 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
3902 pDevice
->SetMapMode(aMapMode
);
3904 comphelper::LibreOfficeKit::setDialogPainting(true);
3905 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0), Size());
3906 comphelper::LibreOfficeKit::setDialogPainting(false);
3911 static void doc_postWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nAction
)
3913 SolarMutexGuard aGuard
;
3915 gImpl
->maLastExceptionMsg
.clear();
3917 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3920 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
3924 if (nAction
== LOK_WINDOW_CLOSE
)
3926 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
3928 else if (FloatingWindow
* pFloatWin
= dynamic_cast<FloatingWindow
*>(pWindow
.get()))
3929 pFloatWin
->EndPopupMode(FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
);
3933 // CERTIFICATE AND DOCUMENT SIGNING
3934 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
3935 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
,
3936 const unsigned char* pPrivateKeyBinary
, const int nPrivateKeySize
)
3941 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3943 if (!pDocument
->mxComponent
.is())
3946 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
3950 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
3955 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
3956 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
;
3957 xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
3958 if (!xSecurityContext
.is())
3961 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
;
3962 xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
3963 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
3965 if (!xCertificateCreator
.is())
3968 uno::Sequence
<sal_Int8
> aCertificateSequence
;
3970 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
3971 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
3972 if (!aCertificateBase64String
.empty())
3974 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
3975 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
3979 aCertificateSequence
.realloc(nCertificateBinarySize
);
3980 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
3983 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
3984 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeySize
);
3985 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
3986 if (!aPrivateKeyBase64String
.empty())
3988 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
3989 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
3993 aPrivateKeySequence
.realloc(nPrivateKeySize
);
3994 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeySize
, aPrivateKeySequence
.begin());
3997 uno::Reference
<security::XCertificate
> xCertificate
;
3998 xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
4000 if (!xCertificate
.is())
4003 SolarMutexGuard aGuard
;
4005 return pObjectShell
->SignDocumentContentUsingCertificate(xCertificate
);
4008 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
4009 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
)
4014 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4016 if (!pDocument
->mxComponent
.is())
4019 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
4023 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
4028 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
4029 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
;
4030 xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
4031 if (!xSecurityContext
.is())
4034 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
;
4035 xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
4036 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
4038 if (!xCertificateCreator
.is())
4041 uno::Sequence
<sal_Int8
> aCertificateSequence
;
4043 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
4044 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
4045 if (!aCertificateBase64String
.empty())
4047 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
4048 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
4052 aCertificateSequence
.realloc(nCertificateBinarySize
);
4053 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
4056 uno::Reference
<security::XCertificate
> xCertificate
;
4057 xCertificate
= xCertificateCreator
->addDERCertificateToTheDatabase(aCertificateSequence
, "TCu,Cu,Tu");
4059 if (!xCertificate
.is())
4062 SAL_INFO("lok", "Certificate Added = IssuerName: " << xCertificate
->getIssuerName() << " SubjectName: " << xCertificate
->getSubjectName());
4067 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
)
4069 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4071 if (!pDocument
->mxComponent
.is())
4072 return int(SignatureState::UNKNOWN
);
4074 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
4076 return int(SignatureState::UNKNOWN
);
4078 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
4080 return int(SignatureState::UNKNOWN
);
4082 SolarMutexGuard aGuard
;
4084 pObjectShell
->RecheckSignature(false);
4086 return int(pObjectShell
->GetDocumentSignatureState());
4089 static char* lo_getError (LibreOfficeKit
*pThis
)
4091 SolarMutexGuard aGuard
;
4093 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
4094 OString aString
= OUStringToOString(pLib
->maLastExceptionMsg
, RTL_TEXTENCODING_UTF8
);
4095 char* pMemory
= static_cast<char*>(malloc(aString
.getLength() + 1));
4096 strcpy(pMemory
, aString
.getStr());
4100 static void lo_freeError(char* pFree
)
4105 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
)
4107 SolarMutexGuard aGuard
;
4109 gImpl
->maLastExceptionMsg
.clear();
4111 LibLibreOffice_Impl
* pImpl
= static_cast<LibLibreOffice_Impl
*>(pThis
);
4113 if (!xSFactory
.is())
4114 xSFactory
= comphelper::getProcessServiceFactory();
4116 if (!xSFactory
.is())
4118 pImpl
->maLastExceptionMsg
= "Service factory is not available";
4122 uno::Reference
<container::XNameAccess
> xTypeDetection(xSFactory
->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY
);
4123 uno::Sequence
<OUString
> aTypes
= xTypeDetection
->getElementNames();
4124 boost::property_tree::ptree aTree
;
4125 for (const OUString
& rType
: aTypes
)
4127 uno::Sequence
<beans::PropertyValue
> aValues
;
4128 if (xTypeDetection
->getByName(rType
) >>= aValues
)
4130 auto it
= std::find_if(aValues
.begin(), aValues
.end(), [](const beans::PropertyValue
& rValue
) { return rValue
.Name
== "MediaType"; });
4132 if (it
!= aValues
.end() && (it
->Value
>>= aValue
) && !aValue
.isEmpty())
4134 boost::property_tree::ptree aChild
;
4135 aChild
.put("MediaType", aValue
.toUtf8());
4136 aTree
.add_child(rType
.toUtf8().getStr(), aChild
);
4140 std::stringstream aStream
;
4141 boost::property_tree::write_json(aStream
, aTree
);
4142 return strdup(aStream
.str().c_str());
4145 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long const features
)
4147 SolarMutexGuard aGuard
;
4149 gImpl
->maLastExceptionMsg
.clear();
4151 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
4152 pLib
->mOptionalFeatures
= features
;
4153 if (features
& LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK
)
4154 comphelper::LibreOfficeKit::setPartInInvalidation(true);
4155 if (features
& LOK_FEATURE_NO_TILED_ANNOTATIONS
)
4156 comphelper::LibreOfficeKit::setTiledAnnotations(false);
4157 if (features
& LOK_FEATURE_RANGE_HEADERS
)
4158 comphelper::LibreOfficeKit::setRangeHeaders(true);
4159 if (features
& LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK
)
4160 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
4163 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
4164 const char* pURL
, const char* pPassword
)
4166 SolarMutexGuard aGuard
;
4168 gImpl
->maLastExceptionMsg
.clear();
4172 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
4173 assert(pLib
->mInteractionMap
.find(OString(pURL
)) != pLib
->mInteractionMap
.end());
4174 pLib
->mInteractionMap
.find(OString(pURL
))->second
->SetPassword(pPassword
);
4177 static char* lo_getVersionInfo(SAL_UNUSED_PARAMETER LibreOfficeKit
* /*pThis*/)
4180 gImpl
->maLastExceptionMsg
.clear();
4181 const OUString
sVersionStrTemplate(
4183 "\"ProductName\": \"%PRODUCTNAME\", "
4184 "\"ProductVersion\": \"%PRODUCTVERSION\", "
4185 "\"ProductExtension\": \"%PRODUCTEXTENSION\", "
4186 "\"BuildId\": \"%BUILDID\" "
4189 const OString sVersionStr
= OUStringToOString(ReplaceStringHookProc(sVersionStrTemplate
), RTL_TEXTENCODING_UTF8
);
4191 char* pVersion
= static_cast<char*>(malloc(sVersionStr
.getLength() + 1));
4192 strcpy(pVersion
, sVersionStr
.getStr());
4196 static void force_c_locale()
4198 // force locale (and resource files loaded) to en-US
4199 OUString
aLangISO("en-US");
4200 SvtSysLocaleOptions aLocalOptions
;
4201 aLocalOptions
.SetLocaleConfigString(aLangISO
);
4202 aLocalOptions
.SetUILocaleConfigString(aLangISO
);
4205 static void aBasicErrorFunc(const OUString
& rError
, const OUString
& rAction
)
4207 OStringBuffer
aBuffer("Unexpected dialog: ");
4208 aBuffer
.append(OUStringToOString(rAction
, RTL_TEXTENCODING_ASCII_US
));
4209 aBuffer
.append(" Error: ");
4210 aBuffer
.append(OUStringToOString(rError
, RTL_TEXTENCODING_ASCII_US
));
4212 fprintf(stderr
, "Unexpected basic error dialog '%s'\n", aBuffer
.getStr());
4215 static bool initialize_uno(const OUString
& aAppProgramURL
)
4218 // For iOS we already hardcode the inifile as "rc" in the .app directory.
4219 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("fundamental"));
4220 xContext
= cppu::defaultBootstrap_InitialComponentContext(aAppProgramURL
+ "/rc");
4221 #elif defined MACOSX
4222 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/../Resources/" SAL_CONFIGFILE("soffice"));
4223 xContext
= cppu::defaultBootstrap_InitialComponentContext();
4225 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("soffice"));
4226 xContext
= cppu::defaultBootstrap_InitialComponentContext();
4231 gImpl
->maLastExceptionMsg
= "XComponentContext could not be created";
4232 SAL_INFO("lok", "XComponentContext could not be created");
4236 xFactory
= xContext
->getServiceManager();
4239 gImpl
->maLastExceptionMsg
= "XMultiComponentFactory could not be created";
4240 SAL_INFO("lok", "XMultiComponentFactory could not be created");
4244 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
4245 comphelper::setProcessServiceFactory(xSFactory
);
4247 SAL_INFO("lok", "Uno initialized - " << xContext
.is());
4249 // set UserInstallation to user profile dir in test/user-template
4250 // rtl::Bootstrap aDefaultVars;
4251 // aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
4252 // configmgr setup ?
4257 static void lo_startmain(void*)
4259 osl_setThreadName("lo_startmain");
4261 if (comphelper::SolarMutex::get())
4262 Application::GetSolarMutex().tryToAcquire();
4264 Application::UpdateMainThread();
4268 Application::ReleaseSolarMutex();
4271 static bool bInitialized
= false;
4273 static void lo_status_indicator_callback(void *data
, comphelper::LibreOfficeKit::statusIndicatorCallbackType type
, int percent
)
4275 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(data
);
4277 if (!pLib
->mpCallback
)
4282 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start
:
4283 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START
, nullptr, pLib
->mpCallbackData
);
4285 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue
:
4286 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
, OUString::number(percent
).toUtf8().getStr(), pLib
->mpCallbackData
);
4288 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Finish
:
4289 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH
, nullptr, pLib
->mpCallbackData
);
4294 /// Used only by LibreOfficeKit when used by Online to pre-initialize
4295 static void preloadData()
4297 // Create user profile in the temp directory for loading the dictionaries
4299 rtl::Bootstrap::get("UserInstallation", sUserPath
);
4300 utl::TempFile
aTempDir(nullptr, true);
4301 aTempDir
.EnableKillingFile();
4302 rtl::Bootstrap::set("UserInstallation", aTempDir
.GetURL());
4304 // Register the bundled extensions
4305 desktop::Desktop::SynchronizeExtensionRepositories(true);
4306 bool bAbort
= desktop::Desktop::CheckExtensionDependencies();
4308 std::cerr
<< "CheckExtensionDependencies failed" << std::endl
;
4310 // preload all available dictionaries
4311 css::uno::Reference
<css::linguistic2::XLinguServiceManager
> xLngSvcMgr
=
4312 css::linguistic2::LinguServiceManager::create(comphelper::getProcessComponentContext());
4313 css::uno::Reference
<linguistic2::XSpellChecker
> xSpellChecker(xLngSvcMgr
->getSpellChecker());
4315 std::cerr
<< "Preloading dictionaries: ";
4316 css::uno::Reference
<linguistic2::XSupportedLocales
> xSpellLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
4317 uno::Sequence
< css::lang::Locale
> aLocales
= xSpellLocales
->getLocales();
4318 for (auto &it
: aLocales
)
4320 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
4321 css::beans::PropertyValues aNone
;
4322 xSpellChecker
->isValid("forcefed", it
, aNone
);
4326 // preload all available thesauri
4327 css::uno::Reference
<linguistic2::XThesaurus
> xThesaurus(xLngSvcMgr
->getThesaurus());
4328 css::uno::Reference
<linguistic2::XSupportedLocales
> xThesLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
4329 aLocales
= xThesLocales
->getLocales();
4330 std::cerr
<< "Preloading thesauri: ";
4331 for (auto &it
: aLocales
)
4333 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
4334 css::beans::PropertyValues aNone
;
4335 xThesaurus
->queryMeanings("forcefed", it
, aNone
);
4339 // Set user profile's path back to the original one
4340 rtl::Bootstrap::set("UserInstallation", sUserPath
);
4342 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
;
4343 xGlobalCfg
= css::ui::GlobalAcceleratorConfiguration::create(
4344 comphelper::getProcessComponentContext());
4345 xGlobalCfg
->getAllKeyEvents();
4347 std::cerr
<< "Preload icons\n";
4348 ImageTree
&images
= ImageTree::get();
4349 images
.getImageUrl("forcefed.png", "style", "FO_oo");
4351 std::cerr
<< "Preload languages\n";
4353 // force load language singleton
4354 SvtLanguageTable::HasLanguageType(LANGUAGE_SYSTEM
);
4355 (void)LanguageTag::isValidBcp47("foo", nullptr);
4357 std::cerr
<< "Preload fonts\n";
4359 // Initialize fonts.
4360 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
4363 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell(xLangSrv
->getSpellChecker(), css::uno::UNO_QUERY
);
4364 css::uno::Reference
<css::linguistic2::XSupportedLocales
> xLocales(xSpell
, css::uno::UNO_QUERY
);
4366 aLocales
= xLocales
->getLocales();
4369 for (const auto& aLocale
: aLocales
)
4371 //TODO: Add more types and cache more aggressively. For now this initializes the fontcache.
4372 using namespace ::com::sun::star::i18n::ScriptType
;
4374 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), LATIN
);
4375 OutputDevice::GetDefaultFont(DefaultFontType::LATIN_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
4376 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), ASIAN
);
4377 OutputDevice::GetDefaultFont(DefaultFontType::CJK_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
4378 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), COMPLEX
);
4379 OutputDevice::GetDefaultFont(DefaultFontType::CTL_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
4383 static int lo_initialize(LibreOfficeKit
* pThis
, const char* pAppPath
, const char* pUserProfileUrl
)
4386 PRE_INIT
, // setup shared data in master process
4387 SECOND_INIT
, // complete init. after fork
4388 FULL_INIT
// do a standard complete init.
4391 // Did we do a pre-initialize
4392 static bool bPreInited
= false;
4394 // What stage are we at ?
4395 if (pThis
== nullptr)
4397 else if (bPreInited
)
4398 eStage
= SECOND_INIT
;
4402 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
4407 if (eStage
== PRE_INIT
)
4408 rtl_alloc_preInit(true);
4409 else if (eStage
== SECOND_INIT
)
4410 rtl_alloc_preInit(false);
4412 if (eStage
!= SECOND_INIT
)
4413 comphelper::LibreOfficeKit::setActive();
4415 if (eStage
!= PRE_INIT
)
4416 comphelper::LibreOfficeKit::setStatusIndicatorCallback(lo_status_indicator_callback
, pLib
);
4418 if (pUserProfileUrl
&& eStage
!= PRE_INIT
)
4421 pUserProfileUrl
, strlen(pUserProfileUrl
), RTL_TEXTENCODING_UTF8
);
4423 if (url
.startsWithIgnoreAsciiCase("vnd.sun.star.pathname:", &path
))
4426 osl::FileBase::RC e
= osl::FileBase::getFileURLFromSystemPath(
4428 if (e
== osl::FileBase::E_None
)
4431 SAL_WARN("lok", "resolving <" << url
<< "> failed with " << +e
);
4433 rtl::Bootstrap::set("UserInstallation", url
);
4434 if (eStage
== SECOND_INIT
)
4435 utl::Bootstrap::reloadData();
4441 aAppPath
= OUString(pAppPath
, strlen(pAppPath
), RTL_TEXTENCODING_UTF8
);
4445 // Fun conversion dance back and forth between URLs and system paths...
4447 ::osl::Module::getUrlFromAddress( reinterpret_cast< oslGenericFunction
>(lo_initialize
),
4449 osl::FileBase::getSystemPathFromFileURL( aAppURL
, aAppPath
);
4451 // The above gives something like
4452 // "/private/var/containers/Bundle/Application/953AA851-CC15-4C60-A2CB-C2C6F24E6F71/Foo.app/Foo",
4453 // and we want to drop the final component (the binary name).
4454 sal_Int32 lastSlash
= aAppPath
.lastIndexOf('/');
4455 assert(lastSlash
> 0);
4456 aAppPath
= aAppPath
.copy(0, lastSlash
);
4461 if (osl::FileBase::getFileURLFromSystemPath(aAppPath
, aAppURL
) != osl::FileBase::E_None
)
4465 // A LibreOffice-using iOS app should have the ICU data file in the app bundle. Initialize ICU
4467 NSString
*bundlePath
= [[NSBundle mainBundle
] bundlePath
];
4469 int fd
= open([[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
], O_RDONLY
);
4471 NSLog(@
"Could not open ICU data file %s", [[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
]);
4475 if (fstat(fd
, &st
) == -1)
4476 NSLog(@
"fstat on ICU data file failed: %s", strerror(errno
));
4479 void *icudata
= mmap(0, (size_t) st
.st_size
, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
4480 if (icudata
== MAP_FAILED
)
4481 NSLog(@
"mmap failed: %s", strerror(errno
));
4484 UErrorCode icuStatus
= U_ZERO_ERROR
;
4485 udata_setCommonData(icudata
, &icuStatus
);
4486 if (U_FAILURE(icuStatus
))
4487 NSLog(@
"udata_setCommonData failed");
4490 // Quick test that ICU works...
4491 UConverter
*cnv
= ucnv_open("iso-8859-3", &icuStatus
);
4492 NSLog(@
"ucnv_open(iso-8859-3)-> %p, err = %s, name=%s",
4493 (void *)cnv
, u_errorName(icuStatus
), (!cnv
)?"?":ucnv_getName(cnv
,&icuStatus
));
4494 if (U_SUCCESS(icuStatus
))
4505 if (eStage
!= SECOND_INIT
)
4507 SAL_INFO("lok", "Attempting to initialize UNO");
4509 if (!initialize_uno(aAppURL
))
4512 // Force headless -- this is only for bitmap rendering.
4513 rtl::Bootstrap::set("SAL_USE_VCLPLUGIN", "svp");
4515 // We specifically need to make sure we have the "headless"
4516 // command arg set (various code specifically checks via
4517 // CommandLineArgs):
4518 desktop::Desktop::GetCommandLineArgs().setHeadless();
4520 if (eStage
== PRE_INIT
)
4522 std::cerr
<< "Init vcl\n";
4525 // pre-load all component libraries.
4527 throw css::uno::DeploymentException("preInit: XComponentContext is not created");
4529 css::uno::Reference
< css::uno::XInterface
> xService
;
4530 xContext
->getValueByName("/singletons/com.sun.star.lang.theServiceManager") >>= xService
;
4532 throw css::uno::DeploymentException("preInit: XMultiComponentFactory is not created");
4534 css::uno::Reference
<css::lang::XInitialization
> aService(
4535 xService
, css::uno::UNO_QUERY_THROW
);
4538 // In order to load implementations and invoke
4539 // component factory it is required:
4540 // 1) defaultBootstrap_InitialComponentContext()
4541 // 2) comphelper::setProcessServiceFactory(xSFactory);
4543 aService
->initialize({css::uno::makeAny
<OUString
>("preload")});
4544 // Force load some modules
4545 VclBuilder::preload();
4546 VclAbstractDialogFactory::Create();
4550 // Release Solar Mutex, lo_startmain thread should acquire it.
4551 Application::ReleaseSolarMutex();
4557 // We could use InitVCL() here -- and used to before using soffice_main,
4558 // however that now deals with the initialisation for us (and it's not
4559 // possible to try to set up VCL twice.
4561 // Instead VCL init is done for us by soffice_main in a separate thread,
4562 // however we specifically can't proceed until this setup is complete
4563 // (or you get segfaults trying to use VCL and/or deadlocks due to other
4564 // setup within soffice_main). Specifically the various Application::
4565 // functions depend on VCL being ready -- the deadlocks would happen
4566 // if you try to use loadDocument too early.
4568 // The RequestHandler is specifically set to be ready when all the other
4569 // init in Desktop::Main (run from soffice_main) is done. We can enable
4570 // the RequestHandler here (without starting any IPC thread;
4571 // shortcutting the invocation in Desktop::Main that would start the IPC
4572 // thread), and can then use it to wait until we're definitely ready to
4575 if (eStage
!= PRE_INIT
)
4577 SAL_INFO("lok", "Re-initialize temp paths");
4578 SvtPathOptions aOptions
;
4580 osl::FileBase::getTempDirURL(aNewTemp
);
4581 aOptions
.SetTempPath(aNewTemp
);
4582 desktop::Desktop::CreateTemporaryDirectory();
4584 SAL_INFO("lok", "Enabling RequestHandler");
4585 RequestHandler::Enable(false);
4586 SAL_INFO("lok", "Starting soffice_main");
4587 RequestHandler::SetReady(false);
4588 pLib
->maThread
= osl_createThread(lo_startmain
, nullptr);
4589 SAL_INFO("lok", "Waiting for RequestHandler");
4590 RequestHandler::WaitForReady();
4591 SAL_INFO("lok", "RequestHandler ready -- continuing");
4594 if (eStage
!= SECOND_INIT
)
4595 ErrorRegistry::RegisterDisplay(aBasicErrorFunc
);
4597 SAL_INFO("lok", "LOK Initialized");
4598 if (eStage
== PRE_INIT
)
4601 bInitialized
= true;
4603 catch (css::uno::Exception
& exception
)
4605 fprintf(stderr
, "Bootstrapping exception '%s'\n",
4606 OUStringToOString(exception
.Message
, RTL_TEXTENCODING_UTF8
).getStr());
4609 if (eStage
== PRE_INIT
)
4611 comphelper::ThreadPool::getSharedOptimalPool().shutdown();
4614 return bInitialized
;
4617 SAL_DLLPUBLIC_EXPORT
4618 LibreOfficeKit
*libreofficekit_hook_2(const char* install_path
, const char* user_profile_url
)
4622 SAL_INFO("lok", "Create libreoffice object");
4624 gImpl
= new LibLibreOffice_Impl();
4625 if (!lo_initialize(gImpl
, install_path
, user_profile_url
))
4630 return static_cast<LibreOfficeKit
*>(gImpl
);
4633 SAL_DLLPUBLIC_EXPORT
4634 LibreOfficeKit
*libreofficekit_hook(const char* install_path
)
4636 return libreofficekit_hook_2(install_path
, nullptr);
4640 int lok_preinit(const char* install_path
, const char* user_profile_url
)
4642 return lo_initialize(nullptr, install_path
, user_profile_url
);
4645 static void lo_destroy(LibreOfficeKit
* pThis
)
4647 SolarMutexClearableGuard aGuard
;
4649 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
4652 SAL_INFO("lok", "LO Destroy");
4654 comphelper::LibreOfficeKit::setStatusIndicatorCallback(nullptr, nullptr);
4655 uno::Reference
<frame::XDesktop2
> xDesktop
= frame::Desktop::create ( ::comphelper::getProcessComponentContext() );
4656 // FIXME: the terminate() call here is a no-op because it detects
4657 // that LibreOfficeKit::isActive() and then returns early!
4658 bool bSuccess
= xDesktop
.is() && xDesktop
->terminate();
4662 bSuccess
= GetpApp() && GetpApp()->QueryExit();
4667 Application::Quit();
4672 osl_joinWithThread(pLib
->maThread
);
4673 osl_destroyThread(pLib
->maThread
);
4676 bInitialized
= false;
4677 SAL_INFO("lok", "LO Destroy Done");
4684 // Used by the unmaintained LibreOfficeLight app. Once that has been retired, get rid of this, too.
4688 __attribute__((visibility("default")))
4689 void temporaryHackToInvokeCallbackHandlers(LibreOfficeKitDocument
* pThis
)
4691 SolarMutexGuard aGuard
;
4692 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4694 int nOrigViewId
= doc_getView(pThis
);
4696 if (nOrigViewId
>= 0 && pDocument
->mpCallbackFlushHandlers
[nOrigViewId
])
4698 pDocument
->mpCallbackFlushHandlers
[nOrigViewId
]->Invoke();
4704 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */