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>
28 #include <osl/detail/android-bootstrap.h>
34 #include <boost/property_tree/json_parser.hpp>
35 #include <boost/algorithm/string.hpp>
37 #include <LibreOfficeKit/LibreOfficeKit.h>
38 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
40 #include <sal/log.hxx>
41 #include <vcl/errinf.hxx>
42 #include <vcl/lok.hxx>
43 #include <osl/file.hxx>
44 #include <osl/process.h>
45 #include <osl/thread.h>
46 #include <rtl/bootstrap.hxx>
47 #include <rtl/strbuf.hxx>
48 #include <rtl/uri.hxx>
49 #include <cppuhelper/bootstrap.hxx>
50 #include <comphelper/base64.hxx>
51 #include <comphelper/dispatchcommand.hxx>
52 #include <comphelper/lok.hxx>
53 #include <comphelper/processfactory.hxx>
54 #include <comphelper/string.hxx>
55 #include <comphelper/profilezone.hxx>
56 #include <comphelper/propertysequence.hxx>
57 #include <comphelper/scopeguard.hxx>
58 #include <comphelper/threadpool.hxx>
60 #include <com/sun/star/beans/XPropertySet.hpp>
61 #include <com/sun/star/container/XNameAccess.hpp>
62 #include <com/sun/star/frame/Desktop.hpp>
63 #include <com/sun/star/frame/DispatchResultEvent.hpp>
64 #include <com/sun/star/frame/DispatchResultState.hpp>
65 #include <com/sun/star/frame/XDispatchProvider.hpp>
66 #include <com/sun/star/frame/XDispatchResultListener.hpp>
67 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
68 #include <com/sun/star/frame/XStorable.hpp>
69 #include <com/sun/star/lang/Locale.hpp>
70 #include <com/sun/star/lang/XComponent.hpp>
71 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
72 #include <com/sun/star/reflection/theCoreReflection.hpp>
73 #include <com/sun/star/reflection/XIdlClass.hpp>
74 #include <com/sun/star/reflection/XIdlReflection.hpp>
75 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
76 #include <com/sun/star/ucb/XContentProvider.hpp>
77 #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
78 #include <com/sun/star/util/URLTransformer.hpp>
79 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
80 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
81 #include <com/sun/star/datatransfer/XTransferable2.hpp>
82 #include <com/sun/star/text/TextContentAnchorType.hpp>
83 #include <com/sun/star/document/XRedlinesSupplier.hpp>
84 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
86 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
87 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
88 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
89 #include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
90 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
91 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
92 #include <com/sun/star/security/XCertificate.hpp>
94 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
95 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
96 #include <com/sun/star/i18n/ScriptType.hpp>
97 #include <com/sun/star/lang/DisposedException.hpp>
99 #include <editeng/fontitem.hxx>
100 #include <editeng/flstitem.hxx>
101 #include <sfx2/app.hxx>
102 #include <sfx2/objsh.hxx>
103 #include <sfx2/viewsh.hxx>
104 #include <sfx2/viewfrm.hxx>
105 #include <sfx2/msgpool.hxx>
106 #include <sfx2/dispatch.hxx>
107 #include <sfx2/lokcharthelper.hxx>
108 #include <sfx2/DocumentSigner.hxx>
109 #include <svx/dialmgr.hxx>
110 #include <svx/dialogs.hrc>
111 #include <svx/strings.hrc>
112 #include <svx/ruler.hxx>
113 #include <svx/svdview.hxx>
114 #include <svx/svxids.hrc>
115 #include <svx/ucsubset.hxx>
116 #include <vcl/vclevent.hxx>
117 #include <vcl/GestureEvent.hxx>
118 #include <vcl/svapp.hxx>
119 #include <unotools/resmgr.hxx>
120 #include <tools/fract.hxx>
121 #include <svtools/ctrltool.hxx>
122 #include <svtools/langtab.hxx>
123 #include <vcl/floatwin.hxx>
124 #include <vcl/fontcharmap.hxx>
125 #include <vcl/graphicfilter.hxx>
126 #include <vcl/ptrstyle.hxx>
127 #include <vcl/sysdata.hxx>
128 #include <vcl/virdev.hxx>
129 #include <vcl/ImageTree.hxx>
130 #include <vcl/ITiledRenderable.hxx>
131 #include <vcl/IDialogRenderable.hxx>
132 #include <vcl/dialog.hxx>
133 #include <unicode/uchar.h>
134 #include <unotools/configmgr.hxx>
135 #include <unotools/syslocaleoptions.hxx>
136 #include <unotools/mediadescriptor.hxx>
137 #include <unotools/pathoptions.hxx>
138 #include <unotools/tempfile.hxx>
139 #include <unotools/streamwrap.hxx>
140 #include <osl/module.hxx>
141 #include <comphelper/sequence.hxx>
142 #include <sfx2/sfxbasemodel.hxx>
143 #include <svl/undo.hxx>
144 #include <unotools/datetime.hxx>
145 #include <i18nlangtag/mslangid.hxx>
146 #include <i18nlangtag/languagetag.hxx>
147 #include <vcl/builder.hxx>
148 #include <vcl/abstdlg.hxx>
149 #include <tools/diagnose_ex.h>
150 #include <vcl/uitest/uiobject.hxx>
154 #include "../app/cmdlineargs.hxx"
155 // We also need to hackily be able to start the main libreoffice thread:
156 #include "../app/sofficemain.h"
157 #include "../app/officeipcthread.hxx"
158 #include <lib/init.hxx>
160 #include "lokinteractionhandler.hxx"
161 #include "lokclipboard.hxx"
162 #include <officecfg/Office/Impress.hxx>
166 using namespace desktop
;
169 static LibLibreOffice_Impl
*gImpl
= nullptr;
170 static std::weak_ptr
< LibreOfficeKitClass
> gOfficeClass
;
171 static std::weak_ptr
< LibreOfficeKitDocumentClass
> gDocumentClass
;
173 static void SetLastExceptionMsg(const OUString
& s
= OUString())
175 SAL_WARN_IF(!s
.isEmpty(), "lok", "lok exception '" + s
+ "'");
177 gImpl
->maLastExceptionMsg
= s
;
183 const char *filterName
;
186 static const ExtensionMap aWriterExtensionMap
[] =
188 { "doc", "MS Word 97" },
189 { "docm", "MS Word 2007 XML VBA" },
190 { "docx", "MS Word 2007 XML" },
191 { "fodt", "OpenDocument Text Flat XML" },
192 { "html", "HTML (StarWriter)" },
193 { "odt", "writer8" },
194 { "ott", "writer8_template" },
195 { "pdf", "writer_pdf_Export" },
197 { "rtf", "Rich Text Format" },
199 { "xhtml", "XHTML Writer File" },
200 { "png", "writer_png_Export" },
204 static const ExtensionMap aCalcExtensionMap
[] =
206 { "csv", "Text - txt - csv (StarCalc)" },
207 { "fods", "OpenDocument Spreadsheet Flat XML" },
208 { "html", "HTML (StarCalc)" },
210 { "ots", "calc8_template" },
211 { "pdf", "calc_pdf_Export" },
212 { "xhtml", "XHTML Calc File" },
213 { "xls", "MS Excel 97" },
214 { "xlsm", "Calc MS Excel 2007 VBA XML" },
215 { "xlsx", "Calc MS Excel 2007 XML" },
216 { "png", "calc_png_Export" },
220 static const ExtensionMap aImpressExtensionMap
[] =
222 { "fodp", "OpenDocument Presentation Flat XML" },
223 { "html", "impress_html_Export" },
224 { "odg", "impress8_draw" },
225 { "odp", "impress8" },
226 { "otp", "impress8_template" },
227 { "pdf", "impress_pdf_Export" },
228 { "potm", "Impress MS PowerPoint 2007 XML Template" },
229 { "pot", "MS PowerPoint 97 Vorlage" },
230 { "pptm", "Impress MS PowerPoint 2007 XML VBA" },
231 { "pptx", "Impress MS PowerPoint 2007 XML" },
232 { "pps", "MS PowerPoint 97 Autoplay" },
233 { "ppt", "MS PowerPoint 97" },
234 { "svg", "impress_svg_Export" },
235 { "swf", "impress_flash_Export" },
236 { "xhtml", "XHTML Impress File" },
237 { "png", "impress_png_Export"},
241 static const ExtensionMap aDrawExtensionMap
[] =
243 { "fodg", "draw_ODG_FlatXML" },
244 { "html", "draw_html_Export" },
246 { "pdf", "draw_pdf_Export" },
247 { "svg", "draw_svg_Export" },
248 { "swf", "draw_flash_Export" },
249 { "xhtml", "XHTML Draw File" },
250 { "png", "draw_png_Export"},
254 static OUString
getUString(const char* pString
)
256 if (pString
== nullptr)
259 OString
sString(pString
, strlen(pString
));
260 return OStringToOUString(sString
, RTL_TEXTENCODING_UTF8
);
263 // Tolerate embedded \0s etc.
264 static char *convertOString(const OString
&rStr
)
266 char* pMemory
= static_cast<char*>(malloc(rStr
.getLength() + 1));
267 assert(pMemory
); // don't tolerate failed allocations.
268 memcpy(pMemory
, rStr
.getStr(), rStr
.getLength() + 1);
272 static char *convertOUString(const OUString
&aStr
)
274 return convertOString(OUStringToOString(aStr
, RTL_TEXTENCODING_UTF8
));
277 /// Try to convert a relative URL to an absolute one, unless it already looks like a URL.
278 static OUString
getAbsoluteURL(const char* pURL
)
280 OUString
aURL(getUString(pURL
));
284 // convert relative paths to absolute ones
285 OUString aWorkingDir
;
286 osl_getProcessWorkingDir(&aWorkingDir
.pData
);
287 if (!aWorkingDir
.endsWith("/"))
292 return rtl::Uri::convertRelToAbs(aWorkingDir
, aURL
);
294 catch (const rtl::MalformedUriException
&)
301 static uno::Any
jsonToUnoAny(const boost::property_tree::ptree
& aTree
)
306 uno::TypeClass aTypeClass
;
307 uno::Reference
< reflection::XIdlField
> aField
;
308 boost::property_tree::ptree aNodeNull
, aNodeValue
, aNodeField
;
309 const std::string
& rType
= aTree
.get
<std::string
>("type", "");
310 const std::string
& rValue
= aTree
.get
<std::string
>("value", "");
311 uno::Sequence
< uno::Reference
< reflection::XIdlField
> > aFields
;
312 uno::Reference
< reflection:: XIdlClass
> xIdlClass
=
313 css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())->forName(OUString::fromUtf8(rType
.c_str()));
316 aTypeClass
= xIdlClass
->getTypeClass();
317 xIdlClass
->createObject(aAny
);
318 aFields
= xIdlClass
->getFields();
319 nFields
= aFields
.getLength();
320 aNodeValue
= aTree
.get_child("value", aNodeNull
);
321 if (nFields
> 0 && aNodeValue
!= aNodeNull
)
323 for (sal_Int32 itField
= 0; itField
< nFields
; ++itField
)
325 aField
= aFields
[itField
];
326 aNodeField
= aNodeValue
.get_child(aField
->getName().toUtf8().getStr(), aNodeNull
);
327 if (aNodeField
!= aNodeNull
)
329 aValue
= jsonToUnoAny(aNodeField
);
330 aField
->set(aAny
, aValue
);
334 else if (!rValue
.empty())
336 if (aTypeClass
== uno::TypeClass_VOID
)
338 else if (aTypeClass
== uno::TypeClass_BYTE
)
339 aAny
<<= static_cast<sal_Int8
>(OString(rValue
.c_str()).toInt32());
340 else if (aTypeClass
== uno::TypeClass_BOOLEAN
)
341 aAny
<<= OString(rValue
.c_str()).toBoolean();
342 else if (aTypeClass
== uno::TypeClass_SHORT
)
343 aAny
<<= static_cast<sal_Int16
>(OString(rValue
.c_str()).toInt32());
344 else if (aTypeClass
== uno::TypeClass_UNSIGNED_SHORT
)
345 aAny
<<= static_cast<sal_uInt16
>(OString(rValue
.c_str()).toUInt32());
346 else if (aTypeClass
== uno::TypeClass_LONG
)
347 aAny
<<= OString(rValue
.c_str()).toInt32();
348 else if (aTypeClass
== uno::TypeClass_UNSIGNED_LONG
)
349 aAny
<<= static_cast<sal_uInt32
>(OString(rValue
.c_str()).toInt32());
350 else if (aTypeClass
== uno::TypeClass_FLOAT
)
351 aAny
<<= OString(rValue
.c_str()).toFloat();
352 else if (aTypeClass
== uno::TypeClass_DOUBLE
)
353 aAny
<<= OString(rValue
.c_str()).toDouble();
354 else if (aTypeClass
== uno::TypeClass_STRING
)
355 aAny
<<= OUString::fromUtf8(rValue
.c_str());
361 std::vector
<beans::PropertyValue
> desktop::jsonToPropertyValuesVector(const char* pJSON
)
363 std::vector
<beans::PropertyValue
> aArguments
;
364 if (pJSON
&& pJSON
[0] != '\0')
366 boost::property_tree::ptree aTree
, aNodeNull
, aNodeValue
;
367 std::stringstream
aStream(pJSON
);
368 boost::property_tree::read_json(aStream
, aTree
);
370 for (const auto& rPair
: aTree
)
372 const std::string
& rType
= rPair
.second
.get
<std::string
>("type", "");
373 const std::string
& rValue
= rPair
.second
.get
<std::string
>("value", "");
375 beans::PropertyValue aValue
;
376 aValue
.Name
= OUString::fromUtf8(rPair
.first
.c_str());
377 if (rType
== "string")
378 aValue
.Value
<<= OUString::fromUtf8(rValue
.c_str());
379 else if (rType
== "boolean")
380 aValue
.Value
<<= OString(rValue
.c_str()).toBoolean();
381 else if (rType
== "float")
382 aValue
.Value
<<= OString(rValue
.c_str()).toFloat();
383 else if (rType
== "long")
384 aValue
.Value
<<= OString(rValue
.c_str()).toInt32();
385 else if (rType
== "short")
386 aValue
.Value
<<= sal_Int16(OString(rValue
.c_str()).toInt32());
387 else if (rType
== "unsigned short")
388 aValue
.Value
<<= sal_uInt16(OString(rValue
.c_str()).toUInt32());
389 else if (rType
== "int64")
390 aValue
.Value
<<= OString(rValue
.c_str()).toInt64();
391 else if (rType
== "int32")
392 aValue
.Value
<<= OString(rValue
.c_str()).toInt32();
393 else if (rType
== "int16")
394 aValue
.Value
<<= sal_Int16(OString(rValue
.c_str()).toInt32());
395 else if (rType
== "uint64")
396 aValue
.Value
<<= OString(rValue
.c_str()).toUInt64();
397 else if (rType
== "uint32")
398 aValue
.Value
<<= OString(rValue
.c_str()).toUInt32();
399 else if (rType
== "uint16")
400 aValue
.Value
<<= sal_uInt16(OString(rValue
.c_str()).toUInt32());
401 else if (rType
== "[]byte")
403 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
404 if (aNodeValue
!= aNodeNull
&& aNodeValue
.size() == 0)
406 uno::Sequence
< sal_Int8
> aSeqByte(reinterpret_cast<const sal_Int8
*>(rValue
.c_str()), rValue
.size());
407 aValue
.Value
<<= aSeqByte
;
410 else if (rType
== "[]any")
412 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
413 if (aNodeValue
!= aNodeNull
&& !aNodeValue
.empty())
416 uno::Sequence
< uno::Any
> aSeq(aNodeValue
.size());
417 for (const auto& rSeqPair
: aNodeValue
)
418 aSeq
[itSeq
++] = jsonToUnoAny(rSeqPair
.second
);
419 aValue
.Value
<<= aSeq
;
423 SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled type '"<<rType
<<"'");
424 aArguments
.push_back(aValue
);
431 static StringMap
jsonToStringMap(const char* pJSON
)
434 if (pJSON
&& pJSON
[0] != '\0')
436 std::stringstream
aStream(pJSON
);
437 boost::property_tree::ptree aTree
;
438 boost::property_tree::read_json(aStream
, aTree
);
440 for (const auto& rPair
: aTree
)
442 aArgs
[OUString::fromUtf8(rPair
.first
.c_str())] = OUString::fromUtf8(rPair
.second
.get_value
<std::string
>(".").c_str());
449 static boost::property_tree::ptree
unoAnyToPropertyTree(const uno::Any
& anyItem
)
451 boost::property_tree::ptree aTree
;
452 OUString aType
= anyItem
.getValueTypeName();
453 aTree
.put("type", aType
.toUtf8().getStr());
455 if (aType
== "string")
456 aTree
.put("value", anyItem
.get
<OUString
>().toUtf8().getStr());
457 else if (aType
== "unsigned long")
458 aTree
.put("value", OString::number(anyItem
.get
<sal_uInt32
>()).getStr());
459 else if (aType
== "long")
460 aTree
.put("value", OString::number(anyItem
.get
<sal_Int32
>()).getStr());
461 else if (aType
== "[]any")
463 uno::Sequence
<uno::Any
> aSeq
;
464 if (anyItem
>>= aSeq
)
466 boost::property_tree::ptree aSubTree
;
468 for (auto i
= 0; i
< aSeq
.getLength(); ++i
)
470 aSubTree
.add_child(OString::number(i
).getStr(), unoAnyToPropertyTree(aSeq
[i
]));
472 aTree
.add_child("value", aSubTree
);
476 // TODO: Add more as required
483 RectangleAndPart
RectangleAndPart::Create(const std::string
& rPayload
)
485 RectangleAndPart aRet
;
486 if (rPayload
.compare(0, 5, "EMPTY") == 0) // payload starts with "EMPTY"
488 aRet
.m_aRectangle
= tools::Rectangle(0, 0, SfxLokHelper::MaxTwips
, SfxLokHelper::MaxTwips
);
489 if (comphelper::LibreOfficeKit::isPartInInvalidation())
490 aRet
.m_nPart
= std::stol(rPayload
.substr(6));
495 std::istringstream
aStream(rPayload
);
496 long nLeft
, nTop
, nWidth
, nHeight
;
497 long nPart
= INT_MIN
;
499 if (comphelper::LibreOfficeKit::isPartInInvalidation())
501 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
>> nComma
>> nPart
;
505 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
508 if (nWidth
> 0 && nHeight
> 0)
510 // The top-left corner starts at (0, 0).
511 // Anything negative is invalid.
524 if (nWidth
> 0 && nHeight
> 0)
526 aRet
.m_aRectangle
= tools::Rectangle(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
529 // else leave empty rect.
531 aRet
.m_nPart
= nPart
;
535 RectangleAndPart
& CallbackFlushHandler::CallbackData::setRectangleAndPart(const std::string
& payload
)
537 setRectangleAndPart(RectangleAndPart::Create(payload
));
539 // Return reference to the cached object.
540 return boost::get
<RectangleAndPart
>(PayloadObject
);
543 void CallbackFlushHandler::CallbackData::setRectangleAndPart(const RectangleAndPart
& rRectAndPart
)
545 PayloadString
= rRectAndPart
.toString().getStr();
546 PayloadObject
= rRectAndPart
;
549 const RectangleAndPart
& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
551 assert(PayloadObject
.which() == 1);
552 return boost::get
<RectangleAndPart
>(PayloadObject
);
555 boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::setJson(const std::string
& payload
)
557 boost::property_tree::ptree aTree
;
558 std::stringstream
aStream(payload
);
559 boost::property_tree::read_json(aStream
, aTree
);
561 // Let boost normalize the payload so it always matches the cache.
564 // Return reference to the cached object.
565 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
568 void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree
& rTree
)
570 std::stringstream aJSONStream
;
571 constexpr bool bPretty
= false; // Don't waste time and bloat logs.
572 boost::property_tree::write_json(aJSONStream
, rTree
, bPretty
);
573 PayloadString
= boost::trim_copy(aJSONStream
.str());
575 PayloadObject
= rTree
;
578 const boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::getJson() const
580 assert(PayloadObject
.which() == 2);
581 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
584 bool CallbackFlushHandler::CallbackData::validate() const
586 switch (PayloadObject
.which())
594 return getRectangleAndPart().toString().getStr() == PayloadString
;
599 std::stringstream aJSONStream
;
600 boost::property_tree::write_json(aJSONStream
, getJson(), false);
601 const std::string aExpected
= boost::trim_copy(aJSONStream
.str());
602 return aExpected
== PayloadString
;
606 assert(!"Unknown variant type; please add an entry to validate.");
616 bool lcl_isViewCallbackType(const int type
)
620 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
621 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
622 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
623 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
624 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
632 int lcl_getViewId(const std::string
& payload
)
634 // this is a cheap way how to get the viewId from a JSON message; proper
635 // parsing is terribly expensive, and we just need the viewId here
636 size_t viewIdPos
= payload
.find("viewId");
637 if (viewIdPos
== std::string::npos
)
640 size_t numberPos
= payload
.find(":", viewIdPos
+ 6);
641 if (numberPos
== std::string::npos
)
644 for (++numberPos
; numberPos
< payload
.length(); ++numberPos
)
646 if (payload
[numberPos
] == ',' || payload
[numberPos
] == '}' || (payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9'))
650 if (numberPos
< payload
.length() && payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9')
651 return strtol(payload
.substr(numberPos
).c_str(), nullptr, 10);
656 int lcl_getViewId(const desktop::CallbackFlushHandler::CallbackData
& rCallbackData
)
658 if (rCallbackData
.isCached())
659 return rCallbackData
.getJson().get
<int>("viewId");
660 return lcl_getViewId(rCallbackData
.PayloadString
);
663 std::string
extractCertificate(const std::string
& certificate
)
665 const std::string
header("-----BEGIN CERTIFICATE-----");
666 const std::string
footer("-----END CERTIFICATE-----");
670 size_t pos1
= certificate
.find(header
);
671 if (pos1
== std::string::npos
)
674 size_t pos2
= certificate
.find(footer
, pos1
+ 1);
675 if (pos2
== std::string::npos
)
678 pos1
= pos1
+ header
.length();
681 return certificate
.substr(pos1
, pos2
);
684 std::string
extractPrivateKey(const std::string
& privateKey
)
686 const std::string
header("-----BEGIN PRIVATE KEY-----");
687 const std::string
footer("-----END PRIVATE KEY-----");
691 size_t pos1
= privateKey
.find(header
);
692 if (pos1
== std::string::npos
)
695 size_t pos2
= privateKey
.find(footer
, pos1
+ 1);
696 if (pos2
== std::string::npos
)
699 pos1
= pos1
+ header
.length();
702 return privateKey
.substr(pos1
, pos2
);
705 } // end anonymous namespace
707 // Could be anonymous in principle, but for the unit testing purposes, we
708 // declare it in init.hxx.
709 OUString
desktop::extractParameter(OUString
& rOptions
, const OUString
& rName
)
713 OUString
aNameEquals(rName
+ "=");
714 OUString
aCommaNameEquals("," + rName
+ "=");
717 if (rOptions
.startsWith(aNameEquals
))
719 size_t nLen
= aNameEquals
.getLength();
720 int nComma
= rOptions
.indexOf(",", nLen
);
723 aValue
= rOptions
.copy(nLen
, nComma
- nLen
);
724 rOptions
= rOptions
.copy(nComma
+ 1);
728 aValue
= rOptions
.copy(nLen
);
732 else if ((nIndex
= rOptions
.indexOf(aCommaNameEquals
)) >= 0)
734 size_t nLen
= aCommaNameEquals
.getLength();
735 int nComma
= rOptions
.indexOf(",", nIndex
+ nLen
);
738 aValue
= rOptions
.copy(nIndex
+ nLen
, nComma
- nIndex
- nLen
);
739 rOptions
= rOptions
.copy(0, nIndex
) + rOptions
.copy(nComma
);
743 aValue
= rOptions
.copy(nIndex
+ nLen
);
744 rOptions
= rOptions
.copy(0, nIndex
);
754 static void doc_destroy(LibreOfficeKitDocument
* pThis
);
755 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* pUrl
, const char* pFormat
, const char* pFilterOptions
);
756 static int doc_getDocumentType(LibreOfficeKitDocument
* pThis
);
757 static int doc_getParts(LibreOfficeKitDocument
* pThis
);
758 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
);
759 static int doc_getPart(LibreOfficeKitDocument
* pThis
);
760 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
);
761 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
);
762 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
);
763 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
);
764 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
, int nPartMode
);
765 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
766 unsigned char* pBuffer
,
767 const int nCanvasWidth
, const int nCanvasHeight
,
768 const int nTilePosX
, const int nTilePosY
,
769 const int nTileWidth
, const int nTileHeight
);
771 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
773 const int nCanvasWidth
, const int nCanvasHeight
,
774 const int nTilePosX
, const int nTilePosY
,
775 const int nTileWidth
, const int nTileHeight
);
777 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
778 unsigned char* pBuffer
,
780 const int nCanvasWidth
, const int nCanvasHeight
,
781 const int nTilePosX
, const int nTilePosY
,
782 const int nTileWidth
, const int nTileHeight
);
783 static int doc_getTileMode(LibreOfficeKitDocument
* pThis
);
784 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
787 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
788 const char* pArguments
);
790 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
791 LibreOfficeKitCallback pCallback
,
793 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
,
797 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
,
801 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
,
802 unsigned nLOKWindowId
,
805 static void doc_sendDialogEvent(LibreOfficeKitDocument
* pThis
,
806 unsigned nLOKWindowId
,
807 const char* pArguments
);
808 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* pThis
,
809 unsigned nLOKWindowId
,
813 static void doc_postMouseEvent (LibreOfficeKitDocument
* pThis
,
820 static void doc_postWindowMouseEvent (LibreOfficeKitDocument
* pThis
,
821 unsigned nLOKWindowId
,
828 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* pThis
,
829 unsigned nLOKWindowId
,
834 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
,
835 const char* pCommand
,
836 const char* pArguments
,
837 bool bNotifyWhenFinished
);
838 static void doc_setTextSelection (LibreOfficeKitDocument
* pThis
,
842 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
,
843 const char* pMimeType
,
844 char** pUsedMimeType
);
845 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
);
846 static int doc_getClipboard (LibreOfficeKitDocument
* pThis
,
847 const char **pMimeTypes
,
849 char ***pOutMimeTypes
,
851 char ***pOutStreams
);
852 static int doc_setClipboard (LibreOfficeKitDocument
* pThis
,
853 const size_t nInCount
,
854 const char **pInMimeTypes
,
855 const size_t *pInSizes
,
856 const char **pInStreams
);
857 static bool doc_paste(LibreOfficeKitDocument
* pThis
,
858 const char* pMimeType
,
861 static void doc_setGraphicSelection (LibreOfficeKitDocument
* pThis
,
865 static void doc_resetSelection (LibreOfficeKitDocument
* pThis
);
866 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
);
867 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
,
869 int nTilePixelHeight
,
871 int nTileTwipHeight
);
872 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
);
873 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
);
874 static int doc_createView(LibreOfficeKitDocument
* pThis
);
875 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
, const char* pOptions
);
876 static void doc_destroyView(LibreOfficeKitDocument
* pThis
, int nId
);
877 static void doc_setView(LibreOfficeKitDocument
* pThis
, int nId
);
878 static int doc_getView(LibreOfficeKitDocument
* pThis
);
879 static int doc_getViewsCount(LibreOfficeKitDocument
* pThis
);
880 static bool doc_getViewIds(LibreOfficeKitDocument
* pThis
, int* pArray
, size_t nSize
);
881 static void doc_setViewLanguage(LibreOfficeKitDocument
* pThis
, int nId
, const char* language
);
882 static unsigned char* doc_renderFontOrientation(LibreOfficeKitDocument
* pThis
,
883 const char *pFontName
,
888 static unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
889 const char *pFontName
,
893 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
);
895 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
896 const int nX
, const int nY
,
897 const int nWidth
, const int nHeight
);
899 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
900 const int nX
, const int nY
,
901 const int nWidth
, const int nHeight
,
902 const double fDPIScale
);
904 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
905 const int nX
, const int nY
,
906 const int nWidth
, const int nHeight
,
907 const double fDPIScale
, int viewId
);
909 static void doc_postWindow(LibreOfficeKitDocument
* pThis
, unsigned
910 nLOKWindowId
, int nAction
, const char* pData
);
912 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
);
914 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
915 const unsigned char* pCertificateBinary
,
916 const int nCertificateBinarySize
,
917 const unsigned char* pPrivateKeyBinary
,
918 const int nPrivateKeyBinarySize
);
920 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
921 const unsigned char* pCertificateBinary
,
922 const int nCertificateBinarySize
);
924 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
);
926 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
);
928 static void doc_resizeWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
929 const int nWidth
, const int nHeight
);
934 ITiledRenderable
* getTiledRenderable(LibreOfficeKitDocument
* pThis
)
936 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
937 return dynamic_cast<ITiledRenderable
*>(pDocument
->mxComponent
.get());
943 * Unfortunately clipboard creation using UNO is insanely baroque.
944 * we also need to ensure that this works for the first view which
945 * has no clear 'createView' called for it (unfortunately).
947 rtl::Reference
<LOKClipboard
> forceSetClipboardForCurrentView(LibreOfficeKitDocument
*pThis
)
949 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
950 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
952 SAL_INFO("lok", "Set to clipboard for view " << xClip
.get());
953 // FIXME: using a hammer here - should not be necessary if all tests used createView.
954 pDoc
->setClipboard(uno::Reference
<datatransfer::clipboard::XClipboard
>(xClip
->getXI(), UNO_QUERY
));
961 } // anonymous namespace
963 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference
<css::lang::XComponent
> &xComponent
)
964 : mxComponent(xComponent
)
966 if (!(m_pDocumentClass
= gDocumentClass
.lock()))
968 m_pDocumentClass
.reset(new LibreOfficeKitDocumentClass
);
970 m_pDocumentClass
->nSize
= sizeof(LibreOfficeKitDocumentClass
);
972 m_pDocumentClass
->destroy
= doc_destroy
;
973 m_pDocumentClass
->saveAs
= doc_saveAs
;
974 m_pDocumentClass
->getDocumentType
= doc_getDocumentType
;
975 m_pDocumentClass
->getParts
= doc_getParts
;
976 m_pDocumentClass
->getPartPageRectangles
= doc_getPartPageRectangles
;
977 m_pDocumentClass
->getPart
= doc_getPart
;
978 m_pDocumentClass
->setPart
= doc_setPart
;
979 m_pDocumentClass
->selectPart
= doc_selectPart
;
980 m_pDocumentClass
->moveSelectedParts
= doc_moveSelectedParts
;
981 m_pDocumentClass
->getPartName
= doc_getPartName
;
982 m_pDocumentClass
->setPartMode
= doc_setPartMode
;
983 m_pDocumentClass
->paintTile
= doc_paintTile
;
985 m_pDocumentClass
->paintTileToCGContext
= doc_paintTileToCGContext
;
987 m_pDocumentClass
->paintPartTile
= doc_paintPartTile
;
988 m_pDocumentClass
->getTileMode
= doc_getTileMode
;
989 m_pDocumentClass
->getDocumentSize
= doc_getDocumentSize
;
990 m_pDocumentClass
->initializeForRendering
= doc_initializeForRendering
;
991 m_pDocumentClass
->registerCallback
= doc_registerCallback
;
992 m_pDocumentClass
->postKeyEvent
= doc_postKeyEvent
;
993 m_pDocumentClass
->postWindowExtTextInputEvent
= doc_postWindowExtTextInputEvent
;
994 m_pDocumentClass
->removeTextContext
= doc_removeTextContext
;
995 m_pDocumentClass
->postWindowKeyEvent
= doc_postWindowKeyEvent
;
996 m_pDocumentClass
->postMouseEvent
= doc_postMouseEvent
;
997 m_pDocumentClass
->postWindowMouseEvent
= doc_postWindowMouseEvent
;
998 m_pDocumentClass
->sendDialogEvent
= doc_sendDialogEvent
;
999 m_pDocumentClass
->postUnoCommand
= doc_postUnoCommand
;
1000 m_pDocumentClass
->setTextSelection
= doc_setTextSelection
;
1001 m_pDocumentClass
->getTextSelection
= doc_getTextSelection
;
1002 m_pDocumentClass
->getSelectionType
= doc_getSelectionType
;
1003 m_pDocumentClass
->getClipboard
= doc_getClipboard
;
1004 m_pDocumentClass
->setClipboard
= doc_setClipboard
;
1005 m_pDocumentClass
->paste
= doc_paste
;
1006 m_pDocumentClass
->setGraphicSelection
= doc_setGraphicSelection
;
1007 m_pDocumentClass
->resetSelection
= doc_resetSelection
;
1008 m_pDocumentClass
->getCommandValues
= doc_getCommandValues
;
1009 m_pDocumentClass
->setClientZoom
= doc_setClientZoom
;
1010 m_pDocumentClass
->setClientVisibleArea
= doc_setClientVisibleArea
;
1011 m_pDocumentClass
->setOutlineState
= doc_setOutlineState
;
1013 m_pDocumentClass
->createView
= doc_createView
;
1014 m_pDocumentClass
->destroyView
= doc_destroyView
;
1015 m_pDocumentClass
->setView
= doc_setView
;
1016 m_pDocumentClass
->getView
= doc_getView
;
1017 m_pDocumentClass
->getViewsCount
= doc_getViewsCount
;
1018 m_pDocumentClass
->getViewIds
= doc_getViewIds
;
1020 m_pDocumentClass
->renderFont
= doc_renderFont
;
1021 m_pDocumentClass
->renderFontOrientation
= doc_renderFontOrientation
;
1022 m_pDocumentClass
->getPartHash
= doc_getPartHash
;
1024 m_pDocumentClass
->paintWindow
= doc_paintWindow
;
1025 m_pDocumentClass
->paintWindowDPI
= doc_paintWindowDPI
;
1026 m_pDocumentClass
->paintWindowForView
= doc_paintWindowForView
;
1027 m_pDocumentClass
->postWindow
= doc_postWindow
;
1028 m_pDocumentClass
->resizeWindow
= doc_resizeWindow
;
1030 m_pDocumentClass
->setViewLanguage
= doc_setViewLanguage
;
1032 m_pDocumentClass
->getPartInfo
= doc_getPartInfo
;
1034 m_pDocumentClass
->insertCertificate
= doc_insertCertificate
;
1035 m_pDocumentClass
->addCertificate
= doc_addCertificate
;
1036 m_pDocumentClass
->getSignatureState
= doc_getSignatureState
;
1038 m_pDocumentClass
->renderShapeSelection
= doc_renderShapeSelection
;
1039 m_pDocumentClass
->postWindowGestureEvent
= doc_postWindowGestureEvent
;
1041 m_pDocumentClass
->createViewWithOptions
= doc_createViewWithOptions
;
1043 gDocumentClass
= m_pDocumentClass
;
1045 pClass
= m_pDocumentClass
.get();
1048 forceSetClipboardForCurrentView(this);
1052 LibLODocument_Impl::~LibLODocument_Impl()
1056 mxComponent
->dispose();
1058 catch (const css::lang::DisposedException
& rException
)
1060 SAL_WARN("lok", "failed to dispose document:" << rException
.Message
);
1064 static OUString
getGenerator()
1066 OUString
sGenerator(
1067 Translate::ExpandVariables("%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)"));
1068 OUString
os("$_OS");
1069 ::rtl::Bootstrap::expandMacros(os
);
1070 return sGenerator
.replaceFirst("%1", os
);
1075 CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument
* pDocument
, LibreOfficeKitCallback pCallback
, void* pData
)
1076 : Idle( "lokit timer callback" ),
1077 m_pDocument(pDocument
),
1078 m_pCallback(pCallback
),
1080 m_nDisableCallbacks(0),
1081 m_bEventLatch(false)
1083 SetPriority(TaskPriority::POST_PAINT
);
1085 // Add the states that are safe to skip duplicates on, even when
1086 // not consequent (i.e. do no emit them if unchanged from last).
1087 m_states
.emplace(LOK_CALLBACK_TEXT_SELECTION
, "NIL");
1088 m_states
.emplace(LOK_CALLBACK_GRAPHIC_SELECTION
, "NIL");
1089 m_states
.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
, "NIL");
1090 m_states
.emplace(LOK_CALLBACK_STATE_CHANGED
, "NIL");
1091 m_states
.emplace(LOK_CALLBACK_MOUSE_POINTER
, "NIL");
1092 m_states
.emplace(LOK_CALLBACK_CELL_CURSOR
, "NIL");
1093 m_states
.emplace(LOK_CALLBACK_CELL_FORMULA
, "NIL");
1094 m_states
.emplace(LOK_CALLBACK_CELL_ADDRESS
, "NIL");
1095 m_states
.emplace(LOK_CALLBACK_CURSOR_VISIBLE
, "NIL");
1096 m_states
.emplace(LOK_CALLBACK_SET_PART
, "NIL");
1101 CallbackFlushHandler::~CallbackFlushHandler()
1106 void CallbackFlushHandler::callback(const int type
, const char* payload
, void* data
)
1108 CallbackFlushHandler
* self
= static_cast<CallbackFlushHandler
*>(data
);
1111 self
->queue(type
, payload
);
1115 void CallbackFlushHandler::queue(const int type
, const char* data
)
1117 comphelper::ProfileZone
aZone("CallbackFlushHander::queue");
1119 CallbackData
aCallbackData(type
, (data
? data
: "(nil)"));
1120 const std::string
& payload
= aCallbackData
.PayloadString
;
1121 SAL_INFO("lok", "Queue: [" << type
<< "]: [" << payload
<< "] on " << m_queue
.size() << " entries.");
1123 bool bIsChartActive
= false;
1124 if (type
== LOK_CALLBACK_GRAPHIC_SELECTION
)
1126 LokChartHelper
aChartHelper(SfxViewShell::Current());
1127 bIsChartActive
= aChartHelper
.GetWindow() != nullptr;
1130 if (callbacksDisabled() && !bIsChartActive
)
1132 // We drop notifications when this is set, except for important ones.
1133 // When we issue a complex command (such as .uno:InsertAnnotation)
1134 // there will be multiple notifications. On the first invalidation
1135 // we will start painting, but other events will get fired
1136 // while the complex command in question executes.
1137 // We don't want to suppress everything here on the wrong assumption
1138 // that no new events are fired during painting.
1139 if (type
!= LOK_CALLBACK_STATE_CHANGED
&&
1140 type
!= LOK_CALLBACK_INVALIDATE_TILES
&&
1141 type
!= LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1142 type
!= LOK_CALLBACK_CURSOR_VISIBLE
&&
1143 type
!= LOK_CALLBACK_VIEW_CURSOR_VISIBLE
&&
1144 type
!= LOK_CALLBACK_TEXT_SELECTION
&&
1145 type
!= LOK_CALLBACK_REFERENCE_MARKS
)
1147 SAL_INFO("lok", "Skipping while painting [" << type
<< "]: [" << payload
<< "].");
1151 // In Writer we drop all notifications during painting.
1152 if (doc_getDocumentType(m_pDocument
) == LOK_DOCTYPE_TEXT
)
1156 // Suppress invalid payloads.
1157 if (type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1158 payload
.find(", 0, 0, ") != std::string::npos
)
1160 // The cursor position is often the relative coordinates of the widget
1161 // issuing it, instead of the absolute one that we expect.
1162 // This is temporary however, and, once the control is created and initialized
1163 // correctly, it eventually emits the correct absolute coordinates.
1164 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
1168 std::unique_lock
<std::mutex
> lock(m_mutex
);
1170 // drop duplicate callbacks for the listed types
1173 case LOK_CALLBACK_TEXT_SELECTION_START
:
1174 case LOK_CALLBACK_TEXT_SELECTION_END
:
1175 case LOK_CALLBACK_TEXT_SELECTION
:
1176 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1177 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1178 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1179 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1180 case LOK_CALLBACK_STATE_CHANGED
:
1181 case LOK_CALLBACK_MOUSE_POINTER
:
1182 case LOK_CALLBACK_CELL_CURSOR
:
1183 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1184 case LOK_CALLBACK_CELL_FORMULA
:
1185 case LOK_CALLBACK_CELL_ADDRESS
:
1186 case LOK_CALLBACK_CURSOR_VISIBLE
:
1187 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1188 case LOK_CALLBACK_SET_PART
:
1189 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1190 case LOK_CALLBACK_INVALIDATE_HEADER
:
1191 case LOK_CALLBACK_WINDOW
:
1193 const auto& pos
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1194 [type
] (const queue_type::value_type
& elem
) { return (elem
.Type
== type
); });
1196 if (pos
!= m_queue
.rend() && pos
->PayloadString
== payload
)
1198 SAL_INFO("lok", "Skipping queue duplicate [" << type
<< + "]: [" << payload
<< "].");
1205 if (type
== LOK_CALLBACK_TEXT_SELECTION
&& payload
.empty())
1207 const auto& posStart
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1208 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_START
); });
1209 if (posStart
!= m_queue
.rend())
1210 posStart
->PayloadString
.clear();
1212 const auto& posEnd
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1213 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_END
); });
1214 if (posEnd
!= m_queue
.rend())
1215 posEnd
->PayloadString
.clear();
1218 // When payload is empty discards any previous state.
1219 if (payload
.empty())
1223 case LOK_CALLBACK_TEXT_SELECTION_START
:
1224 case LOK_CALLBACK_TEXT_SELECTION_END
:
1225 case LOK_CALLBACK_TEXT_SELECTION
:
1226 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1227 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1228 case LOK_CALLBACK_INVALIDATE_TILES
:
1230 [type
](const queue_type::value_type
& elem
) { return (elem
.Type
== type
); }))
1231 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << payload
<< "].");
1239 // These are safe to use the latest state and ignore previous
1240 // ones (if any) since the last overrides previous ones.
1241 case LOK_CALLBACK_TEXT_SELECTION_START
:
1242 case LOK_CALLBACK_TEXT_SELECTION_END
:
1243 case LOK_CALLBACK_TEXT_SELECTION
:
1244 case LOK_CALLBACK_MOUSE_POINTER
:
1245 case LOK_CALLBACK_CELL_CURSOR
:
1246 case LOK_CALLBACK_CELL_FORMULA
:
1247 case LOK_CALLBACK_CELL_ADDRESS
:
1248 case LOK_CALLBACK_CURSOR_VISIBLE
:
1249 case LOK_CALLBACK_SET_PART
:
1250 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
:
1251 case LOK_CALLBACK_RULER_UPDATE
:
1254 [type
](const queue_type::value_type
& elem
) { return (elem
.Type
== type
); }))
1255 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << payload
<< "].");
1259 // These are safe to use the latest state and ignore previous
1260 // ones (if any) since the last overrides previous ones,
1261 // but only if the view is the same.
1262 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1263 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1264 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1265 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1266 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1267 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1269 const int nViewId
= lcl_getViewId(payload
);
1271 [type
, nViewId
] (const queue_type::value_type
& elem
) {
1272 return (elem
.Type
== type
&& nViewId
== lcl_getViewId(elem
));
1278 case LOK_CALLBACK_INVALIDATE_TILES
:
1279 if (processInvalidateTilesEvent(aCallbackData
))
1283 // State changes with same name override previous ones with a different value.
1284 // Ex. ".uno:PageStatus=Slide 20 of 83" overwrites any previous PageStatus.
1285 case LOK_CALLBACK_STATE_CHANGED
:
1287 // Compare the state name=value and overwrite earlier entries with same name.
1288 const auto pos
= payload
.find('=');
1289 if (pos
!= std::string::npos
)
1291 const std::string name
= payload
.substr(0, pos
+ 1);
1293 [type
, &name
] (const queue_type::value_type
& elem
) {
1294 return (elem
.Type
== type
) && (elem
.PayloadString
.compare(0, name
.size(), name
) == 0);
1301 case LOK_CALLBACK_WINDOW
:
1302 if (processWindowEvent(aCallbackData
))
1306 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1308 // remove only selection ranges and 'EMPTY' messages
1309 // always send 'INPLACE' and 'INPLACE EXIT' messages
1310 removeAll([type
, payload
] (const queue_type::value_type
& elem
)
1311 { return (elem
.Type
== type
&& elem
.PayloadString
[0] != 'I'); });
1317 // Validate that the cached data and the payload string are identical.
1318 assert(aCallbackData
.validate() && "Cached callback payload object and string mismatch!");
1319 m_queue
.emplace_back(aCallbackData
);
1320 SAL_INFO("lok", "Queued #" << (m_queue
.size() - 1) <<
1321 " [" << type
<< "]: [" << payload
<< "] to have " << m_queue
.size() << " entries.");
1325 // Dump the queue state and validate cached data.
1327 std::ostringstream oss
;
1328 if (m_queue
.empty())
1331 oss
<< m_queue
.size() << " items\n";
1332 for (const CallbackData
& c
: m_queue
)
1333 oss
<< i
++ << ": [" << c
.Type
<< "] [" << c
.PayloadString
<< "].\n";
1334 SAL_INFO("lok", "Current Queue: " << oss
.str());
1335 for (const CallbackData
& c
: m_queue
)
1336 assert(c
.validate());
1347 bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData
& aCallbackData
)
1349 const std::string
& payload
= aCallbackData
.PayloadString
;
1350 const int type
= aCallbackData
.Type
;
1352 RectangleAndPart
& rcNew
= aCallbackData
.setRectangleAndPart(payload
);
1353 if (rcNew
.isEmpty())
1355 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
1359 // If we have to invalidate all tiles, we can skip any new tile invalidation.
1360 // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
1362 = std::find_if(m_queue
.rbegin(), m_queue
.rend(), [](const queue_type::value_type
& elem
) {
1363 return (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
);
1365 if (pos
!= m_queue
.rend())
1367 const RectangleAndPart
& rcOld
= pos
->getRectangleAndPart();
1368 if (rcOld
.isInfinite() && (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
))
1370 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
1371 << "] since all tiles need to be invalidated.");
1375 if (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
)
1377 // If fully overlapping.
1378 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1380 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
1381 << "] since overlaps existing all-parts.");
1387 if (rcNew
.isInfinite())
1389 SAL_INFO("lok", "Have Empty [" << type
<< "]: [" << payload
1390 << "] so removing all with part " << rcNew
.m_nPart
<< ".");
1391 removeAll([&rcNew
](const queue_type::value_type
& elem
) {
1392 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1394 // Remove exiting if new is all-encompassing, or if of the same part.
1395 const RectangleAndPart rcOld
= RectangleAndPart::Create(elem
.PayloadString
);
1396 return (rcNew
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
);
1405 const auto rcOrig
= rcNew
;
1407 SAL_INFO("lok", "Have [" << type
<< "]: [" << payload
<< "] so merging overlapping.");
1408 removeAll([&rcNew
](const queue_type::value_type
& elem
) {
1409 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1411 const RectangleAndPart
& rcOld
= elem
.getRectangleAndPart();
1412 if (rcNew
.m_nPart
!= -1 && rcOld
.m_nPart
!= -1 && rcOld
.m_nPart
!= rcNew
.m_nPart
)
1414 SAL_INFO("lok", "Nothing to merge between new: "
1415 << rcNew
.toString() << ", and old: " << rcOld
.toString());
1419 if (rcNew
.m_nPart
== -1)
1421 // Don't merge unless fully overlapped.
1422 SAL_INFO("lok", "New " << rcNew
.toString() << " has " << rcOld
.toString()
1424 if (rcNew
.m_aRectangle
.IsInside(rcOld
.m_aRectangle
))
1426 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
1427 << rcOld
.toString() << ".");
1431 else if (rcOld
.m_nPart
== -1)
1433 // Don't merge unless fully overlapped.
1434 SAL_INFO("lok", "Old " << rcOld
.toString() << " has " << rcNew
.toString()
1436 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1438 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
1439 << rcOld
.toString() << ".");
1445 const tools::Rectangle rcOverlap
1446 = rcNew
.m_aRectangle
.GetIntersection(rcOld
.m_aRectangle
);
1447 const bool bOverlap
= !rcOverlap
.IsEmpty();
1448 SAL_INFO("lok", "Merging " << rcNew
.toString() << " & " << rcOld
.toString()
1449 << " => " << rcOverlap
.toString()
1450 << " Overlap: " << bOverlap
);
1453 rcNew
.m_aRectangle
.Union(rcOld
.m_aRectangle
);
1454 SAL_INFO("lok", "Merged: " << rcNew
.toString());
1464 if (rcNew
.m_aRectangle
!= rcOrig
.m_aRectangle
)
1466 SAL_INFO("lok", "Replacing: " << rcOrig
.toString() << " by " << rcNew
.toString());
1467 if (rcNew
.m_aRectangle
.GetWidth() < rcOrig
.m_aRectangle
.GetWidth()
1468 || rcNew
.m_aRectangle
.GetHeight() < rcOrig
.m_aRectangle
.GetHeight())
1470 SAL_WARN("lok", "Error: merged rect smaller.");
1475 aCallbackData
.setRectangleAndPart(rcNew
);
1480 bool CallbackFlushHandler::processWindowEvent(CallbackData
& aCallbackData
)
1482 const std::string
& payload
= aCallbackData
.PayloadString
;
1483 const int type
= aCallbackData
.Type
;
1485 boost::property_tree::ptree
& aTree
= aCallbackData
.setJson(payload
);
1486 const unsigned nLOKWindowId
= aTree
.get
<unsigned>("id", 0);
1487 const std::string aAction
= aTree
.get
<std::string
>("action", "");
1488 if (aAction
== "invalidate")
1490 std::string aRectStr
= aTree
.get
<std::string
>("rectangle", "");
1491 // no 'rectangle' field => invalidate all of the window =>
1492 // remove all previous window part invalidations
1493 if (aRectStr
.empty())
1495 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1496 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1498 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1499 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
1500 && aOldTree
.get
<std::string
>("action", "") == "invalidate")
1510 // if we have to invalidate all of the window, ignore
1511 // any part invalidation message
1512 const auto invAllExist
= std::any_of(m_queue
.rbegin(), m_queue
.rend(),
1513 [&nLOKWindowId
] (const queue_type::value_type
& elem
)
1515 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1518 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1519 return nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
1520 && aOldTree
.get
<std::string
>("action", "") == "invalidate"
1521 && aOldTree
.get
<std::string
>("rectangle", "").empty();
1524 // we found a invalidate-all window callback
1527 SAL_INFO("lok.dialog", "Skipping queue ["
1528 << type
<< "]: [" << payload
1529 << "] since whole window needs to be invalidated.");
1533 std::istringstream
aRectStream(aRectStr
);
1534 long nLeft
, nTop
, nWidth
, nHeight
;
1536 aRectStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
1537 tools::Rectangle
aNewRect(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
1538 bool currentIsRedundant
= false;
1539 removeAll([&aNewRect
, &nLOKWindowId
,
1540 ¤tIsRedundant
](const queue_type::value_type
& elem
) {
1541 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1544 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1545 if (aOldTree
.get
<std::string
>("action", "") == "invalidate")
1547 // Not possible that we encounter an empty rectangle here; we already handled this case above.
1548 std::istringstream
aOldRectStream(aOldTree
.get
<std::string
>("rectangle", ""));
1549 long nOldLeft
, nOldTop
, nOldWidth
, nOldHeight
;
1551 aOldRectStream
>> nOldLeft
>> nOldComma
>> nOldTop
>> nOldComma
>> nOldWidth
1552 >> nOldComma
>> nOldHeight
;
1553 const tools::Rectangle aOldRect
= tools::Rectangle(
1554 nOldLeft
, nOldTop
, nOldLeft
+ nOldWidth
, nOldTop
+ nOldHeight
);
1556 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1558 if (aNewRect
== aOldRect
)
1560 SAL_INFO("lok.dialog", "Duplicate rect [" << aNewRect
.toString()
1561 << "]. Skipping new.");
1562 // We have a rectangle in the queue already that makes the current Callback useless.
1563 currentIsRedundant
= true;
1566 // new one engulfs the old one?
1567 else if (aNewRect
.IsInside(aOldRect
))
1569 SAL_INFO("lok.dialog",
1570 "New rect [" << aNewRect
.toString() << "] engulfs old ["
1571 << aOldRect
.toString() << "]. Replacing old.");
1574 // old one engulfs the new one?
1575 else if (aOldRect
.IsInside(aNewRect
))
1577 SAL_INFO("lok.dialog",
1578 "Old rect [" << aOldRect
.toString() << "] engulfs new ["
1579 << aNewRect
.toString() << "]. Skipping new.");
1580 // We have a rectangle in the queue already that makes the current Callback useless.
1581 currentIsRedundant
= true;
1586 // Overlapping rects.
1587 const tools::Rectangle aPreMergeRect
= aNewRect
;
1588 aNewRect
.Union(aOldRect
);
1589 SAL_INFO("lok.dialog", "Merging rects ["
1590 << aPreMergeRect
.toString() << "] & ["
1591 << aOldRect
.toString() << "] = ["
1592 << aNewRect
.toString()
1593 << "]. Replacing old.");
1603 // Do not enqueue if redundant.
1604 if (currentIsRedundant
)
1607 aTree
.put("rectangle", aNewRect
.toString().getStr());
1608 aCallbackData
.setJson(aTree
);
1609 assert(aCallbackData
.validate() && "Validation after setJson failed!");
1612 else if (aAction
== "created")
1614 // Remove all previous actions on same dialog, if we are creating it anew.
1615 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1616 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1618 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1619 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1625 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
1628 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
1633 auto xClip
= forceSetClipboardForCurrentView(m_pDocument
);
1635 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(xClip
.get());
1636 pWindow
->SetClipboard(xClipboard
);
1639 else if (aAction
== "size_changed")
1641 // A size change is practically re-creation of the window.
1642 // But at a minimum it's a full invalidation.
1643 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1644 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1646 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1647 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1649 const std::string aOldAction
= aOldTree
.get
<std::string
>("action", "");
1650 if (aOldAction
== "invalidate")
1662 void CallbackFlushHandler::Invoke()
1664 comphelper::ProfileZone
aZone("CallbackFlushHander::Invoke");
1666 if (m_pCallback
&& !m_bEventLatch
)
1668 std::scoped_lock
<std::mutex
> lock(m_mutex
);
1670 SAL_INFO("lok", "Flushing " << m_queue
.size() << " elements.");
1671 for (const auto& rCallbackData
: m_queue
)
1673 const int type
= rCallbackData
.Type
;
1674 const auto& payload
= rCallbackData
.PayloadString
;
1675 const int viewId
= lcl_isViewCallbackType(type
) ? lcl_getViewId(rCallbackData
) : -1;
1679 const auto stateIt
= m_states
.find(type
);
1680 if (stateIt
!= m_states
.end())
1682 // If the state didn't change, it's safe to ignore.
1683 if (stateIt
->second
== payload
)
1685 SAL_INFO("lok", "Skipping duplicate [" << type
<< "]: [" << payload
<< "].");
1689 stateIt
->second
= payload
;
1694 const auto statesIt
= m_viewStates
.find(viewId
);
1695 if (statesIt
!= m_viewStates
.end())
1697 auto& states
= statesIt
->second
;
1698 const auto stateIt
= states
.find(type
);
1699 if (stateIt
!= states
.end())
1701 // If the state didn't change, it's safe to ignore.
1702 if (stateIt
->second
== payload
)
1704 SAL_INFO("lok", "Skipping view duplicate [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
1708 SAL_INFO("lok", "Replacing an element in view states [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
1709 stateIt
->second
= payload
;
1713 SAL_INFO("lok", "Inserted a new element in view states: [" << type
<< ',' << viewId
<< "]: [" << payload
<< "]");
1714 states
.emplace(type
, payload
);
1720 m_pCallback(type
, payload
.c_str(), m_pData
);
1727 bool CallbackFlushHandler::removeAll(const std::function
<bool (const CallbackFlushHandler::queue_type::value_type
&)>& rTestFunc
)
1729 auto newEnd
= std::remove_if(m_queue
.begin(), m_queue
.end(), rTestFunc
);
1730 if (newEnd
!= m_queue
.end())
1732 m_queue
.erase(newEnd
, m_queue
.end());
1739 void CallbackFlushHandler::addViewStates(int viewId
)
1741 const auto& result
= m_viewStates
.emplace(viewId
, decltype(m_viewStates
)::mapped_type());
1742 if (!result
.second
&& result
.first
!= m_viewStates
.end())
1744 result
.first
->second
.clear();
1748 void CallbackFlushHandler::removeViewStates(int viewId
)
1750 m_viewStates
.erase(viewId
);
1754 static void doc_destroy(LibreOfficeKitDocument
*pThis
)
1756 comphelper::ProfileZone
aZone("doc_destroy");
1758 SolarMutexGuard aGuard
;
1760 LOKClipboardFactory::releaseClipboardForView(-1);
1762 LibLODocument_Impl
*pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1766 static void lo_destroy (LibreOfficeKit
* pThis
);
1767 static int lo_initialize (LibreOfficeKit
* pThis
, const char* pInstallPath
, const char* pUserProfilePath
);
1768 static LibreOfficeKitDocument
* lo_documentLoad (LibreOfficeKit
* pThis
, const char* pURL
);
1769 static char * lo_getError (LibreOfficeKit
* pThis
);
1770 static void lo_freeError (char* pFree
);
1771 static LibreOfficeKitDocument
* lo_documentLoadWithOptions (LibreOfficeKit
* pThis
,
1773 const char* pOptions
);
1774 static void lo_registerCallback (LibreOfficeKit
* pThis
,
1775 LibreOfficeKitCallback pCallback
,
1777 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
);
1778 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long features
);
1779 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
1781 const char* pPassword
);
1782 static char* lo_getVersionInfo(LibreOfficeKit
* pThis
);
1783 static int lo_runMacro (LibreOfficeKit
* pThis
, const char* pURL
);
1785 static bool lo_signDocument(LibreOfficeKit
* pThis
,
1787 const unsigned char* pCertificateBinary
,
1788 const int nCertificateBinarySize
,
1789 const unsigned char* pPrivateKeyBinary
,
1790 const int nPrivateKeyBinarySize
);
1792 static void lo_runLoop(LibreOfficeKit
* pThis
,
1793 LibreOfficeKitPollCallback pPollCallback
,
1794 LibreOfficeKitWakeCallback pWakeCallback
,
1797 LibLibreOffice_Impl::LibLibreOffice_Impl()
1798 : m_pOfficeClass( gOfficeClass
.lock() )
1800 , mpCallback(nullptr)
1801 , mpCallbackData(nullptr)
1802 , mOptionalFeatures(0)
1804 if(!m_pOfficeClass
) {
1805 m_pOfficeClass
.reset(new LibreOfficeKitClass
);
1806 m_pOfficeClass
->nSize
= sizeof(LibreOfficeKitClass
);
1808 m_pOfficeClass
->destroy
= lo_destroy
;
1809 m_pOfficeClass
->documentLoad
= lo_documentLoad
;
1810 m_pOfficeClass
->getError
= lo_getError
;
1811 m_pOfficeClass
->freeError
= lo_freeError
;
1812 m_pOfficeClass
->documentLoadWithOptions
= lo_documentLoadWithOptions
;
1813 m_pOfficeClass
->registerCallback
= lo_registerCallback
;
1814 m_pOfficeClass
->getFilterTypes
= lo_getFilterTypes
;
1815 m_pOfficeClass
->setOptionalFeatures
= lo_setOptionalFeatures
;
1816 m_pOfficeClass
->setDocumentPassword
= lo_setDocumentPassword
;
1817 m_pOfficeClass
->getVersionInfo
= lo_getVersionInfo
;
1818 m_pOfficeClass
->runMacro
= lo_runMacro
;
1819 m_pOfficeClass
->signDocument
= lo_signDocument
;
1820 m_pOfficeClass
->runLoop
= lo_runLoop
;
1822 gOfficeClass
= m_pOfficeClass
;
1825 pClass
= m_pOfficeClass
.get();
1828 LibLibreOffice_Impl::~LibLibreOffice_Impl()
1836 void paintTileToCGContext(ITiledRenderable
* pDocument
,
1837 void* rCGContext
, const Size nCanvasSize
,
1838 const int nTilePosX
, const int nTilePosY
,
1839 const int nTileWidth
, const int nTileHeight
)
1841 SystemGraphicsData aData
;
1842 aData
.rCGContext
= reinterpret_cast<CGContextRef
>(rCGContext
);
1844 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::DEFAULT
);
1845 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
1846 pDevice
->SetOutputSizePixel(nCanvasSize
);
1847 pDocument
->paintTile(*pDevice
, nCanvasSize
.Width(), nCanvasSize
.Height(),
1848 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
1851 void paintTileIOS(LibreOfficeKitDocument
* pThis
,
1852 unsigned char* pBuffer
,
1853 const int nCanvasWidth
, const int nCanvasHeight
, const double fDPIScale
,
1854 const int nTilePosX
, const int nTilePosY
,
1855 const int nTileWidth
, const int nTileHeight
)
1857 CGContextRef pCGContext
= CGBitmapContextCreate(pBuffer
, nCanvasWidth
, nCanvasHeight
, 8,
1858 nCanvasWidth
* 4, CGColorSpaceCreateDeviceRGB(),
1859 kCGImageAlphaPremultipliedFirst
| kCGImageByteOrder32Little
);
1861 CGContextTranslateCTM(pCGContext
, 0, nCanvasHeight
);
1862 CGContextScaleCTM(pCGContext
, fDPIScale
, -fDPIScale
);
1864 doc_paintTileToCGContext(pThis
, (void*) pCGContext
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
1866 CGContextRelease(pCGContext
);
1870 } // anonymous namespace
1872 // Wonder global state ...
1873 static uno::Reference
<css::uno::XComponentContext
> xContext
;
1874 static uno::Reference
<css::lang::XMultiServiceFactory
> xSFactory
;
1875 static uno::Reference
<css::lang::XMultiComponentFactory
> xFactory
;
1877 static LibreOfficeKitDocument
* lo_documentLoad(LibreOfficeKit
* pThis
, const char* pURL
)
1879 return lo_documentLoadWithOptions(pThis
, pURL
, nullptr);
1882 static LibreOfficeKitDocument
* lo_documentLoadWithOptions(LibreOfficeKit
* pThis
, const char* pURL
, const char* pOptions
)
1884 comphelper::ProfileZone
aZone("lo_documentLoadWithOptions");
1886 SolarMutexGuard aGuard
;
1888 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
1889 pLib
->maLastExceptionMsg
.clear();
1891 OUString
aURL(getAbsoluteURL(pURL
));
1894 pLib
->maLastExceptionMsg
= "Filename to load was not provided.";
1895 SAL_INFO("lok", "URL for load is empty");
1899 pLib
->maLastExceptionMsg
.clear();
1903 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
1904 SAL_INFO("lok", "ComponentContext is not available");
1908 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
1910 if (!xComponentLoader
.is())
1912 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
1913 SAL_INFO("lok", "ComponentLoader is not available");
1919 // 'Language=...' is an option that LOK consumes by itself, and does
1920 // not pass it as a parameter to the filter
1921 OUString aOptions
= getUString(pOptions
);
1922 const OUString aLanguage
= extractParameter(aOptions
, "Language");
1924 if (!aLanguage
.isEmpty())
1926 // use with care - it sets it for the entire core, not just the
1928 SvtSysLocaleOptions aSysLocaleOptions
;
1929 aSysLocaleOptions
.SetLocaleConfigString(aLanguage
);
1930 aSysLocaleOptions
.SetUILocaleConfigString(aLanguage
);
1931 // Set the LOK language tag, used for dialog tunneling.
1932 comphelper::LibreOfficeKit::setLanguageTag(aSysLocaleOptions
.GetLanguageTag());
1935 uno::Sequence
<css::beans::PropertyValue
> aFilterOptions(2);
1936 aFilterOptions
[0] = css::beans::PropertyValue( "FilterOptions",
1938 uno::makeAny(aOptions
),
1939 beans::PropertyState_DIRECT_VALUE
);
1941 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
1942 new LOKInteractionHandler("load", pLib
));
1943 auto const pair(pLib
->mInteractionMap
.insert(std::make_pair(aURL
.toUtf8(), pInteraction
)));
1944 comphelper::ScopeGuard
const g([&] () {
1947 pLib
->mInteractionMap
.erase(aURL
.toUtf8());
1950 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
1951 aFilterOptions
[1].Name
= "InteractionHandler";
1952 aFilterOptions
[1].Value
<<= xInteraction
;
1955 sal_Int16 nMacroExecMode = document::MacroExecMode::USE_CONFIG;
1956 aFilterOptions[2].Name = "MacroExecutionMode";
1957 aFilterOptions[2].Value <<= nMacroExecMode;
1959 sal_Int16 nUpdateDoc = document::UpdateDocMode::ACCORDING_TO_CONFIG;
1960 aFilterOptions[3].Name = "UpdateDocMode";
1961 aFilterOptions[3].Value <<= nUpdateDoc;
1964 uno::Reference
<lang::XComponent
> xComponent
= xComponentLoader
->loadComponentFromURL(
1968 assert(!xComponent
.is() || pair
.second
); // concurrent loading of same URL ought to fail
1970 if (!xComponent
.is())
1972 pLib
->maLastExceptionMsg
= "loadComponentFromURL returned an empty reference";
1973 SAL_INFO("lok", "Document can't be loaded - " << pLib
->maLastExceptionMsg
);
1977 LibLODocument_Impl
* pDocument
= new LibLODocument_Impl(xComponent
);
1978 if (pLib
->mpCallback
)
1980 int nState
= doc_getSignatureState(pDocument
);
1981 pLib
->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS
, OString::number(nState
).getStr(), pLib
->mpCallbackData
);
1985 catch (const uno::Exception
& exception
)
1987 pLib
->maLastExceptionMsg
= exception
.Message
;
1988 TOOLS_INFO_EXCEPTION("lok", "Document can't be loaded");
1994 static int lo_runMacro(LibreOfficeKit
* pThis
, const char *pURL
)
1996 comphelper::ProfileZone
aZone("lo_runMacro");
1998 SolarMutexGuard aGuard
;
2000 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2001 pLib
->maLastExceptionMsg
.clear();
2003 OUString
sURL( pURL
, strlen(pURL
), RTL_TEXTENCODING_UTF8
);
2006 pLib
->maLastExceptionMsg
= "Macro to run was not provided.";
2007 SAL_INFO("lok", "Macro URL is empty");
2011 if (!sURL
.startsWith("macro://"))
2013 pLib
->maLastExceptionMsg
= "This doesn't look like macro URL";
2014 SAL_INFO("lok", "Macro URL is invalid");
2018 pLib
->maLastExceptionMsg
.clear();
2022 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
2023 SAL_INFO("lok", "ComponentContext is not available");
2028 aURL
.Complete
= sURL
;
2030 uno::Reference
< util::XURLTransformer
> xParser( util::URLTransformer::create( xContext
) );
2033 xParser
->parseStrict( aURL
);
2035 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
2037 if (!xComponentLoader
.is())
2039 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
2040 SAL_INFO("lok", "ComponentLoader is not available");
2044 xFactory
= xContext
->getServiceManager();
2048 uno::Reference
<frame::XDispatchProvider
> xDP
;
2049 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
2050 xDP
.set( xSFactory
->createInstance("com.sun.star.comp.sfx2.SfxMacroLoader"), uno::UNO_QUERY
);
2051 uno::Reference
<frame::XDispatch
> xD
= xDP
->queryDispatch( aURL
, OUString(), 0);
2055 pLib
->maLastExceptionMsg
= "Macro loader is not available";
2056 SAL_INFO("lok", "Macro loader is not available");
2060 uno::Reference
< frame::XSynchronousDispatch
> xSyncDisp( xD
, uno::UNO_QUERY_THROW
);
2061 uno::Sequence
<css::beans::PropertyValue
> aEmpty
;
2062 css::beans::PropertyValue aErr
;
2063 uno::Any aRet
= xSyncDisp
->dispatchWithReturnValue( aURL
, aEmpty
);
2066 if (aErr
.Name
== "ErrorCode")
2068 sal_uInt32 nErrCode
= 0; // ERRCODE_NONE
2069 aErr
.Value
>>= nErrCode
;
2071 pLib
->maLastExceptionMsg
= "An error occurred running macro (error code: " + OUString::number( nErrCode
) + ")";
2072 SAL_INFO("lok", "Macro execution terminated with error code " << nErrCode
);
2083 static bool lo_signDocument(LibreOfficeKit
* /*pThis*/,
2085 const unsigned char* pCertificateBinary
,
2086 const int nCertificateBinarySize
,
2087 const unsigned char* pPrivateKeyBinary
,
2088 const int nPrivateKeyBinarySize
)
2090 comphelper::ProfileZone
aZone("lo_signDocument");
2092 OUString
aURL(getAbsoluteURL(pURL
));
2099 uno::Sequence
<sal_Int8
> aCertificateSequence
;
2101 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
2102 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
2103 if (!aCertificateBase64String
.empty())
2105 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
2106 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
2110 aCertificateSequence
.realloc(nCertificateBinarySize
);
2111 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
2114 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
2115 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeyBinarySize
);
2116 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
2117 if (!aPrivateKeyBase64String
.empty())
2119 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
2120 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
2124 aPrivateKeySequence
.realloc(nPrivateKeyBinarySize
);
2125 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeyBinarySize
, aPrivateKeySequence
.begin());
2128 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
2129 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
2130 if (!xSecurityContext
.is())
2133 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
2134 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
2136 if (!xCertificateCreator
.is())
2139 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
2141 if (!xCertificate
.is())
2144 sfx2::DocumentSigner
aDocumentSigner(aURL
);
2145 if (!aDocumentSigner
.signDocument(xCertificate
))
2151 static void lo_registerCallback (LibreOfficeKit
* pThis
,
2152 LibreOfficeKitCallback pCallback
,
2155 SolarMutexGuard aGuard
;
2157 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2158 pLib
->maLastExceptionMsg
.clear();
2160 pLib
->mpCallback
= pCallback
;
2161 pLib
->mpCallbackData
= pData
;
2164 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* sUrl
, const char* pFormat
, const char* pFilterOptions
)
2166 comphelper::ProfileZone
aZone("doc_saveAs");
2168 SolarMutexGuard aGuard
;
2169 SetLastExceptionMsg();
2171 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2173 OUString sFormat
= getUString(pFormat
);
2174 OUString
aURL(getAbsoluteURL(sUrl
));
2177 SetLastExceptionMsg("Filename to save to was not provided.");
2178 SAL_INFO("lok", "URL for save is empty");
2184 const ExtensionMap
* pMap
;
2186 switch (doc_getDocumentType(pThis
))
2188 case LOK_DOCTYPE_SPREADSHEET
:
2189 pMap
= aCalcExtensionMap
;
2191 case LOK_DOCTYPE_PRESENTATION
:
2192 pMap
= aImpressExtensionMap
;
2194 case LOK_DOCTYPE_DRAWING
:
2195 pMap
= aDrawExtensionMap
;
2197 case LOK_DOCTYPE_TEXT
:
2198 pMap
= aWriterExtensionMap
;
2200 case LOK_DOCTYPE_OTHER
:
2202 SAL_INFO("lok", "Can't save document - unsupported document type.");
2206 if (pFormat
== nullptr)
2208 // sniff from the extension
2209 sal_Int32 idx
= aURL
.lastIndexOf(".");
2212 sFormat
= aURL
.copy( idx
+ 1 );
2216 SetLastExceptionMsg("input filename without a suffix");
2221 OUString aFilterName
;
2222 for (sal_Int32 i
= 0; pMap
[i
].extn
; ++i
)
2224 if (sFormat
.equalsIgnoreAsciiCaseAscii(pMap
[i
].extn
))
2226 aFilterName
= getUString(pMap
[i
].filterName
);
2230 if (aFilterName
.isEmpty())
2232 SetLastExceptionMsg("no output filter found for provided suffix");
2236 OUString aFilterOptions
= getUString(pFilterOptions
);
2238 // Check if watermark for pdf is passed by filteroptions...
2239 // It is not a real filter option so it must be filtered out.
2240 OUString watermarkText
, sFullSheetPreview
;
2242 if ((aIndex
= aFilterOptions
.indexOf(",Watermark=")) >= 0)
2244 int bIndex
= aFilterOptions
.indexOf("WATERMARKEND");
2245 watermarkText
= aFilterOptions
.copy(aIndex
+11, bIndex
-(aIndex
+11));
2247 OUString temp
= aFilterOptions
.copy(0, aIndex
);
2248 aFilterOptions
= temp
+ aFilterOptions
.copy(bIndex
+12);
2252 if ((aIndex
= aFilterOptions
.indexOf(",FullSheetPreview=")) >= 0)
2254 int bIndex
= aFilterOptions
.indexOf("FULLSHEETPREVEND");
2255 sFullSheetPreview
= aFilterOptions
.copy(aIndex
+18, bIndex
-(aIndex
+18));
2257 OUString temp
= aFilterOptions
.copy(0, aIndex
);
2258 aFilterOptions
= temp
+ aFilterOptions
.copy(bIndex
+16);
2261 bool bFullSheetPreview
= sFullSheetPreview
== "true";
2263 // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
2264 // gets a new name). When this is not provided, the meaning of
2265 // saveAs() is more like save-a-copy, which allows saving to any
2266 // random format like PDF or PNG.
2267 // It is not a real filter option, so we have to filter it out.
2268 const uno::Sequence
<OUString
> aOptionSeq
= comphelper::string::convertCommaSeparated(aFilterOptions
);
2269 std::vector
<OUString
> aFilteredOptionVec
;
2270 bool bTakeOwnership
= false;
2271 MediaDescriptor aSaveMediaDescriptor
;
2272 for (const auto& rOption
: aOptionSeq
)
2274 if (rOption
== "TakeOwnership")
2275 bTakeOwnership
= true;
2276 else if (rOption
== "NoFileSync")
2277 aSaveMediaDescriptor
["NoFileSync"] <<= true;
2279 aFilteredOptionVec
.push_back(rOption
);
2282 aSaveMediaDescriptor
["Overwrite"] <<= true;
2283 aSaveMediaDescriptor
["FilterName"] <<= aFilterName
;
2285 auto aFilteredOptionSeq
= comphelper::containerToSequence
<OUString
>(aFilteredOptionVec
);
2286 aFilterOptions
= comphelper::string::convertCommaSeparated(aFilteredOptionSeq
);
2287 aSaveMediaDescriptor
[MediaDescriptor::PROP_FILTEROPTIONS()] <<= aFilterOptions
;
2289 if(!watermarkText
.isEmpty() || bFullSheetPreview
)
2291 uno::Sequence
< beans::PropertyValue
> aFilterData( static_cast<int>(bFullSheetPreview
) + static_cast<int>(!watermarkText
.isEmpty()) );
2293 if (!watermarkText
.isEmpty())
2295 aFilterData
[ 0 ].Name
= "TiledWatermark";
2296 aFilterData
[ 0 ].Value
<<= watermarkText
;
2299 if (bFullSheetPreview
)
2301 int nOptIndex
= static_cast<int>(!watermarkText
.isEmpty());
2303 aFilterData
[ nOptIndex
].Name
= "SinglePageSheets";
2304 aFilterData
[ nOptIndex
].Value
<<= true;
2307 aSaveMediaDescriptor
["FilterData"] <<= aFilterData
;
2310 // add interaction handler too
2313 // gImpl does not have to exist when running from a unit test
2314 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
2315 new LOKInteractionHandler("saveas", gImpl
, pDocument
));
2316 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
2318 aSaveMediaDescriptor
[MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteraction
;
2321 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2324 xStorable
->storeAsURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
2326 xStorable
->storeToURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
2330 catch (const uno::Exception
& exception
)
2332 SetLastExceptionMsg("exception: " + exception
.Message
);
2337 static void doc_iniUnoCommands ()
2339 SolarMutexGuard aGuard
;
2340 SetLastExceptionMsg();
2342 OUString sUnoCommands
[] =
2344 OUString(".uno:AlignLeft"),
2345 OUString(".uno:AlignHorizontalCenter"),
2346 OUString(".uno:AlignRight"),
2347 OUString(".uno:BackColor"),
2348 OUString(".uno:BackgroundColor"),
2349 OUString(".uno:TableCellBackgroundColor"),
2350 OUString(".uno:Bold"),
2351 OUString(".uno:CenterPara"),
2352 OUString(".uno:CharBackColor"),
2353 OUString(".uno:CharBackgroundExt"),
2354 OUString(".uno:CharFontName"),
2355 OUString(".uno:Color"),
2356 OUString(".uno:ControlCodes"),
2357 OUString(".uno:DecrementIndent"),
2358 OUString(".uno:DefaultBullet"),
2359 OUString(".uno:DefaultNumbering"),
2360 OUString(".uno:FontColor"),
2361 OUString(".uno:FontHeight"),
2362 OUString(".uno:IncrementIndent"),
2363 OUString(".uno:Italic"),
2364 OUString(".uno:JustifyPara"),
2365 OUString(".uno:OutlineFont"),
2366 OUString(".uno:LeftPara"),
2367 OUString(".uno:LanguageStatus"),
2368 OUString(".uno:RightPara"),
2369 OUString(".uno:Shadowed"),
2370 OUString(".uno:SubScript"),
2371 OUString(".uno:SuperScript"),
2372 OUString(".uno:Strikeout"),
2373 OUString(".uno:StyleApply"),
2374 OUString(".uno:Underline"),
2375 OUString(".uno:ModifiedStatus"),
2376 OUString(".uno:Undo"),
2377 OUString(".uno:Redo"),
2378 OUString(".uno:InsertPage"),
2379 OUString(".uno:DeletePage"),
2380 OUString(".uno:DuplicatePage"),
2381 OUString(".uno:Cut"),
2382 OUString(".uno:Copy"),
2383 OUString(".uno:Paste"),
2384 OUString(".uno:SelectAll"),
2385 OUString(".uno:InsertAnnotation"),
2386 OUString(".uno:DeleteAnnotation"),
2387 OUString(".uno:ReplyComment"),
2388 OUString(".uno:ResolveComment"),
2389 OUString(".uno:InsertRowsBefore"),
2390 OUString(".uno:InsertRowsAfter"),
2391 OUString(".uno:InsertColumnsBefore"),
2392 OUString(".uno:InsertColumnsAfter"),
2393 OUString(".uno:DeleteRows"),
2394 OUString(".uno:DeleteColumns"),
2395 OUString(".uno:DeleteTable"),
2396 OUString(".uno:SelectTable"),
2397 OUString(".uno:EntireRow"),
2398 OUString(".uno:EntireColumn"),
2399 OUString(".uno:EntireCell"),
2400 OUString(".uno:AssignLayout"),
2401 OUString(".uno:StatusDocPos"),
2402 OUString(".uno:RowColSelCount"),
2403 OUString(".uno:StatusPageStyle"),
2404 OUString(".uno:InsertMode"),
2405 OUString(".uno:SpellOnline"),
2406 OUString(".uno:StatusSelectionMode"),
2407 OUString(".uno:StateTableCell"),
2408 OUString(".uno:StatusBarFunc"),
2409 OUString(".uno:StatePageNumber"),
2410 OUString(".uno:StateWordCount"),
2411 OUString(".uno:SelectionMode"),
2412 OUString(".uno:PageStatus"),
2413 OUString(".uno:LayoutStatus"),
2414 OUString(".uno:Context"),
2415 OUString(".uno:WrapText"),
2416 OUString(".uno:ToggleMergeCells"),
2417 OUString(".uno:NumberFormatCurrency"),
2418 OUString(".uno:NumberFormatPercent"),
2419 OUString(".uno:NumberFormatDate"),
2420 OUString(".uno:SortAscending"),
2421 OUString(".uno:SortDescending"),
2422 OUString(".uno:TrackChanges"),
2423 OUString(".uno:ShowTrackedChanges"),
2424 OUString(".uno:NextTrackedChange"),
2425 OUString(".uno:PreviousTrackedChange"),
2426 OUString(".uno:AcceptAllTrackedChanges"),
2427 OUString(".uno:RejectAllTrackedChanges"),
2428 OUString(".uno:TableDialog"),
2429 OUString(".uno:FormatCellDialog"),
2430 OUString(".uno:FontDialog"),
2431 OUString(".uno:ParagraphDialog"),
2432 OUString(".uno:OutlineBullet"),
2433 OUString(".uno:InsertIndexesEntry"),
2434 OUString(".uno:DocumentRepair"),
2435 OUString(".uno:TransformDialog"),
2436 OUString(".uno:InsertPageHeader"),
2437 OUString(".uno:InsertPageFooter"),
2438 OUString(".uno:OnlineAutoFormat"),
2439 OUString(".uno:InsertSymbol"),
2440 OUString(".uno:EditRegion"),
2441 OUString(".uno:ThesaurusDialog")
2444 util::URL aCommandURL
;
2445 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2446 SfxViewFrame
* pViewFrame
= pViewShell
? pViewShell
->GetViewFrame(): nullptr;
2448 // check if Frame-Controller were created.
2451 SAL_WARN("lok", "iniUnoCommands: No Frame-Controller created.");
2456 xContext
= comphelper::getProcessComponentContext();
2459 SAL_WARN("lok", "iniUnoCommands: Component context is not available");
2463 SfxSlotPool
& rSlotPool
= SfxSlotPool::GetSlotPool(pViewFrame
);
2464 uno::Reference
<util::XURLTransformer
> xParser(util::URLTransformer::create(xContext
));
2466 for (const auto & sUnoCommand
: sUnoCommands
)
2468 aCommandURL
.Complete
= sUnoCommand
;
2469 xParser
->parseStrict(aCommandURL
);
2471 // when null, this command is not supported by the given component
2472 // (like eg. Calc does not have ".uno:DefaultBullet" etc.)
2473 if (const SfxSlot
* pSlot
= rSlotPool
.GetUnoSlot(aCommandURL
.Path
))
2475 // Initialize slot to dispatch .uno: Command.
2476 pViewFrame
->GetBindings().GetDispatch(pSlot
, aCommandURL
, false);
2481 static int doc_getDocumentType (LibreOfficeKitDocument
* pThis
)
2483 comphelper::ProfileZone
aZone("doc_getDocumentType");
2485 SolarMutexGuard aGuard
;
2486 SetLastExceptionMsg();
2488 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2492 uno::Reference
<lang::XServiceInfo
> xDocument(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2494 if (xDocument
->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
2496 return LOK_DOCTYPE_SPREADSHEET
;
2498 else if (xDocument
->supportsService("com.sun.star.presentation.PresentationDocument"))
2500 return LOK_DOCTYPE_PRESENTATION
;
2502 else if (xDocument
->supportsService("com.sun.star.drawing.DrawingDocument"))
2504 return LOK_DOCTYPE_DRAWING
;
2506 else if (xDocument
->supportsService("com.sun.star.text.TextDocument") || xDocument
->supportsService("com.sun.star.text.WebDocument"))
2508 return LOK_DOCTYPE_TEXT
;
2512 SetLastExceptionMsg("unknown document type");
2515 catch (const uno::Exception
& exception
)
2517 SetLastExceptionMsg("exception: " + exception
.Message
);
2519 return LOK_DOCTYPE_OTHER
;
2522 static int doc_getParts (LibreOfficeKitDocument
* pThis
)
2524 comphelper::ProfileZone
aZone("doc_getParts");
2526 SolarMutexGuard aGuard
;
2528 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2531 SetLastExceptionMsg("Document doesn't support tiled rendering");
2535 return pDoc
->getParts();
2538 static int doc_getPart (LibreOfficeKitDocument
* pThis
)
2540 comphelper::ProfileZone
aZone("doc_getPart");
2542 SolarMutexGuard aGuard
;
2543 SetLastExceptionMsg();
2545 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2548 SetLastExceptionMsg("Document doesn't support tiled rendering");
2552 return pDoc
->getPart();
2555 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
)
2557 comphelper::ProfileZone
aZone("doc_setPart");
2559 SolarMutexGuard aGuard
;
2560 SetLastExceptionMsg();
2562 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2565 SetLastExceptionMsg("Document doesn't support tiled rendering");
2569 pDoc
->setPart( nPart
);
2572 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
)
2574 comphelper::ProfileZone
aZone("doc_getPartInfo");
2576 SolarMutexGuard aGuard
;
2577 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2580 SetLastExceptionMsg("Document doesn't support tiled rendering");
2584 return convertOUString(pDoc
->getPartInfo(nPart
));
2587 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
)
2589 SolarMutexGuard aGuard
;
2591 gImpl
->maLastExceptionMsg
.clear();
2593 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2596 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2600 pDoc
->selectPart( nPart
, nSelect
);
2603 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
)
2605 SolarMutexGuard aGuard
;
2607 gImpl
->maLastExceptionMsg
.clear();
2609 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2612 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2616 pDoc
->moveSelectedParts(nPosition
, bDuplicate
);
2619 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
)
2621 comphelper::ProfileZone
aZone("doc_getPartPageRectangles");
2623 SolarMutexGuard aGuard
;
2624 SetLastExceptionMsg();
2626 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2629 SetLastExceptionMsg("Document doesn't support tiled rendering");
2633 return convertOUString(pDoc
->getPartPageRectangles());
2636 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
)
2638 comphelper::ProfileZone
aZone("doc_getPartName");
2640 SolarMutexGuard aGuard
;
2641 SetLastExceptionMsg();
2643 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2646 SetLastExceptionMsg("Document doesn't support tiled rendering");
2650 return convertOUString(pDoc
->getPartName(nPart
));
2653 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
)
2655 comphelper::ProfileZone
aZone("doc_getPartHash");
2657 SolarMutexGuard aGuard
;
2658 SetLastExceptionMsg();
2660 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2663 SetLastExceptionMsg("Document doesn't support tiled rendering");
2667 return convertOUString(pDoc
->getPartHash(nPart
));
2670 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
,
2673 comphelper::ProfileZone
aZone("doc_setPartMode");
2675 SolarMutexGuard aGuard
;
2676 SetLastExceptionMsg();
2678 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2681 SetLastExceptionMsg("Document doesn't support tiled rendering");
2686 int nCurrentPart
= pDoc
->getPart();
2688 pDoc
->setPartMode(nPartMode
);
2690 // We need to make sure the internal state is updated, just changing the mode
2691 // might not update the relevant shells (i.e. impress will keep rendering the
2692 // previous mode unless we do this).
2693 // TODO: we might want to do this within the relevant components rather than
2694 // here, but that's also dependent on how we implement embedded object
2695 // rendering I guess?
2696 // TODO: we could be clever and e.g. set to 0 when we change to/from
2697 // embedded object mode, and not when changing between slide/notes/combined
2699 if ( nCurrentPart
< pDoc
->getParts() )
2701 pDoc
->setPart( nCurrentPart
);
2709 #if defined(ANDROID)
2710 /// For the distinction if the LOK is used for the 'old' (JNI-based) or the
2711 /// 'new' (loolwsd-based) app. Default to the 'new', ie. not used from JNI as
2712 /// implemented in sal/android/libreofficekit-jni.c.
2713 bool android_lok_from_jni
= false;
2716 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
2717 unsigned char* pBuffer
,
2718 const int nCanvasWidth
, const int nCanvasHeight
,
2719 const int nTilePosX
, const int nTilePosY
,
2720 const int nTileWidth
, const int nTileHeight
)
2722 comphelper::ProfileZone
aZone("doc_paintTile");
2724 SolarMutexGuard aGuard
;
2725 SetLastExceptionMsg();
2727 SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth
<< "x" << nTileHeight
<<
2728 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
2729 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2731 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2734 SetLastExceptionMsg("Document doesn't support tiled rendering");
2738 #if defined(UNX) && !defined(MACOSX) && !defined(ENABLE_HEADLESS)
2740 // Painting of zoomed or HiDPI spreadsheets is special, we actually draw everything at 100%,
2741 // and only set cairo's (or CoreGraphic's, in the iOS case) scale factor accordingly, so that
2742 // everything is painted bigger or smaller. This is different to what Calc's internal scaling
2743 // would do - because that one is trying to fit the lines between cells to integer multiples of
2745 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
2748 double fDPIScaleX
= 1.0;
2749 paintTileIOS(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, fDPIScaleX
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2751 ScopedVclPtrInstance
< VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
2753 #if defined(ANDROID)
2754 if (!android_lok_from_jni
)
2757 // Set background to transparent by default.
2758 // [Unless it is the 'old' (JNI-based) Android app - no idea why it
2759 // needs avoiding this.]
2760 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
2763 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
2764 Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(),
2767 pDoc
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
,
2768 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2770 static bool bDebug
= getenv("LOK_DEBUG_TILES") != nullptr;
2773 // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
2774 tools::Rectangle
aRect(0, 0, 5, 5);
2775 aRect
= pDevice
->PixelToLogic(aRect
);
2776 pDevice
->Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
2777 pDevice
->SetFillColor(COL_LIGHTRED
);
2778 pDevice
->SetLineColor();
2779 pDevice
->DrawRect(aRect
);
2791 // This function is separate only to be used by LibreOfficeLight. If that app can be retired, this
2792 // function's code can be inlined.
2793 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
2795 const int nCanvasWidth
, const int nCanvasHeight
,
2796 const int nTilePosX
, const int nTilePosY
,
2797 const int nTileWidth
, const int nTileHeight
)
2799 SolarMutexGuard aGuard
;
2800 SetLastExceptionMsg();
2802 SAL_INFO( "lok.tiledrendering", "paintTileToCGContext: painting [" << nTileWidth
<< "x" << nTileHeight
<<
2803 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
2804 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2806 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2809 SetLastExceptionMsg("Document doesn't support tiled rendering");
2813 Size
aCanvasSize(nCanvasWidth
, nCanvasHeight
);
2814 paintTileToCGContext(pDoc
, rCGContext
, aCanvasSize
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2819 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
2820 unsigned char* pBuffer
,
2822 const int nCanvasWidth
, const int nCanvasHeight
,
2823 const int nTilePosX
, const int nTilePosY
,
2824 const int nTileWidth
, const int nTileHeight
)
2826 comphelper::ProfileZone
aZone("doc_paintPartTile");
2828 SolarMutexGuard aGuard
;
2829 SetLastExceptionMsg();
2831 SAL_INFO( "lok.tiledrendering", "paintPartTile: painting @ " << nPart
<< " ["
2832 << nTileWidth
<< "x" << nTileHeight
<< "]@("
2833 << nTilePosX
<< ", " << nTilePosY
<< ") to ["
2834 << nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2836 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2837 int nOrigViewId
= doc_getView(pThis
);
2839 if (nOrigViewId
< 0)
2841 // tile painting always needs a SfxViewShell::Current(), but actually
2842 // it does not really matter which one - all of them should paint the
2844 int viewCount
= doc_getViewsCount(pThis
);
2848 std::vector
<int> viewIds(viewCount
);
2849 doc_getViewIds(pThis
, viewIds
.data(), viewCount
);
2851 nOrigViewId
= viewIds
[0];
2852 doc_setView(pThis
, nOrigViewId
);
2855 // Disable callbacks while we are painting.
2856 if (nOrigViewId
>= 0)
2858 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
2859 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
2860 handlerIt
->second
->disableCallbacks();
2865 // Text documents have a single coordinate system; don't change part.
2867 const bool isText
= (doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
);
2868 int nViewId
= nOrigViewId
;
2871 // Check if just switching to another view is enough, that has
2872 // less side-effects.
2873 if (nPart
!= doc_getPart(pThis
))
2875 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
2878 if (pViewShell
->getPart() == nPart
)
2880 nViewId
= static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
2881 doc_setView(pThis
, nViewId
);
2884 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
2888 nOrigPart
= doc_getPart(pThis
);
2889 if (nPart
!= nOrigPart
)
2891 doc_setPart(pThis
, nPart
);
2895 doc_paintTile(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2897 if (!isText
&& nPart
!= nOrigPart
)
2899 doc_setPart(pThis
, nOrigPart
);
2901 if (!isText
&& nViewId
!= nOrigViewId
)
2903 doc_setView(pThis
, nOrigViewId
);
2906 catch (const std::exception
&)
2908 // Nothing to do but restore the PartTilePainting flag.
2911 if (nOrigViewId
>= 0)
2913 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
2914 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
2915 handlerIt
->second
->enableCallbacks();
2919 static int doc_getTileMode(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
2921 SetLastExceptionMsg();
2922 return LOK_TILEMODE_BGRA
;
2925 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
2929 comphelper::ProfileZone
aZone("doc_getDocumentSize");
2931 SolarMutexGuard aGuard
;
2932 SetLastExceptionMsg();
2934 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2937 Size aDocumentSize
= pDoc
->getDocumentSize();
2938 *pWidth
= aDocumentSize
.Width();
2939 *pHeight
= aDocumentSize
.Height();
2943 SetLastExceptionMsg("Document doesn't support tiled rendering");
2947 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
2948 const char* pArguments
)
2950 comphelper::ProfileZone
aZone("doc_initializeForRendering");
2952 SolarMutexGuard aGuard
;
2953 SetLastExceptionMsg();
2955 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2958 doc_iniUnoCommands();
2959 pDoc
->initializeForTiledRendering(
2960 comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments
)));
2964 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
2965 LibreOfficeKitCallback pCallback
,
2968 SolarMutexGuard aGuard
;
2969 SetLastExceptionMsg();
2971 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2973 int nView
= SfxLokHelper::getView();
2977 if (pCallback
!= nullptr)
2980 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
2982 if (pair
.first
== nId
)
2985 pair
.second
->addViewStates(nView
);
2991 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
2993 if (pair
.first
== nId
)
2996 pair
.second
->removeViewStates(nView
);
3000 pDocument
->mpCallbackFlushHandlers
[nView
].reset(new CallbackFlushHandler(pThis
, pCallback
, pData
));
3002 if (pCallback
!= nullptr)
3005 for (const auto& pair
: pDocument
->mpCallbackFlushHandlers
)
3007 if (pair
.first
== nId
)
3010 pDocument
->mpCallbackFlushHandlers
[nView
]->addViewStates(pair
.first
);
3014 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
3016 pViewShell
->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback
, pDocument
->mpCallbackFlushHandlers
[nView
].get());
3020 /// Returns the JSON representation of all the comments in the document
3021 static char* getPostIts(LibreOfficeKitDocument
* pThis
)
3023 SetLastExceptionMsg();
3024 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3027 SetLastExceptionMsg("Document doesn't support tiled rendering");
3030 OUString aComments
= pDoc
->getPostIts();
3031 return strdup(aComments
.toUtf8().getStr());
3034 /// Returns the JSON representation of the positions of all the comments in the document
3035 static char* getPostItsPos(LibreOfficeKitDocument
* pThis
)
3037 SetLastExceptionMsg();
3038 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3041 SetLastExceptionMsg("Document doesn't support tiled rendering");
3044 OUString aComments
= pDoc
->getPostItsPos();
3045 return strdup(aComments
.toUtf8().getStr());
3048 static char* getRulerState(LibreOfficeKitDocument
* pThis
)
3050 SetLastExceptionMsg();
3051 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3054 SetLastExceptionMsg("Document doesn't support tiled rendering");
3057 OUString state
= pDoc
->getRulerState();
3058 return strdup(state
.toUtf8().getStr());
3061 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nCharCode
, int nKeyCode
)
3063 comphelper::ProfileZone
aZone("doc_postKeyEvent");
3065 SolarMutexGuard aGuard
;
3066 SetLastExceptionMsg();
3068 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3071 SetLastExceptionMsg("Document doesn't support tiled rendering");
3075 pDoc
->postKeyEvent(nType
, nCharCode
, nKeyCode
);
3078 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
, unsigned nWindowId
, int nType
, const char* pText
)
3080 comphelper::ProfileZone
aZone("doc_postWindowExtTextInputEvent");
3082 SolarMutexGuard aGuard
;
3083 VclPtr
<vcl::Window
> pWindow
;
3086 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3089 SetLastExceptionMsg("Document doesn't support tiled rendering");
3092 pWindow
= pDoc
->getDocWindow();
3096 pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
3101 SetLastExceptionMsg("No window found for window id: " + OUString::number(nWindowId
));
3105 SfxLokHelper::postExtTextEventAsync(pWindow
, nType
, OUString::fromUtf8(OString(pText
, strlen(pText
))));
3108 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, int nCharBefore
, int nCharAfter
)
3110 SolarMutexGuard aGuard
;
3111 VclPtr
<vcl::Window
> pWindow
;
3112 if (nLOKWindowId
== 0)
3114 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3117 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3120 pWindow
= pDoc
->getDocWindow();
3124 pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3129 gImpl
->maLastExceptionMsg
= "No window found for window id: " + OUString::number(nLOKWindowId
);
3133 // Annoyingly - backspace and delete are handled in the apps via an accelerator
3134 // which are PostMessage'd by SfxViewShell::ExecKey_Impl so to stay in the same
3135 // order we do this synchronously here, unless we're in a dialog.
3136 if (nCharBefore
> 0)
3139 if (nLOKWindowId
== 0)
3141 KeyEvent
aEvt(8, 1283);
3142 for (int i
= 0; i
< nCharBefore
; ++i
)
3143 pWindow
->KeyInput(aEvt
);
3146 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 8, 1283, nCharBefore
- 1);
3152 if (nLOKWindowId
== 0)
3154 KeyEvent
aEvt(46, 1286);
3155 for (int i
= 0; i
< nCharAfter
; ++i
)
3156 pWindow
->KeyInput(aEvt
);
3159 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 46, 1286, nCharAfter
- 1);
3163 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nCharCode
, int nKeyCode
)
3165 comphelper::ProfileZone
aZone("doc_postWindowKeyEvent");
3167 SolarMutexGuard aGuard
;
3168 SetLastExceptionMsg();
3170 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3173 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3177 KeyEvent
aEvent(nCharCode
, nKeyCode
, 0);
3181 case LOK_KEYEVENT_KEYINPUT
:
3182 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
3184 case LOK_KEYEVENT_KEYUP
:
3185 Application::PostKeyEvent(VclEventId::WindowKeyUp
, pWindow
, &aEvent
);
3193 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
)
3195 comphelper::ProfileZone
aZone("doc_renderShapeSelection");
3197 SolarMutexGuard aGuard
;
3198 SetLastExceptionMsg();
3200 LokChartHelper
aChartHelper(SfxViewShell::Current());
3202 if (aChartHelper
.GetWindow())
3207 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3209 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
3211 SvMemoryStream aOutStream
;
3212 uno::Reference
<io::XOutputStream
> xOut
= new utl::OOutputStreamWrapper(aOutStream
);
3214 utl::MediaDescriptor aMediaDescriptor
;
3215 switch (doc_getDocumentType(pThis
))
3217 case LOK_DOCTYPE_PRESENTATION
:
3218 aMediaDescriptor
["FilterName"] <<= OUString("impress_svg_Export");
3220 case LOK_DOCTYPE_TEXT
:
3221 aMediaDescriptor
["FilterName"] <<= OUString("writer_svg_Export");
3223 case LOK_DOCTYPE_SPREADSHEET
:
3224 aMediaDescriptor
["FilterName"] <<= OUString("calc_svg_Export");
3227 SAL_WARN("lok", "Failed to render shape selection: Document type is not supported");
3229 aMediaDescriptor
["SelectionOnly"] <<= true;
3230 aMediaDescriptor
["OutputStream"] <<= xOut
;
3232 xStorable
->storeToURL("private:stream", aMediaDescriptor
.getAsConstPropertyValueList());
3236 const size_t nOutputSize
= aOutStream
.GetEndOfData();
3237 *pOutput
= static_cast<char*>(malloc(nOutputSize
));
3240 std::memcpy(*pOutput
, aOutStream
.GetData(), nOutputSize
);
3245 catch (const uno::Exception
& exception
)
3247 css::uno::Any
exAny( cppu::getCaughtException() );
3248 SetLastExceptionMsg(exception
.Message
);
3249 SAL_WARN("lok", "Failed to render shape selection: " << exceptionToString(exAny
));
3255 /** Class to react on finishing of a dispatched command.
3257 This will call a LOK_COMMAND_FINISHED callback when postUnoCommand was
3258 called with the parameter requesting the notification.
3260 @see LibreOfficeKitCallbackType::LOK_CALLBACK_UNO_COMMAND_RESULT.
3262 class DispatchResultListener
: public cppu::WeakImplHelper
<css::frame::XDispatchResultListener
>
3264 OString maCommand
; ///< Command for which this is the result.
3265 std::shared_ptr
<CallbackFlushHandler
> mpCallback
; ///< Callback to call.
3268 DispatchResultListener(const char* pCommand
, std::shared_ptr
<CallbackFlushHandler
> const & pCallback
)
3269 : maCommand(pCommand
)
3270 , mpCallback(pCallback
)
3275 virtual void SAL_CALL
dispatchFinished(const css::frame::DispatchResultEvent
& rEvent
) override
3277 boost::property_tree::ptree aTree
;
3278 aTree
.put("commandName", maCommand
.getStr());
3280 if (rEvent
.State
!= frame::DispatchResultState::DONTKNOW
)
3282 bool bSuccess
= (rEvent
.State
== frame::DispatchResultState::SUCCESS
);
3283 aTree
.put("success", bSuccess
);
3286 aTree
.add_child("result", unoAnyToPropertyTree(rEvent
.Result
));
3288 std::stringstream aStream
;
3289 boost::property_tree::write_json(aStream
, aTree
);
3290 OString aPayload
= aStream
.str().c_str();
3291 mpCallback
->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
3294 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
{}
3297 static void doc_sendDialogEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nWindowId
, const char* pArguments
)
3299 SolarMutexGuard aGuard
;
3301 StringMap
aMap(jsonToStringMap(pArguments
));
3302 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
3305 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3308 else if (aMap
.find("id") != aMap
.end())
3310 const OUString
sClickAction("CLICK");
3311 const OUString
sSelectAction("SELECT");
3312 const OUString
sClearAction("CLEAR");
3313 const OUString
sTypeAction("TYPE");
3314 const OUString
sUpAction("UP");
3315 const OUString
sDownAction("DOWN");
3319 WindowUIObject
aUIObject(pWindow
);
3320 std::unique_ptr
<UIObject
> pUIWindow(aUIObject
.get_child(aMap
["id"]));
3322 bool bIsClickAction
= false;
3324 if (aMap
.find("cmd") != aMap
.end()) {
3325 if (aMap
["cmd"] == "selected")
3327 aMap
["POS"] = aMap
["data"];
3328 aMap
["TEXT"] = aMap
["data"];
3330 pUIWindow
->execute(sSelectAction
, aMap
);
3332 else if (aMap
["cmd"] == "plus")
3334 pUIWindow
->execute(sUpAction
, aMap
);
3336 else if (aMap
["cmd"] == "minus")
3338 pUIWindow
->execute(sDownAction
, aMap
);
3340 else if (aMap
["cmd"] == "set")
3342 aMap
["TEXT"] = aMap
["data"];
3344 pUIWindow
->execute(sClearAction
, aMap
);
3345 pUIWindow
->execute(sTypeAction
, aMap
);
3348 bIsClickAction
= true;
3351 bIsClickAction
= true;
3354 pUIWindow
->execute(sClickAction
, aMap
);
3359 pWindow
->GetParent()->Hide();
3360 pWindow
->GetParent()->Show();
3364 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
, const char* pCommand
, const char* pArguments
, bool bNotifyWhenFinished
)
3366 comphelper::ProfileZone
aZone("doc_postUnoCommand");
3368 SolarMutexGuard aGuard
;
3369 SetLastExceptionMsg();
3371 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
3372 OUString
aCommand(pCommand
, strlen(pCommand
), RTL_TEXTENCODING_UTF8
);
3373 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3375 std::vector
<beans::PropertyValue
> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments
));
3377 if (!vcl::lok::isUnipoll())
3379 beans::PropertyValue aSynchronMode
;
3380 aSynchronMode
.Name
= "SynchronMode";
3381 aSynchronMode
.Value
<<= false;
3382 aPropertyValuesVector
.push_back(aSynchronMode
);
3385 int nView
= SfxLokHelper::getView();
3389 // Set/unset mobile view for LOK
3390 if (gImpl
&& aCommand
== ".uno:LOKSetMobile")
3392 comphelper::LibreOfficeKit::setMobile(nView
);
3395 else if (gImpl
&& aCommand
== ".uno:LOKUnSetMobile")
3397 comphelper::LibreOfficeKit::setMobile(nView
, false);
3401 // handle potential interaction
3402 if (gImpl
&& aCommand
== ".uno:Save")
3404 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
3405 new LOKInteractionHandler("save", gImpl
, pDocument
));
3406 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
3408 beans::PropertyValue aValue
;
3409 aValue
.Name
= "InteractionHandler";
3410 aValue
.Value
<<= xInteraction
;
3411 aPropertyValuesVector
.push_back(aValue
);
3413 bool bDontSaveIfUnmodified
= false;
3414 aPropertyValuesVector
.erase(std::remove_if(aPropertyValuesVector
.begin(),
3415 aPropertyValuesVector
.end(),
3416 [&bDontSaveIfUnmodified
](const beans::PropertyValue
& aItem
){
3417 if (aItem
.Name
== "DontSaveIfUnmodified")
3419 bDontSaveIfUnmodified
= aItem
.Value
.get
<bool>();
3423 }), aPropertyValuesVector
.end());
3425 // skip saving and tell the result via UNO_COMMAND_RESULT
3426 if (bDontSaveIfUnmodified
&& !pDocSh
->IsModified())
3428 boost::property_tree::ptree aTree
;
3429 aTree
.put("commandName", pCommand
);
3430 aTree
.put("success", false);
3432 // Add the reason for not saving
3433 const uno::Any aResultValue
= uno::makeAny(OUString("unmodified"));
3434 aTree
.add_child("result", unoAnyToPropertyTree(aResultValue
));
3436 std::stringstream aStream
;
3437 boost::property_tree::write_json(aStream
, aTree
);
3438 OString aPayload
= aStream
.str().c_str();
3439 pDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
3443 else if (gImpl
&& aCommand
== ".uno:TransformDialog")
3445 bool bNeedConversion
= false;
3446 SfxViewShell
* pViewShell
= SfxViewShell::Current();
3447 LokChartHelper
aChartHelper(pViewShell
);
3449 if (aChartHelper
.GetWindow() )
3451 bNeedConversion
= true;
3453 else if (const SdrView
* pView
= pViewShell
->GetDrawView())
3455 if (OutputDevice
* pOutputDevice
= pView
->GetFirstOutputDevice())
3457 bNeedConversion
= (pOutputDevice
->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
);
3461 if (bNeedConversion
)
3464 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
3466 if (rPropValue
.Name
== "TransformPosX"
3467 || rPropValue
.Name
== "TransformPosY"
3468 || rPropValue
.Name
== "TransformWidth"
3469 || rPropValue
.Name
== "TransformHeight"
3470 || rPropValue
.Name
== "TransformRotationX"
3471 || rPropValue
.Name
== "TransformRotationY")
3473 rPropValue
.Value
>>= value
;
3474 value
= OutputDevice::LogicToLogic(value
, MapUnit::MapTwip
, MapUnit::Map100thMM
);
3475 rPropValue
.Value
<<= value
;
3480 if (aChartHelper
.GetWindow())
3482 if (aPropertyValuesVector
[0].Name
!= "Action")
3484 tools::Rectangle aChartBB
= aChartHelper
.GetChartBoundingBox();
3485 int nLeft
= OutputDevice::LogicToLogic(aChartBB
.Left(), MapUnit::MapTwip
, MapUnit::Map100thMM
);
3486 int nTop
= OutputDevice::LogicToLogic(aChartBB
.Top(), MapUnit::MapTwip
, MapUnit::Map100thMM
);
3489 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
3491 if (rPropValue
.Name
== "TransformPosX" || rPropValue
.Name
== "TransformRotationX")
3493 rPropValue
.Value
>>= value
;
3494 rPropValue
.Value
<<= value
- nLeft
;
3496 else if (rPropValue
.Name
== "TransformPosY" || rPropValue
.Name
== "TransformRotationY")
3498 rPropValue
.Value
>>= value
;
3499 rPropValue
.Value
<<= value
- nTop
;
3503 util::URL aCommandURL
;
3504 aCommandURL
.Path
= "LOKTransform";
3505 css::uno::Reference
<css::frame::XDispatch
>& aChartDispatcher
= aChartHelper
.GetXDispatcher();
3506 aChartDispatcher
->dispatch(aCommandURL
, comphelper::containerToSequence(aPropertyValuesVector
));
3511 bool bResult
= false;
3512 if (bNotifyWhenFinished
&& pDocument
->mpCallbackFlushHandlers
.count(nView
))
3514 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
),
3515 new DispatchResultListener(pCommand
, pDocument
->mpCallbackFlushHandlers
[nView
]));
3518 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
));
3522 SetLastExceptionMsg("Failed to dispatch the .uno: command");
3526 static void doc_postMouseEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
3528 comphelper::ProfileZone
aZone("doc_postMouseEvent");
3530 SolarMutexGuard aGuard
;
3531 SetLastExceptionMsg();
3533 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3536 SetLastExceptionMsg("Document doesn't support tiled rendering");
3540 pDoc
->postMouseEvent(nType
, nX
, nY
, nCount
, nButtons
, nModifier
);
3543 static void doc_postWindowMouseEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
3545 comphelper::ProfileZone
aZone("doc_postWindowMouseEvent");
3547 SolarMutexGuard aGuard
;
3548 SetLastExceptionMsg();
3550 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3553 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3557 const Point
aPos(nX
, nY
);
3558 MouseEvent
aEvent(aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
, nButtons
, nModifier
);
3560 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
3562 pDialog
->EnableInput();
3567 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN
:
3568 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown
, pWindow
, &aEvent
);
3570 case LOK_MOUSEEVENT_MOUSEBUTTONUP
:
3571 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp
, pWindow
, &aEvent
);
3573 case LOK_MOUSEEVENT_MOUSEMOVE
:
3574 Application::PostMouseEvent(VclEventId::WindowMouseMove
, pWindow
, &aEvent
);
3582 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, const char* pType
, int nX
, int nY
, int nOffset
)
3584 comphelper::ProfileZone
aZone("doc_postWindowGestureEvent");
3586 SolarMutexGuard aGuard
;
3587 SetLastExceptionMsg();
3589 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3592 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3596 OString
aType(pType
);
3597 GestureEventType eEventType
= GestureEventType::PanningUpdate
;
3599 if (aType
== "panBegin")
3600 eEventType
= GestureEventType::PanningBegin
;
3601 else if (aType
== "panEnd")
3602 eEventType
= GestureEventType::PanningEnd
;
3604 GestureEvent aEvent
{
3609 PanningOrientation::Vertical
,
3612 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
3614 pDialog
->EnableInput();
3617 Application::PostGestureEvent(VclEventId::WindowGestureEvent
, pWindow
, &aEvent
);
3620 static void doc_setTextSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
3622 comphelper::ProfileZone
aZone("doc_setTextSelection");
3624 SolarMutexGuard aGuard
;
3625 SetLastExceptionMsg();
3627 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3630 SetLastExceptionMsg("Document doesn't support tiled rendering");
3634 pDoc
->setTextSelection(nType
, nX
, nY
);
3637 static bool getFromTransferrable(
3638 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3639 const OString
&aInMimeType
, OString
&aRet
);
3641 static bool encodeImageAsHTML(
3642 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3643 const OString
&aMimeType
, OString
&aRet
)
3645 if (!getFromTransferrable(xTransferable
, aMimeType
, aRet
))
3648 // Encode in base64.
3649 auto aSeq
= Sequence
<sal_Int8
>(reinterpret_cast<const sal_Int8
*>(aRet
.getStr()),
3651 OUStringBuffer aBase64Data
;
3652 comphelper::Base64::encode(aBase64Data
, aSeq
);
3655 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
3657 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
3658 "name=\"generator\" content=\""
3659 + getGenerator().toUtf8()
3661 "</head><body><img src=\"data:" + aMimeType
+ ";base64,"
3662 + aBase64Data
.makeStringAndClear().toUtf8() + "\"/></body></html>";
3667 static bool encodeTextAsHTML(
3668 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3669 const OString
&aMimeType
, OString
&aRet
)
3671 if (!getFromTransferrable(xTransferable
, aMimeType
, aRet
))
3674 // Embed in HTML - FIXME: needs some escaping.
3675 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
3677 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
3678 "name=\"generator\" content=\""
3679 + getGenerator().toUtf8()
3680 + "\"/></head><body><pre>" + aRet
+ "</pre></body></html>";
3685 static bool getFromTransferrable(
3686 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3687 const OString
&aInMimeType
, OString
&aRet
)
3689 OString
aMimeType(aInMimeType
);
3691 // Take care of UTF-8 text here.
3692 bool bConvert
= false;
3693 sal_Int32 nIndex
= 0;
3694 if (aMimeType
.getToken(0, ';', nIndex
) == "text/plain")
3696 if (aMimeType
.getToken(0, ';', nIndex
) == "charset=utf-8")
3698 aMimeType
= "text/plain;charset=utf-16";
3703 datatransfer::DataFlavor aFlavor
;
3704 aFlavor
.MimeType
= OUString::fromUtf8(aMimeType
.getStr());
3705 if (aMimeType
== "text/plain;charset=utf-16")
3706 aFlavor
.DataType
= cppu::UnoType
<OUString
>::get();
3708 aFlavor
.DataType
= cppu::UnoType
< uno::Sequence
<sal_Int8
> >::get();
3710 if (!xTransferable
->isDataFlavorSupported(aFlavor
))
3712 // Try harder for HTML it is our copy/paste meta-file format
3713 if (aInMimeType
== "text/html")
3715 // Desperate measures - convert text to HTML instead.
3716 if (encodeTextAsHTML(xTransferable
, "text/plain;charset=utf-8", aRet
))
3718 // If html is not supported, might be a graphic-selection,
3719 if (encodeImageAsHTML(xTransferable
, "image/png", aRet
))
3723 SetLastExceptionMsg("Flavor " + aFlavor
.MimeType
+ " is not supported");
3730 aAny
= xTransferable
->getTransferData(aFlavor
);
3732 catch (const css::datatransfer::UnsupportedFlavorException
& e
)
3734 SetLastExceptionMsg("Unsupported flavor " + aFlavor
.MimeType
+ " exception " + e
.Message
);
3737 catch (const css::uno::Exception
& e
)
3739 SetLastExceptionMsg("Exception getting " + aFlavor
.MimeType
+ " exception " + e
.Message
);
3743 if (aFlavor
.DataType
== cppu::UnoType
<OUString
>::get())
3748 aRet
= OUStringToOString(aString
, RTL_TEXTENCODING_UTF8
);
3750 aRet
= OString(reinterpret_cast<const sal_Char
*>(aString
.getStr()), aString
.getLength() * sizeof(sal_Unicode
));
3754 uno::Sequence
<sal_Int8
> aSequence
;
3756 aRet
= OString(reinterpret_cast<sal_Char
*>(aSequence
.getArray()), aSequence
.getLength());
3762 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, char** pUsedMimeType
)
3764 comphelper::ProfileZone
aZone("doc_getTextSelection");
3766 SolarMutexGuard aGuard
;
3767 SetLastExceptionMsg();
3769 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3772 SetLastExceptionMsg("Document doesn't support tiled rendering");
3776 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= pDoc
->getSelection();
3779 SetLastExceptionMsg("No selection available");
3783 const char *pType
= pMimeType
;
3784 if (!pType
|| pType
[0] == '\0')
3785 pType
= "text/plain;charset=utf-8";
3788 bool bSuccess
= getFromTransferrable(xTransferable
, OString(pType
), aRet
);
3792 if (pUsedMimeType
) // legacy
3795 *pUsedMimeType
= strdup(pMimeType
);
3797 *pUsedMimeType
= nullptr;
3800 return convertOString(aRet
);
3803 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
)
3805 comphelper::ProfileZone
aZone("doc_getSelectionType");
3807 SolarMutexGuard aGuard
;
3808 SetLastExceptionMsg();
3810 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3813 SetLastExceptionMsg("Document doesn't support tiled rendering");
3814 return LOK_SELTYPE_NONE
;
3817 css::uno::Reference
<css::datatransfer::XTransferable2
> xTransferable(pDoc
->getSelection(), css::uno::UNO_QUERY
);
3820 SetLastExceptionMsg("No selection available");
3821 return LOK_SELTYPE_NONE
;
3824 if (xTransferable
->isComplex())
3825 return LOK_SELTYPE_COMPLEX
;
3828 bool bSuccess
= getFromTransferrable(xTransferable
, "text/plain;charset=utf-8", aRet
);
3830 return LOK_SELTYPE_NONE
;
3832 if (aRet
.getLength() > 10000)
3833 return LOK_SELTYPE_COMPLEX
;
3835 return aRet
.getLength() ? LOK_SELTYPE_TEXT
: LOK_SELTYPE_NONE
;
3838 static int doc_getClipboard(LibreOfficeKitDocument
* pThis
,
3839 const char **pMimeTypes
,
3841 char ***pOutMimeTypes
,
3843 char ***pOutStreams
)
3845 comphelper::ProfileZone
aZone("doc_getClipboard");
3847 SolarMutexGuard aGuard
;
3848 SetLastExceptionMsg();
3851 assert (pOutMimeTypes
);
3853 assert (pOutStreams
);
3856 *pOutMimeTypes
= nullptr;
3857 *pOutSizes
= nullptr;
3858 *pOutStreams
= nullptr;
3860 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3863 SetLastExceptionMsg("Document doesn't support tiled rendering");
3867 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
3869 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= xClip
->getContents();
3870 SAL_INFO("lok", "Got from clip: " << xClip
.get() << " transferrable: " << xTransferable
);
3873 SetLastExceptionMsg("No clipboard content available");
3877 std::vector
<OString
> aMimeTypes
;
3878 if (!pMimeTypes
) // everything
3880 const uno::Sequence
< css::datatransfer::DataFlavor
> flavors
= xTransferable
->getTransferDataFlavors();
3881 if (!flavors
.getLength())
3883 SetLastExceptionMsg("Flavourless selection");
3886 for (const auto &it
: flavors
)
3887 aMimeTypes
.push_back(OUStringToOString(it
.MimeType
, RTL_TEXTENCODING_UTF8
));
3891 for (size_t i
= 0; pMimeTypes
[i
]; ++i
)
3892 aMimeTypes
.push_back(OString(pMimeTypes
[i
]));
3895 *pOutCount
= aMimeTypes
.size();
3896 *pOutSizes
= static_cast<size_t *>(malloc(*pOutCount
* sizeof(size_t)));
3897 *pOutMimeTypes
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
3898 *pOutStreams
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
3899 for (size_t i
= 0; i
< aMimeTypes
.size(); ++i
)
3901 if (aMimeTypes
[i
] == "text/plain;charset=utf-16")
3902 (*pOutMimeTypes
)[i
] = strdup("text/plain;charset=utf-8");
3904 (*pOutMimeTypes
)[i
] = strdup(aMimeTypes
[i
].getStr());
3907 bool bSuccess
= getFromTransferrable(xTransferable
, (*pOutMimeTypes
)[i
], aRet
);
3908 if (!bSuccess
|| aRet
.getLength() < 1)
3910 (*pOutSizes
)[i
] = 0;
3911 (*pOutStreams
)[i
] = nullptr;
3915 (*pOutSizes
)[i
] = aRet
.getLength();
3916 (*pOutStreams
)[i
] = convertOString(aRet
);
3923 static int doc_setClipboard(LibreOfficeKitDocument
* pThis
,
3924 const size_t nInCount
,
3925 const char **pInMimeTypes
,
3926 const size_t *pInSizes
,
3927 const char **pInStreams
)
3932 (void) pInMimeTypes
;
3936 comphelper::ProfileZone
aZone("doc_setClipboard");
3938 SolarMutexGuard aGuard
;
3939 SetLastExceptionMsg();
3941 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3944 SetLastExceptionMsg("Document doesn't support tiled rendering");
3948 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(nInCount
, pInMimeTypes
, pInSizes
, pInStreams
));
3950 auto xClip
= forceSetClipboardForCurrentView(pThis
);
3951 xClip
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
3953 SAL_INFO("lok", "Set clip: " << xClip
.get() << " to: " << xTransferable
);
3955 if (!pDoc
->isMimeTypeSupported())
3957 SetLastExceptionMsg("Document doesn't support this mime type");
3964 static bool doc_paste(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, const char* pData
, size_t nSize
)
3966 comphelper::ProfileZone
aZone("doc_paste");
3968 SolarMutexGuard aGuard
;
3970 const char *pInMimeTypes
[1];
3971 const char *pInStreams
[1];
3973 pInMimeTypes
[0] = pMimeType
;
3974 pInSizes
[0] = nSize
;
3975 pInStreams
[0] = pData
;
3977 if (!doc_setClipboard(pThis
, 1, pInMimeTypes
, pInSizes
, pInStreams
))
3980 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
3982 {"AnchorType", uno::makeAny(static_cast<sal_uInt16
>(text::TextContentAnchorType_AS_CHARACTER
))},
3983 {"IgnoreComments", uno::makeAny(true)},
3985 if (!comphelper::dispatchCommand(".uno:Paste", aPropertyValues
))
3987 SetLastExceptionMsg("Failed to dispatch the .uno: command");
3994 static void doc_setGraphicSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
3996 comphelper::ProfileZone
aZone("doc_setGraphicSelection");
3998 SolarMutexGuard aGuard
;
3999 SetLastExceptionMsg();
4001 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4004 SetLastExceptionMsg("Document doesn't support tiled rendering");
4008 pDoc
->setGraphicSelection(nType
, nX
, nY
);
4011 static void doc_resetSelection(LibreOfficeKitDocument
* pThis
)
4013 comphelper::ProfileZone
aZone("doc_resetSelection");
4015 SolarMutexGuard aGuard
;
4016 SetLastExceptionMsg();
4018 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4021 SetLastExceptionMsg("Document doesn't support tiled rendering");
4025 pDoc
->resetSelection();
4028 static char* getLanguages(const char* pCommand
)
4030 css::uno::Sequence
< css::lang::Locale
> aLocales
;
4034 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
4037 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
4039 aLocales
= xSpell
->getLocales();
4043 boost::property_tree::ptree aTree
;
4044 aTree
.put("commandName", pCommand
);
4045 boost::property_tree::ptree aValues
;
4046 boost::property_tree::ptree aChild
;
4048 for ( sal_Int32 itLocale
= 0; itLocale
< aLocales
.getLength(); itLocale
++ )
4050 const LanguageTag
aLanguageTag( aLocales
[itLocale
]);
4051 sLanguage
= SvtLanguageTable::GetLanguageString(aLanguageTag
.getLanguageType());
4052 if (sLanguage
.startsWith("{") && sLanguage
.endsWith("}"))
4055 sLanguage
+= ";" + aLanguageTag
.getBcp47(false);
4056 aChild
.put("", sLanguage
.toUtf8());
4057 aValues
.push_back(std::make_pair("", aChild
));
4059 aTree
.add_child("commandValues", aValues
);
4060 std::stringstream aStream
;
4061 boost::property_tree::write_json(aStream
, aTree
);
4062 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4063 assert(pJson
); // Don't handle OOM conditions
4064 strcpy(pJson
, aStream
.str().c_str());
4065 pJson
[aStream
.str().size()] = '\0';
4069 static char* getFonts (const char* pCommand
)
4071 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4072 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4073 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4074 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4076 boost::property_tree::ptree aTree
;
4077 aTree
.put("commandName", pCommand
);
4078 boost::property_tree::ptree aValues
;
4081 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4082 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
4084 boost::property_tree::ptree aChildren
;
4085 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
4086 const sal_IntPtr
* pAry
= pList
->GetSizeAry(rFontMetric
);
4087 sal_uInt16 nSizeCount
= 0;
4088 while (pAry
[nSizeCount
])
4090 boost::property_tree::ptree aChild
;
4091 aChild
.put("", static_cast<float>(pAry
[nSizeCount
]) / 10);
4092 aChildren
.push_back(std::make_pair("", aChild
));
4095 aValues
.add_child(rFontMetric
.GetFamilyName().toUtf8().getStr(), aChildren
);
4098 aTree
.add_child("commandValues", aValues
);
4099 std::stringstream aStream
;
4100 boost::property_tree::write_json(aStream
, aTree
);
4101 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4102 assert(pJson
); // Don't handle OOM conditions
4103 strcpy(pJson
, aStream
.str().c_str());
4104 pJson
[aStream
.str().size()] = '\0';
4108 static char* getFontSubset (const OString
& aFontName
)
4110 OUString
aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName
, RTL_TEXTENCODING_UTF8
), rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
));
4111 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4112 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4113 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4114 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4116 boost::property_tree::ptree aTree
;
4117 aTree
.put("commandName", ".uno:FontSubset");
4118 boost::property_tree::ptree aValues
;
4120 if ( pList
&& !aFoundFont
.isEmpty() )
4122 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4123 sal_uInt16 nItFont
= 0;
4124 for (; nItFont
< nFontCount
; ++nItFont
)
4126 if (aFoundFont
== pList
->GetFontName(nItFont
).GetFamilyName())
4132 if ( nItFont
< nFontCount
)
4134 FontCharMapRef
xFontCharMap (new FontCharMap());
4135 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
));
4136 const vcl::Font
& aFont(pList
->GetFontName(nItFont
));
4138 aDevice
->SetFont(aFont
);
4139 aDevice
->GetFontCharMap(xFontCharMap
);
4140 SubsetMap
aSubMap(xFontCharMap
);
4142 for (auto const& subset
: aSubMap
.GetSubsetMap())
4144 boost::property_tree::ptree aChild
;
4145 aChild
.put("", static_cast<int>(ublock_getCode(subset
.GetRangeMin())));
4146 aValues
.push_back(std::make_pair("", aChild
));
4151 aTree
.add_child("commandValues", aValues
);
4152 std::stringstream aStream
;
4153 boost::property_tree::write_json(aStream
, aTree
);
4154 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4155 assert(pJson
); // Don't handle OOM conditions
4156 strcpy(pJson
, aStream
.str().c_str());
4157 pJson
[aStream
.str().size()] = '\0';
4161 static char* getStyles(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
4163 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4165 boost::property_tree::ptree aTree
;
4166 aTree
.put("commandName", pCommand
);
4167 uno::Reference
<css::style::XStyleFamiliesSupplier
> xStyleFamiliesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
4168 uno::Reference
<container::XNameAccess
> xStyleFamilies
= xStyleFamiliesSupplier
->getStyleFamilies();
4169 uno::Sequence
<OUString
> aStyleFamilies
= xStyleFamilies
->getElementNames();
4171 static const std::vector
<OUString
> aWriterStyles
=
4182 // We need to keep a list of the default style names
4183 // in order to filter these out later when processing
4184 // the full list of styles.
4185 std::set
<OUString
> aDefaultStyleNames
;
4187 boost::property_tree::ptree aValues
;
4188 for (sal_Int32 nStyleFam
= 0; nStyleFam
< aStyleFamilies
.getLength(); ++nStyleFam
)
4190 boost::property_tree::ptree aChildren
;
4191 OUString sStyleFam
= aStyleFamilies
[nStyleFam
];
4192 uno::Reference
<container::XNameAccess
> xStyleFamily(xStyleFamilies
->getByName(sStyleFam
), uno::UNO_QUERY
);
4194 // Writer provides a huge number of styles, we have a list of 7 "default" styles which
4195 // should be shown in the normal dropdown, which we should add to the start of the list
4196 // to simplify their selection.
4197 if (sStyleFam
== "ParagraphStyles"
4198 && doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
)
4200 for (const OUString
& rStyle
: aWriterStyles
)
4202 aDefaultStyleNames
.insert( rStyle
);
4204 boost::property_tree::ptree aChild
;
4205 aChild
.put("", rStyle
.toUtf8());
4206 aChildren
.push_back(std::make_pair("", aChild
));
4210 const uno::Sequence
<OUString
> aStyles
= xStyleFamily
->getElementNames();
4211 for (const OUString
& rStyle
: aStyles
)
4213 // Filter out the default styles - they are already at the top
4215 if (aDefaultStyleNames
.find(rStyle
) == aDefaultStyleNames
.end() ||
4216 (sStyleFam
!= "ParagraphStyles" || doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
) )
4218 boost::property_tree::ptree aChild
;
4219 aChild
.put("", rStyle
.toUtf8());
4220 aChildren
.push_back(std::make_pair("", aChild
));
4223 aValues
.add_child(sStyleFam
.toUtf8().getStr(), aChildren
);
4226 // Header & Footer Styles
4229 boost::property_tree::ptree aChild
;
4230 boost::property_tree::ptree aChildren
;
4231 const OUString
sPageStyles("PageStyles");
4232 uno::Reference
<beans::XPropertySet
> xProperty
;
4233 uno::Reference
<container::XNameContainer
> xContainer
;
4235 if (xStyleFamilies
->hasByName(sPageStyles
) && (xStyleFamilies
->getByName(sPageStyles
) >>= xContainer
))
4237 uno::Sequence
<OUString
> aSeqNames
= xContainer
->getElementNames();
4238 for (sal_Int32 itName
= 0; itName
< aSeqNames
.getLength(); itName
++)
4241 sName
= aSeqNames
[itName
];
4242 xProperty
.set(xContainer
->getByName(sName
), uno::UNO_QUERY
);
4243 if (xProperty
.is() && (xProperty
->getPropertyValue("IsPhysical") >>= bIsPhysical
) && bIsPhysical
)
4245 xProperty
->getPropertyValue("DisplayName") >>= sName
;
4246 aChild
.put("", sName
.toUtf8());
4247 aChildren
.push_back(std::make_pair("", aChild
));
4250 aValues
.add_child("HeaderFooter", aChildren
);
4255 boost::property_tree::ptree aCommandList
;
4258 boost::property_tree::ptree aChild
;
4260 OUString sClearFormat
= SvxResId(RID_SVXSTR_CLEARFORM
);
4262 boost::property_tree::ptree aName
;
4263 aName
.put("", sClearFormat
.toUtf8());
4264 aChild
.push_back(std::make_pair("text", aName
));
4266 boost::property_tree::ptree aCommand
;
4267 aCommand
.put("", ".uno:ResetAttributes");
4268 aChild
.push_back(std::make_pair("id", aCommand
));
4270 aCommandList
.push_back(std::make_pair("", aChild
));
4273 aValues
.add_child("Commands", aCommandList
);
4276 aTree
.add_child("commandValues", aValues
);
4277 std::stringstream aStream
;
4278 boost::property_tree::write_json(aStream
, aTree
);
4279 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4280 assert(pJson
); // Don't handle OOM conditions
4281 strcpy(pJson
, aStream
.str().c_str());
4282 pJson
[aStream
.str().size()] = '\0';
4286 enum class UndoOrRedo
4292 /// Returns the JSON representation of either an undo or a redo stack.
4293 static char* getUndoOrRedo(LibreOfficeKitDocument
* pThis
, UndoOrRedo eCommand
)
4295 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4297 auto pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
4301 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
4305 SfxUndoManager
* pUndoManager
= pObjectShell
->GetUndoManager();
4310 if (eCommand
== UndoOrRedo::UNDO
)
4311 aString
= pUndoManager
->GetUndoActionsInfo();
4313 aString
= pUndoManager
->GetRedoActionsInfo();
4314 char* pJson
= strdup(aString
.toUtf8().getStr());
4318 /// Returns the JSON representation of the redline stack.
4319 static char* getTrackedChanges(LibreOfficeKitDocument
* pThis
)
4321 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4323 uno::Reference
<document::XRedlinesSupplier
> xRedlinesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
4324 std::stringstream aStream
;
4325 // We want positions of the track changes also which is not possible from
4326 // UNO. Enable positioning information for text documents only for now, so
4327 // construct the tracked changes JSON from inside the sw/, not here using UNO
4328 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
&& xRedlinesSupplier
.is())
4330 uno::Reference
<container::XEnumeration
> xRedlines
= xRedlinesSupplier
->getRedlines()->createEnumeration();
4331 boost::property_tree::ptree aRedlines
;
4332 for (size_t nIndex
= 0; xRedlines
->hasMoreElements(); ++nIndex
)
4334 uno::Reference
<beans::XPropertySet
> xRedline(xRedlines
->nextElement(), uno::UNO_QUERY
);
4335 boost::property_tree::ptree aRedline
;
4336 aRedline
.put("index", nIndex
);
4339 xRedline
->getPropertyValue("RedlineAuthor") >>= sAuthor
;
4340 aRedline
.put("author", sAuthor
.toUtf8().getStr());
4343 xRedline
->getPropertyValue("RedlineType") >>= sType
;
4344 aRedline
.put("type", sType
.toUtf8().getStr());
4347 xRedline
->getPropertyValue("RedlineComment") >>= sComment
;
4348 aRedline
.put("comment", sComment
.toUtf8().getStr());
4350 OUString sDescription
;
4351 xRedline
->getPropertyValue("RedlineDescription") >>= sDescription
;
4352 aRedline
.put("description", sDescription
.toUtf8().getStr());
4354 util::DateTime aDateTime
;
4355 xRedline
->getPropertyValue("RedlineDateTime") >>= aDateTime
;
4356 OUString sDateTime
= utl::toISO8601(aDateTime
);
4357 aRedline
.put("dateTime", sDateTime
.toUtf8().getStr());
4359 aRedlines
.push_back(std::make_pair("", aRedline
));
4362 boost::property_tree::ptree aTree
;
4363 aTree
.add_child("redlines", aRedlines
);
4364 boost::property_tree::write_json(aStream
, aTree
);
4368 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4371 SetLastExceptionMsg("Document doesn't support tiled rendering");
4374 OUString aTrackedChanges
= pDoc
->getTrackedChanges();
4375 aStream
<< aTrackedChanges
.toUtf8();
4378 char* pJson
= strdup(aStream
.str().c_str());
4383 /// Returns the JSON representation of the redline author table.
4384 static char* getTrackedChangeAuthors(LibreOfficeKitDocument
* pThis
)
4386 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4389 SetLastExceptionMsg("Document doesn't support tiled rendering");
4392 OUString aAuthors
= pDoc
->getTrackedChangeAuthors();
4393 return strdup(aAuthors
.toUtf8().getStr());
4396 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
4398 comphelper::ProfileZone
aZone("doc_getCommandValues");
4400 SolarMutexGuard aGuard
;
4401 SetLastExceptionMsg();
4403 OString
aCommand(pCommand
);
4404 static const OString
aViewRowColumnHeaders(".uno:ViewRowColumnHeaders");
4405 static const OString
aCellCursor(".uno:CellCursor");
4406 static const OString
aFontSubset(".uno:FontSubset&name=");
4408 if (!strcmp(pCommand
, ".uno:LanguageStatus"))
4410 return getLanguages(pCommand
);
4412 else if (!strcmp(pCommand
, ".uno:CharFontName"))
4414 return getFonts(pCommand
);
4416 else if (!strcmp(pCommand
, ".uno:StyleApply"))
4418 return getStyles(pThis
, pCommand
);
4420 else if (aCommand
== ".uno:Undo")
4422 return getUndoOrRedo(pThis
, UndoOrRedo::UNDO
);
4424 else if (aCommand
== ".uno:Redo")
4426 return getUndoOrRedo(pThis
, UndoOrRedo::REDO
);
4428 else if (aCommand
== ".uno:AcceptTrackedChanges")
4430 return getTrackedChanges(pThis
);
4432 else if (aCommand
== ".uno:TrackedChangeAuthors")
4434 return getTrackedChangeAuthors(pThis
);
4436 else if (aCommand
== ".uno:ViewAnnotations")
4438 return getPostIts(pThis
);
4440 else if (aCommand
== ".uno:ViewAnnotationsPosition")
4442 return getPostItsPos(pThis
);
4444 else if (aCommand
== ".uno:RulerState")
4446 return getRulerState(pThis
);
4448 else if (aCommand
.startsWith(aViewRowColumnHeaders
))
4450 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4453 SetLastExceptionMsg("Document doesn't support tiled rendering");
4457 tools::Rectangle aRectangle
;
4458 if (aCommand
.getLength() > aViewRowColumnHeaders
.getLength())
4460 // Command has parameters.
4465 OString aArguments
= aCommand
.copy(aViewRowColumnHeaders
.getLength() + 1);
4466 sal_Int32 nParamIndex
= 0;
4469 OString aParamToken
= aArguments
.getToken(0, '&', nParamIndex
);
4470 sal_Int32 nIndex
= 0;
4475 OString aToken
= aParamToken
.getToken(0, '=', nIndex
);
4476 if (!aKey
.getLength())
4481 while (nIndex
>= 0);
4483 nX
= aValue
.toInt32();
4484 else if (aKey
== "y")
4485 nY
= aValue
.toInt32();
4486 else if (aKey
== "width")
4487 nWidth
= aValue
.toInt32();
4488 else if (aKey
== "height")
4489 nHeight
= aValue
.toInt32();
4491 while (nParamIndex
>= 0);
4493 aRectangle
= tools::Rectangle(nX
, nY
, nX
+ nWidth
, nY
+ nHeight
);
4496 OUString aHeaders
= pDoc
->getRowColumnHeaders(aRectangle
);
4497 if (aHeaders
.isEmpty())
4500 return convertOUString(aHeaders
);
4502 else if (aCommand
.startsWith(aCellCursor
))
4504 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4507 SetLastExceptionMsg("Document doesn't support tiled rendering");
4511 // Command has parameters.
4512 int nOutputWidth
= 0;
4513 int nOutputHeight
= 0;
4514 long nTileWidth
= 0;
4515 long nTileHeight
= 0;
4516 if (aCommand
.getLength() > aCellCursor
.getLength())
4518 OString aArguments
= aCommand
.copy(aCellCursor
.getLength() + 1);
4519 sal_Int32 nParamIndex
= 0;
4522 OString aParamToken
= aArguments
.getToken(0, '&', nParamIndex
);
4523 sal_Int32 nIndex
= 0;
4528 OString aToken
= aParamToken
.getToken(0, '=', nIndex
);
4529 if (!aKey
.getLength())
4534 while (nIndex
>= 0);
4535 if (aKey
== "outputWidth")
4536 nOutputWidth
= aValue
.toInt32();
4537 else if (aKey
== "outputHeight")
4538 nOutputHeight
= aValue
.toInt32();
4539 else if (aKey
== "tileWidth")
4540 nTileWidth
= aValue
.toInt64();
4541 else if (aKey
== "tileHeight")
4542 nTileHeight
= aValue
.toInt64();
4544 while (nParamIndex
>= 0);
4547 return convertOString(pDoc
->getCellCursor(nOutputWidth
, nOutputHeight
, nTileWidth
, nTileHeight
));
4549 else if (aCommand
.startsWith(aFontSubset
))
4551 return getFontSubset(OString(pCommand
+ aFontSubset
.getLength()));
4555 SetLastExceptionMsg("Unknown command, no values returned");
4560 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
, int nTilePixelWidth
, int nTilePixelHeight
,
4561 int nTileTwipWidth
, int nTileTwipHeight
)
4563 comphelper::ProfileZone
aZone("doc_setClientZoom");
4565 SolarMutexGuard aGuard
;
4566 SetLastExceptionMsg();
4568 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4571 SetLastExceptionMsg("Document doesn't support tiled rendering");
4575 pDoc
->setClientZoom(nTilePixelWidth
, nTilePixelHeight
, nTileTwipWidth
, nTileTwipHeight
);
4578 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
)
4580 comphelper::ProfileZone
aZone("doc_setClientVisibleArea");
4582 SolarMutexGuard aGuard
;
4583 SetLastExceptionMsg();
4585 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4588 SetLastExceptionMsg("Document doesn't support tiled rendering");
4592 tools::Rectangle
aRectangle(Point(nX
, nY
), Size(nWidth
, nHeight
));
4593 pDoc
->setClientVisibleArea(aRectangle
);
4596 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
)
4598 comphelper::ProfileZone
aZone("doc_setOutlineState");
4600 SolarMutexGuard aGuard
;
4601 SetLastExceptionMsg();
4603 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4606 SetLastExceptionMsg("Document doesn't support tiled rendering");
4610 pDoc
->setOutlineState(bColumn
, nLevel
, nIndex
, bHidden
);
4613 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
,
4614 const char* pOptions
)
4616 comphelper::ProfileZone
aZone("doc_createView");
4618 SolarMutexGuard aGuard
;
4619 SetLastExceptionMsg();
4621 OUString aOptions
= getUString(pOptions
);
4622 const OUString aLanguage
= extractParameter(aOptions
, "Language");
4624 if (!aLanguage
.isEmpty())
4626 // Set the LOK language tag, used for dialog tunneling.
4627 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage
));
4630 int nId
= SfxLokHelper::createView();
4635 forceSetClipboardForCurrentView(pThis
);
4641 static int doc_createView(LibreOfficeKitDocument
* pThis
)
4643 return doc_createViewWithOptions(pThis
, nullptr); // No options.
4646 static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
)
4648 comphelper::ProfileZone
aZone("doc_destroyView");
4650 SolarMutexGuard aGuard
;
4651 SetLastExceptionMsg();
4653 LOKClipboardFactory::releaseClipboardForView(nId
);
4655 SfxLokHelper::destroyView(nId
);
4658 static void doc_setView(LibreOfficeKitDocument
* pThis
, int nId
)
4660 comphelper::ProfileZone
aZone("doc_setView");
4662 SolarMutexGuard aGuard
;
4663 SetLastExceptionMsg();
4665 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4666 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nId
);
4667 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4668 handlerIt
->second
->disableCallbacks();
4672 SfxLokHelper::setView(nId
);
4674 catch (const std::exception
&)
4678 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4679 handlerIt
->second
->enableCallbacks();
4682 static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
4684 comphelper::ProfileZone
aZone("doc_getView");
4686 SolarMutexGuard aGuard
;
4687 SetLastExceptionMsg();
4689 return SfxLokHelper::getView();
4692 static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
4694 comphelper::ProfileZone
aZone("doc_getViewsCount");
4696 SolarMutexGuard aGuard
;
4697 SetLastExceptionMsg();
4699 return SfxLokHelper::getViewsCount();
4702 static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int* pArray
, size_t nSize
)
4704 comphelper::ProfileZone
aZone("doc_getViewsIds");
4706 SolarMutexGuard aGuard
;
4707 SetLastExceptionMsg();
4709 return SfxLokHelper::getViewIds(pArray
, nSize
);
4712 static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
, const char* language
)
4714 comphelper::ProfileZone
aZone("doc_setViewLanguage");
4716 SolarMutexGuard aGuard
;
4717 SetLastExceptionMsg();
4719 SfxLokHelper::setViewLanguage(nId
, OStringToOUString(language
, RTL_TEXTENCODING_UTF8
));
4724 unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
4725 const char* pFontName
,
4730 return doc_renderFontOrientation(pThis
, pFontName
, pChar
, pFontWidth
, pFontHeight
, 0);
4733 unsigned char* doc_renderFontOrientation(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/,
4734 const char* pFontName
,
4740 comphelper::ProfileZone
aZone("doc_renderFont");
4742 SolarMutexGuard aGuard
;
4743 SetLastExceptionMsg();
4745 OString
aSearchedFontName(pFontName
);
4746 OUString
aText(OStringToOUString(pChar
, RTL_TEXTENCODING_UTF8
));
4747 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4748 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4749 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4750 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4752 const int nDefaultFontSize
= 25;
4756 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4757 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
4759 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
4760 const OUString
& aFontName
= rFontMetric
.GetFamilyName();
4761 if (aSearchedFontName
!= aFontName
.toUtf8())
4764 if (aText
.isEmpty())
4765 aText
= rFontMetric
.GetFamilyName();
4767 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
));
4768 ::tools::Rectangle aRect
;
4769 vcl::Font
aFont(rFontMetric
);
4770 aFont
.SetFontSize(Size(0, nDefaultFontSize
));
4771 aFont
.SetOrientation(pOrientation
);
4772 aDevice
->SetFont(aFont
);
4773 aDevice
->GetTextBoundRect(aRect
, aText
);
4774 if (aRect
.IsEmpty())
4777 int nFontWidth
= aRect
.BottomRight().X() + 1;
4778 int nFontHeight
= aRect
.BottomRight().Y() + 1;
4780 if (!(nFontWidth
> 0 && nFontHeight
> 0))
4783 if (*pFontWidth
> 0 && *pFontHeight
> 0)
4785 double fScaleX
= *pFontWidth
/ static_cast<double>(nFontWidth
) / 1.5;
4786 double fScaleY
= *pFontHeight
/ static_cast<double>(nFontHeight
) / 1.5;
4788 double fScale
= std::min(fScaleX
, fScaleY
);
4792 int nFontSize
= fScale
* nDefaultFontSize
;
4793 aFont
.SetFontSize(Size(0, nFontSize
));
4794 aDevice
->SetFont(aFont
);
4797 aRect
= tools::Rectangle(0, 0, *pFontWidth
, *pFontHeight
);
4799 nFontWidth
= *pFontWidth
;
4800 nFontHeight
= *pFontHeight
;
4804 unsigned char* pBuffer
= static_cast<unsigned char*>(malloc(4 * nFontWidth
* nFontHeight
));
4808 memset(pBuffer
, 0, nFontWidth
* nFontHeight
* 4);
4809 aDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
4810 aDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
4811 Size(nFontWidth
, nFontHeight
), Fraction(1.0), Point(),
4814 if (*pFontWidth
> 0 && *pFontHeight
> 0)
4816 DrawTextFlags
const nStyle
=
4817 DrawTextFlags::Center
4818 | DrawTextFlags::VCenter
4819 | DrawTextFlags::Bottom
4820 | DrawTextFlags::MultiLine
4821 | DrawTextFlags::WordBreak
;// | DrawTextFlags::WordBreakHyphenation ;
4823 aDevice
->DrawText(aRect
, aText
, nStyle
);
4827 *pFontWidth
= nFontWidth
;
4828 *pFontHeight
= nFontHeight
;
4830 aDevice
->DrawText(Point(0,0), aText
);
4841 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
4842 unsigned char* pBuffer
,
4843 const int nX
, const int nY
,
4844 const int nWidth
, const int nHeight
)
4846 doc_paintWindowDPI(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, 1.0);
4849 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
4850 unsigned char* pBuffer
,
4851 const int nX
, const int nY
,
4852 const int nWidth
, const int nHeight
,
4853 const double fDPIScale
)
4855 doc_paintWindowForView(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, fDPIScale
, -1);
4858 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
4859 unsigned char* pBuffer
, const int nX
, const int nY
,
4860 const int nWidth
, const int nHeight
,
4861 const double fDPIScale
, int viewId
)
4863 comphelper::ProfileZone
aZone("doc_paintWindowDPI");
4865 SolarMutexGuard aGuard
;
4866 SetLastExceptionMsg();
4868 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4871 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4875 // Used to avoid work in setView if set.
4876 comphelper::LibreOfficeKit::setDialogPainting(true);
4879 doc_setView(pThis
, viewId
);
4881 // Setup cairo (or CoreGraphics, in the iOS case) to draw with the changed DPI scale (and return
4882 // back to 1.0 when the painting finishes)
4883 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
4884 comphelper::LibreOfficeKit::setDPIScale(fDPIScale
);
4888 CGContextRef cgc
= CGBitmapContextCreate(pBuffer
, nWidth
, nHeight
, 8, nWidth
*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst
| kCGImageByteOrder32Little
);
4890 CGContextTranslateCTM(cgc
, 0, nHeight
);
4891 CGContextScaleCTM(cgc
, fDPIScale
, -fDPIScale
);
4893 SystemGraphicsData aData
;
4894 aData
.rCGContext
= cgc
;
4896 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::DEFAULT
);
4897 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
4899 pDevice
->SetOutputSizePixel(Size(nWidth
, nHeight
));
4901 MapMode
aMapMode(pDevice
->GetMapMode());
4902 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
4903 pDevice
->SetMapMode(aMapMode
);
4905 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0), Size());
4907 CGContextRelease(cgc
);
4911 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
4912 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
4914 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(Size(nWidth
, nHeight
), Fraction(1.0), Point(), pBuffer
);
4916 MapMode
aMapMode(pDevice
->GetMapMode());
4917 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
4918 pDevice
->SetMapMode(aMapMode
);
4920 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0), Size());
4923 comphelper::LibreOfficeKit::setDialogPainting(false);
4926 static void doc_postWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nAction
, const char* pData
)
4928 comphelper::ProfileZone
aZone("doc_postWindow");
4930 SolarMutexGuard aGuard
;
4931 SetLastExceptionMsg();
4933 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4936 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4940 if (nAction
== LOK_WINDOW_CLOSE
)
4942 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
4944 else if (FloatingWindow
* pFloatWin
= dynamic_cast<FloatingWindow
*>(pWindow
.get()))
4945 pFloatWin
->EndPopupMode(FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
);
4947 else if (nAction
== LOK_WINDOW_PASTE
)
4950 css::uno::Sequence
<sal_Int8
> aData
;
4951 std::vector
<beans::PropertyValue
> aArgs(jsonToPropertyValuesVector(pData
));
4953 aArgs
.size() == 2 &&
4954 aArgs
[0].Name
== "MimeType" && (aArgs
[0].Value
>>= aMimeType
) &&
4955 aArgs
[1].Name
== "Data" && (aArgs
[1].Value
>>= aData
);
4958 if (!aMimeType
.isEmpty() && aData
.hasElements())
4960 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(aMimeType
, aData
));
4961 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(new LOKClipboard
);
4962 xClipboard
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
4963 pWindow
->SetClipboard(xClipboard
);
4965 KeyEvent
aEvent(0, KEY_PASTE
, 0);
4966 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
4969 SetLastExceptionMsg("Window command 'paste': wrong parameters.");
4973 // CERTIFICATE AND DOCUMENT SIGNING
4974 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
4975 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
,
4976 const unsigned char* pPrivateKeyBinary
, const int nPrivateKeySize
)
4978 comphelper::ProfileZone
aZone("doc_insertCertificate");
4983 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4985 if (!pDocument
->mxComponent
.is())
4988 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
4992 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
4997 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
4998 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
4999 if (!xSecurityContext
.is())
5002 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
5003 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
5005 if (!xCertificateCreator
.is())
5008 uno::Sequence
<sal_Int8
> aCertificateSequence
;
5010 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
5011 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
5012 if (!aCertificateBase64String
.empty())
5014 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
5015 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
5019 aCertificateSequence
.realloc(nCertificateBinarySize
);
5020 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
5023 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
5024 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeySize
);
5025 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
5026 if (!aPrivateKeyBase64String
.empty())
5028 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
5029 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
5033 aPrivateKeySequence
.realloc(nPrivateKeySize
);
5034 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeySize
, aPrivateKeySequence
.begin());
5037 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
5039 if (!xCertificate
.is())
5042 SolarMutexGuard aGuard
;
5044 return pObjectShell
->SignDocumentContentUsingCertificate(xCertificate
);
5047 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
5048 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
)
5050 comphelper::ProfileZone
aZone("doc_addCertificate");
5055 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5057 if (!pDocument
->mxComponent
.is())
5060 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
5064 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
5069 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
5070 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
5071 if (!xSecurityContext
.is())
5074 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
5075 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
5077 if (!xCertificateCreator
.is())
5080 uno::Sequence
<sal_Int8
> aCertificateSequence
;
5082 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
5083 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
5084 if (!aCertificateBase64String
.empty())
5086 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
5087 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
5091 aCertificateSequence
.realloc(nCertificateBinarySize
);
5092 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
5095 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->addDERCertificateToTheDatabase(aCertificateSequence
, "TCu,Cu,Tu");
5097 if (!xCertificate
.is())
5100 SAL_INFO("lok", "Certificate Added = IssuerName: " << xCertificate
->getIssuerName() << " SubjectName: " << xCertificate
->getSubjectName());
5105 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
)
5107 comphelper::ProfileZone
aZone("doc_getSignatureState");
5109 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5111 if (!pDocument
->mxComponent
.is())
5112 return int(SignatureState::UNKNOWN
);
5114 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
5116 return int(SignatureState::UNKNOWN
);
5118 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
5120 return int(SignatureState::UNKNOWN
);
5122 SolarMutexGuard aGuard
;
5124 pObjectShell
->RecheckSignature(false);
5126 return int(pObjectShell
->GetDocumentSignatureState());
5129 static void doc_resizeWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
,
5130 const int nWidth
, const int nHeight
)
5132 SolarMutexGuard aGuard
;
5134 gImpl
->maLastExceptionMsg
.clear();
5136 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5139 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog resizing, or window not found.";
5143 pWindow
->SetSizePixel(Size(nWidth
, nHeight
));
5146 static char* lo_getError (LibreOfficeKit
*pThis
)
5148 comphelper::ProfileZone
aZone("lo_getError");
5150 SolarMutexGuard aGuard
;
5152 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5153 return convertOUString(pLib
->maLastExceptionMsg
);
5156 static void lo_freeError(char* pFree
)
5161 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
)
5163 SolarMutexGuard aGuard
;
5164 SetLastExceptionMsg();
5166 LibLibreOffice_Impl
* pImpl
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5168 if (!xSFactory
.is())
5169 xSFactory
= comphelper::getProcessServiceFactory();
5171 if (!xSFactory
.is())
5173 pImpl
->maLastExceptionMsg
= "Service factory is not available";
5177 uno::Reference
<container::XNameAccess
> xTypeDetection(xSFactory
->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY
);
5178 const uno::Sequence
<OUString
> aTypes
= xTypeDetection
->getElementNames();
5179 boost::property_tree::ptree aTree
;
5180 for (const OUString
& rType
: aTypes
)
5182 uno::Sequence
<beans::PropertyValue
> aValues
;
5183 if (xTypeDetection
->getByName(rType
) >>= aValues
)
5185 auto it
= std::find_if(aValues
.begin(), aValues
.end(), [](const beans::PropertyValue
& rValue
) { return rValue
.Name
== "MediaType"; });
5187 if (it
!= aValues
.end() && (it
->Value
>>= aValue
) && !aValue
.isEmpty())
5189 boost::property_tree::ptree aChild
;
5190 aChild
.put("MediaType", aValue
.toUtf8());
5191 aTree
.add_child(rType
.toUtf8().getStr(), aChild
);
5195 std::stringstream aStream
;
5196 boost::property_tree::write_json(aStream
, aTree
);
5197 return strdup(aStream
.str().c_str());
5200 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long const features
)
5202 comphelper::ProfileZone
aZone("lo_setOptionalFeatures");
5204 SolarMutexGuard aGuard
;
5205 SetLastExceptionMsg();
5207 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5208 pLib
->mOptionalFeatures
= features
;
5209 if (features
& LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK
)
5210 comphelper::LibreOfficeKit::setPartInInvalidation(true);
5211 if (features
& LOK_FEATURE_NO_TILED_ANNOTATIONS
)
5212 comphelper::LibreOfficeKit::setTiledAnnotations(false);
5213 if (features
& LOK_FEATURE_RANGE_HEADERS
)
5214 comphelper::LibreOfficeKit::setRangeHeaders(true);
5215 if (features
& LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK
)
5216 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
5219 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
5220 const char* pURL
, const char* pPassword
)
5222 comphelper::ProfileZone
aZone("lo_setDocumentPassword");
5224 SolarMutexGuard aGuard
;
5225 SetLastExceptionMsg();
5229 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5230 assert(pLib
->mInteractionMap
.find(OString(pURL
)) != pLib
->mInteractionMap
.end());
5231 pLib
->mInteractionMap
.find(OString(pURL
))->second
->SetPassword(pPassword
);
5234 static char* lo_getVersionInfo(SAL_UNUSED_PARAMETER LibreOfficeKit
* /*pThis*/)
5236 SetLastExceptionMsg();
5237 const OUString
sVersionStrTemplate(
5239 "\"ProductName\": \"%PRODUCTNAME\", "
5240 "\"ProductVersion\": \"%PRODUCTVERSION\", "
5241 "\"ProductExtension\": \"%PRODUCTEXTENSION\", "
5242 "\"BuildId\": \"%BUILDID\" "
5245 return convertOUString(ReplaceStringHookProc(sVersionStrTemplate
));
5248 static void force_c_locale()
5250 // force locale (and resource files loaded) to en-US
5251 OUString
aLangISO("en-US");
5252 SvtSysLocaleOptions aLocalOptions
;
5253 aLocalOptions
.SetLocaleConfigString(aLangISO
);
5254 aLocalOptions
.SetUILocaleConfigString(aLangISO
);
5257 static void aBasicErrorFunc(const OUString
& rError
, const OUString
& rAction
)
5259 OString aBuffer
= "Unexpected dialog: " +
5260 OUStringToOString(rAction
, RTL_TEXTENCODING_ASCII_US
) +
5262 OUStringToOString(rError
, RTL_TEXTENCODING_ASCII_US
);
5264 fprintf(stderr
, "Unexpected basic error dialog '%s'\n", aBuffer
.getStr());
5267 static bool initialize_uno(const OUString
& aAppProgramURL
)
5270 // For iOS we already hardcode the inifile as "rc" in the .app directory.
5271 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("fundamental"));
5272 xContext
= cppu::defaultBootstrap_InitialComponentContext(aAppProgramURL
+ "/rc");
5273 #elif defined MACOSX
5274 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/../Resources/" SAL_CONFIGFILE("soffice"));
5275 xContext
= cppu::defaultBootstrap_InitialComponentContext();
5277 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("soffice"));
5278 xContext
= cppu::defaultBootstrap_InitialComponentContext();
5283 SetLastExceptionMsg("XComponentContext could not be created");
5284 SAL_INFO("lok", "XComponentContext could not be created");
5288 xFactory
= xContext
->getServiceManager();
5291 SetLastExceptionMsg("XMultiComponentFactory could not be created");
5292 SAL_INFO("lok", "XMultiComponentFactory could not be created");
5296 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
5297 comphelper::setProcessServiceFactory(xSFactory
);
5299 SAL_INFO("lok", "Uno initialized - " << xContext
.is());
5301 // set UserInstallation to user profile dir in test/user-template
5302 // rtl::Bootstrap aDefaultVars;
5303 // aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
5304 // configmgr setup ?
5309 // pre-unipoll version.
5310 static void lo_startmain(void*)
5312 osl_setThreadName("lo_startmain");
5314 if (comphelper::SolarMutex::get())
5315 Application::GetSolarMutex().tryToAcquire();
5317 Application::UpdateMainThread();
5321 Application::ReleaseSolarMutex();
5325 static void lo_runLoop(LibreOfficeKit
* /*pThis*/,
5326 LibreOfficeKitPollCallback pPollCallback
,
5327 LibreOfficeKitWakeCallback pWakeCallback
,
5330 #if defined(IOS) || defined(ANDROID)
5331 Application::GetSolarMutex().acquire();
5335 SolarMutexGuard aGuard
;
5337 vcl::lok::registerPollCallbacks(pPollCallback
, pWakeCallback
, pData
);
5338 Application::UpdateMainThread();
5341 #if defined(IOS) || defined(ANDROID)
5342 vcl::lok::unregisterPollCallbacks();
5343 Application::ReleaseSolarMutex();
5347 static bool bInitialized
= false;
5349 static void lo_status_indicator_callback(void *data
, comphelper::LibreOfficeKit::statusIndicatorCallbackType type
, int percent
)
5351 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(data
);
5353 if (!pLib
->mpCallback
)
5358 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start
:
5359 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START
, nullptr, pLib
->mpCallbackData
);
5361 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue
:
5362 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
,
5363 OUString(OUString::number(percent
)).toUtf8().getStr(), pLib
->mpCallbackData
);
5365 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Finish
:
5366 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH
, nullptr, pLib
->mpCallbackData
);
5371 /// Used only by LibreOfficeKit when used by Online to pre-initialize
5372 static void preloadData()
5374 comphelper::ProfileZone
aZone("preload data");
5376 // Create user profile in the temp directory for loading the dictionaries
5378 rtl::Bootstrap::get("UserInstallation", sUserPath
);
5379 utl::TempFile
aTempDir(nullptr, true);
5380 aTempDir
.EnableKillingFile();
5381 rtl::Bootstrap::set("UserInstallation", aTempDir
.GetURL());
5383 // Register the bundled extensions
5384 desktop::Desktop::SynchronizeExtensionRepositories(true);
5385 bool bAbort
= desktop::Desktop::CheckExtensionDependencies();
5387 std::cerr
<< "CheckExtensionDependencies failed" << std::endl
;
5389 // preload all available dictionaries
5390 css::uno::Reference
<css::linguistic2::XLinguServiceManager
> xLngSvcMgr
=
5391 css::linguistic2::LinguServiceManager::create(comphelper::getProcessComponentContext());
5392 css::uno::Reference
<linguistic2::XSpellChecker
> xSpellChecker(xLngSvcMgr
->getSpellChecker());
5394 std::cerr
<< "Preloading dictionaries: ";
5395 css::uno::Reference
<linguistic2::XSupportedLocales
> xSpellLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
5396 uno::Sequence
< css::lang::Locale
> aLocales
= xSpellLocales
->getLocales();
5397 for (auto &it
: aLocales
)
5399 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
5400 css::beans::PropertyValues aNone
;
5401 xSpellChecker
->isValid("forcefed", it
, aNone
);
5405 // preload all available thesauri
5406 css::uno::Reference
<linguistic2::XThesaurus
> xThesaurus(xLngSvcMgr
->getThesaurus());
5407 css::uno::Reference
<linguistic2::XSupportedLocales
> xThesLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
5408 aLocales
= xThesLocales
->getLocales();
5409 std::cerr
<< "Preloading thesauri: ";
5410 for (auto &it
: aLocales
)
5412 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
5413 css::beans::PropertyValues aNone
;
5414 xThesaurus
->queryMeanings("forcefed", it
, aNone
);
5418 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
= css::ui::GlobalAcceleratorConfiguration::create(
5419 comphelper::getProcessComponentContext());
5420 xGlobalCfg
->getAllKeyEvents();
5422 std::cerr
<< "Preload icons\n";
5423 ImageTree
&images
= ImageTree::get();
5424 images
.getImageUrl("forcefed.png", "style", "FO_oo");
5426 std::cerr
<< "Preload languages\n";
5428 // force load language singleton
5429 SvtLanguageTable::HasLanguageType(LANGUAGE_SYSTEM
);
5430 (void)LanguageTag::isValidBcp47("foo", nullptr);
5432 std::cerr
<< "Preload fonts\n";
5434 // Initialize fonts.
5435 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
5438 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
5440 aLocales
= xSpell
->getLocales();
5443 for (const auto& aLocale
: std::as_const(aLocales
))
5445 //TODO: Add more types and cache more aggressively. For now this initializes the fontcache.
5446 using namespace ::com::sun::star::i18n::ScriptType
;
5448 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), LATIN
);
5449 OutputDevice::GetDefaultFont(DefaultFontType::LATIN_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
5450 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), ASIAN
);
5451 OutputDevice::GetDefaultFont(DefaultFontType::CJK_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
5452 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), COMPLEX
);
5453 OutputDevice::GetDefaultFont(DefaultFontType::CTL_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
5456 // Set user profile's path back to the original one
5457 rtl::Bootstrap::set("UserInstallation", sUserPath
);
5460 class ProfileZoneDumper
: public AutoTimer
5462 static const int dumpTimeoutMS
= 5000;
5464 ProfileZoneDumper() : AutoTimer( "zone dumper" )
5466 SetTimeout(dumpTimeoutMS
);
5469 virtual void Invoke() override
5471 const css::uno::Sequence
<OUString
> aEvents
=
5472 comphelper::ProfileRecording::getRecordingAndClear();
5473 OStringBuffer aOutput
;
5474 for (const auto &s
: aEvents
)
5476 aOutput
.append(OUStringToOString(s
, RTL_TEXTENCODING_UTF8
));
5477 aOutput
.append("\n");
5479 OString aChunk
= aOutput
.makeStringAndClear();
5480 if (gImpl
&& gImpl
->mpCallback
)
5481 gImpl
->mpCallback(LOK_CALLBACK_PROFILE_FRAME
, aChunk
.getStr(), gImpl
->mpCallbackData
);
5485 static int lo_initialize(LibreOfficeKit
* pThis
, const char* pAppPath
, const char* pUserProfileUrl
)
5488 PRE_INIT
, // setup shared data in master process
5489 SECOND_INIT
, // complete init. after fork
5490 FULL_INIT
// do a standard complete init.
5493 // Did we do a pre-initialize
5494 static bool bPreInited
= false;
5495 static bool bUnipoll
= false;
5496 static bool bProfileZones
= false;
5498 { // cf. string lifetime for preinit
5499 std::vector
<OUString
> aOpts
;
5501 // ':' delimited options - avoiding ABI change for new parameters
5502 const char *pOptions
= getenv("SAL_LOK_OPTIONS");
5504 aOpts
= comphelper::string::split(OUString(pOptions
, strlen(pOptions
), RTL_TEXTENCODING_UTF8
), ':');
5505 for (const auto &it
: aOpts
)
5507 if (it
== "unipoll")
5509 else if (it
== "profile_events")
5510 bProfileZones
= true;
5511 else if (it
== "sc_no_grid_bg")
5512 comphelper::LibreOfficeKit::setCompatFlag(
5513 comphelper::LibreOfficeKit::Compat::scNoGridBackground
);
5517 // What stage are we at ?
5518 if (pThis
== nullptr)
5520 else if (bPreInited
)
5521 eStage
= SECOND_INIT
;
5525 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5530 // Turn profile zones on early
5531 if (bProfileZones
&& eStage
== SECOND_INIT
)
5533 comphelper::ProfileRecording::startRecording(true);
5534 new ProfileZoneDumper();
5537 comphelper::ProfileZone
aZone("lok-init");
5539 if (eStage
== PRE_INIT
)
5540 rtl_alloc_preInit(true);
5541 else if (eStage
== SECOND_INIT
)
5542 rtl_alloc_preInit(false);
5544 if (eStage
!= SECOND_INIT
)
5545 comphelper::LibreOfficeKit::setActive();
5547 if (eStage
!= PRE_INIT
)
5548 comphelper::LibreOfficeKit::setStatusIndicatorCallback(lo_status_indicator_callback
, pLib
);
5550 if (pUserProfileUrl
&& eStage
!= PRE_INIT
)
5553 pUserProfileUrl
, strlen(pUserProfileUrl
), RTL_TEXTENCODING_UTF8
);
5555 if (url
.startsWithIgnoreAsciiCase("vnd.sun.star.pathname:", &path
))
5558 osl::FileBase::RC e
= osl::FileBase::getFileURLFromSystemPath(
5560 if (e
== osl::FileBase::E_None
)
5563 SAL_WARN("lok", "resolving <" << url
<< "> failed with " << +e
);
5565 rtl::Bootstrap::set("UserInstallation", url
);
5566 if (eStage
== SECOND_INIT
)
5567 utl::Bootstrap::reloadData();
5573 aAppPath
= OUString(pAppPath
, strlen(pAppPath
), RTL_TEXTENCODING_UTF8
);
5578 aAppPath
= OUString::fromUtf8(lo_get_app_data_dir()) + "/program";
5580 // Fun conversion dance back and forth between URLs and system paths...
5582 ::osl::Module::getUrlFromAddress( reinterpret_cast< oslGenericFunction
>(lo_initialize
),
5584 osl::FileBase::getSystemPathFromFileURL( aAppURL
, aAppPath
);
5588 // The above gives something like
5589 // "/private/var/containers/Bundle/Application/953AA851-CC15-4C60-A2CB-C2C6F24E6F71/Foo.app/Foo",
5590 // and we want to drop the final component (the binary name).
5591 sal_Int32 lastSlash
= aAppPath
.lastIndexOf('/');
5592 assert(lastSlash
> 0);
5593 aAppPath
= aAppPath
.copy(0, lastSlash
);
5598 if (osl::FileBase::getFileURLFromSystemPath(aAppPath
, aAppURL
) != osl::FileBase::E_None
)
5602 // A LibreOffice-using iOS app should have the ICU data file in the app bundle. Initialize ICU
5604 NSString
*bundlePath
= [[NSBundle mainBundle
] bundlePath
];
5606 int fd
= open([[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
], O_RDONLY
);
5608 NSLog(@
"Could not open ICU data file %s", [[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
]);
5612 if (fstat(fd
, &st
) == -1)
5613 NSLog(@
"fstat on ICU data file failed: %s", strerror(errno
));
5616 void *icudata
= mmap(0, (size_t) st
.st_size
, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
5617 if (icudata
== MAP_FAILED
)
5618 NSLog(@
"mmap failed: %s", strerror(errno
));
5621 UErrorCode icuStatus
= U_ZERO_ERROR
;
5622 udata_setCommonData(icudata
, &icuStatus
);
5623 if (U_FAILURE(icuStatus
))
5624 NSLog(@
"udata_setCommonData failed");
5627 // Quick test that ICU works...
5628 UConverter
*cnv
= ucnv_open("iso-8859-3", &icuStatus
);
5629 if (U_SUCCESS(icuStatus
))
5632 NSLog(@
"ucnv_open() failed: %s", u_errorName(icuStatus
));
5642 if (eStage
!= SECOND_INIT
)
5644 SAL_INFO("lok", "Attempting to initialize UNO");
5646 if (!initialize_uno(aAppURL
))
5649 // Force headless -- this is only for bitmap rendering.
5650 rtl::Bootstrap::set("SAL_USE_VCLPLUGIN", "svp");
5652 // We specifically need to make sure we have the "headless"
5653 // command arg set (various code specifically checks via
5654 // CommandLineArgs):
5655 desktop::Desktop::GetCommandLineArgs().setHeadless();
5658 if (InitVCL() && [NSThread isMainThread
])
5660 static bool bFirstTime
= true;
5663 Application::GetSolarMutex().release();
5667 SfxApplication::GetOrCreate();
5670 if (eStage
== PRE_INIT
)
5673 comphelper::ProfileZone
aInit("Init vcl");
5674 std::cerr
<< "Init vcl\n";
5678 // pre-load all graphic libraries.
5679 GraphicFilter::GetGraphicFilter().preload();
5681 // pre-load all component libraries.
5683 throw css::uno::DeploymentException("preInit: XComponentContext is not created");
5685 css::uno::Reference
< css::uno::XInterface
> xService
;
5686 xContext
->getValueByName("/singletons/com.sun.star.lang.theServiceManager") >>= xService
;
5688 throw css::uno::DeploymentException("preInit: XMultiComponentFactory is not created");
5690 css::uno::Reference
<css::lang::XInitialization
> aService(
5691 xService
, css::uno::UNO_QUERY_THROW
);
5694 // In order to load implementations and invoke
5695 // component factory it is required:
5696 // 1) defaultBootstrap_InitialComponentContext()
5697 // 2) comphelper::setProcessServiceFactory(xSFactory);
5700 comphelper::ProfileZone
aInit("preload");
5701 aService
->initialize({css::uno::makeAny
<OUString
>("preload")});
5703 { // Force load some modules
5704 comphelper::ProfileZone
aInit("preload modules");
5705 VclBuilder::preload();
5706 VclAbstractDialogFactory::Create();
5711 // Release Solar Mutex, lo_startmain thread should acquire it.
5712 Application::ReleaseSolarMutex();
5718 if (eStage
!= PRE_INIT
)
5720 SAL_INFO("lok", "Re-initialize temp paths");
5721 SvtPathOptions aOptions
;
5723 osl::FileBase::getTempDirURL(aNewTemp
);
5724 aOptions
.SetTempPath(aNewTemp
);
5725 desktop::Desktop::CreateTemporaryDirectory();
5727 // The RequestHandler is specifically set to be ready when all the other
5728 // init in Desktop::Main (run from soffice_main) is done. We can enable
5729 // the RequestHandler here (without starting any IPC thread;
5730 // shortcutting the invocation in Desktop::Main that would start the IPC
5731 // thread), and can then use it to wait until we're definitely ready to
5734 SAL_INFO("lok", "Enabling RequestHandler");
5735 RequestHandler::Enable(false);
5736 SAL_INFO("lok", "Starting soffice_main");
5737 RequestHandler::SetReady(false);
5740 // Start the main thread only in non-unipoll mode (i.e. multithreaded).
5741 pLib
->maThread
= osl_createThread(lo_startmain
, nullptr);
5742 SAL_INFO("lok", "Waiting for RequestHandler");
5743 RequestHandler::WaitForReady();
5744 SAL_INFO("lok", "RequestHandler ready -- continuing");
5750 if (eStage
!= SECOND_INIT
)
5751 ErrorRegistry::RegisterDisplay(aBasicErrorFunc
);
5753 SAL_INFO("lok", "LOK Initialized");
5754 if (eStage
== PRE_INIT
)
5757 bInitialized
= true;
5759 catch (css::uno::Exception
& exception
)
5761 fprintf(stderr
, "Bootstrapping exception '%s'\n",
5762 OUStringToOString(exception
.Message
, RTL_TEXTENCODING_UTF8
).getStr());
5765 if (eStage
== PRE_INIT
)
5767 comphelper::ThreadPool::getSharedOptimalPool().shutdown();
5770 // Turn off quick editing on IOS and ANDROID
5771 #if defined IOS || defined ANDROID
5772 if (officecfg::Office::Impress::Misc::TextObject::QuickEditing::get())
5774 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
5775 officecfg::Office::Impress::Misc::TextObject::QuickEditing::set(false, batch
);
5780 return bInitialized
;
5784 LibreOfficeKit
*libreofficekit_hook_2(const char* install_path
, const char* user_profile_url
)
5788 SAL_INFO("lok", "Create libreoffice object");
5790 gImpl
= new LibLibreOffice_Impl();
5791 if (!lo_initialize(gImpl
, install_path
, user_profile_url
))
5796 return static_cast<LibreOfficeKit
*>(gImpl
);
5800 LibreOfficeKit
*libreofficekit_hook(const char* install_path
)
5802 return libreofficekit_hook_2(install_path
, nullptr);
5806 int lok_preinit(const char* install_path
, const char* user_profile_url
)
5808 return lo_initialize(nullptr, install_path
, user_profile_url
);
5811 static void lo_destroy(LibreOfficeKit
* pThis
)
5813 SolarMutexClearableGuard aGuard
;
5815 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5818 SAL_INFO("lok", "LO Destroy");
5820 comphelper::LibreOfficeKit::setStatusIndicatorCallback(nullptr, nullptr);
5821 uno::Reference
<frame::XDesktop2
> xDesktop
= frame::Desktop::create ( ::comphelper::getProcessComponentContext() );
5822 // FIXME: the terminate() call here is a no-op because it detects
5823 // that LibreOfficeKit::isActive() and then returns early!
5824 bool bSuccess
= xDesktop
.is() && xDesktop
->terminate();
5828 bSuccess
= GetpApp() && GetpApp()->QueryExit();
5833 Application::Quit();
5838 osl_joinWithThread(pLib
->maThread
);
5839 osl_destroyThread(pLib
->maThread
);
5842 bInitialized
= false;
5843 SAL_INFO("lok", "LO Destroy Done");
5848 // Used by the unmaintained LibreOfficeLight app. Once that has been retired, get rid of this, too.
5850 __attribute__((visibility("default")))
5851 void temporaryHackToInvokeCallbackHandlers(LibreOfficeKitDocument
* pThis
)
5853 SolarMutexGuard aGuard
;
5854 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5856 int nOrigViewId
= doc_getView(pThis
);
5858 if (nOrigViewId
>= 0 && pDocument
->mpCallbackFlushHandlers
[nOrigViewId
])
5860 pDocument
->mpCallbackFlushHandlers
[nOrigViewId
]->Invoke();
5868 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */