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_features.h>
11 #include <config_folders.h>
20 #include <unicode/udata.h>
21 #include <unicode/ucnv.h>
23 #import <Foundation/Foundation.h>
24 #import <CoreGraphics/CoreGraphics.h>
29 #include <osl/detail/android-bootstrap.h>
35 #include <boost/property_tree/json_parser.hpp>
36 #include <boost/algorithm/string.hpp>
38 #include <LibreOfficeKit/LibreOfficeKit.h>
39 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
41 #include <sal/log.hxx>
42 #include <vcl/errinf.hxx>
43 #include <vcl/lok.hxx>
44 #include <osl/file.hxx>
45 #include <osl/process.h>
46 #include <osl/thread.h>
47 #include <rtl/bootstrap.hxx>
48 #include <rtl/strbuf.hxx>
49 #include <rtl/uri.hxx>
50 #include <cppuhelper/bootstrap.hxx>
51 #include <comphelper/base64.hxx>
52 #include <comphelper/dispatchcommand.hxx>
53 #include <comphelper/lok.hxx>
54 #include <comphelper/processfactory.hxx>
55 #include <comphelper/string.hxx>
56 #include <comphelper/profilezone.hxx>
57 #include <comphelper/propertysequence.hxx>
58 #include <comphelper/scopeguard.hxx>
59 #include <comphelper/threadpool.hxx>
61 #include <com/sun/star/beans/XPropertySet.hpp>
62 #include <com/sun/star/container/XNameAccess.hpp>
63 #include <com/sun/star/frame/Desktop.hpp>
64 #include <com/sun/star/frame/DispatchResultEvent.hpp>
65 #include <com/sun/star/frame/DispatchResultState.hpp>
66 #include <com/sun/star/frame/XDispatchProvider.hpp>
67 #include <com/sun/star/frame/XDispatchResultListener.hpp>
68 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
69 #include <com/sun/star/frame/XStorable.hpp>
70 #include <com/sun/star/lang/Locale.hpp>
71 #include <com/sun/star/lang/XComponent.hpp>
72 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
73 #include <com/sun/star/reflection/theCoreReflection.hpp>
74 #include <com/sun/star/reflection/XIdlClass.hpp>
75 #include <com/sun/star/reflection/XIdlReflection.hpp>
76 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
77 #include <com/sun/star/ucb/XContentProvider.hpp>
78 #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
79 #include <com/sun/star/util/URLTransformer.hpp>
80 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
81 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
82 #include <com/sun/star/datatransfer/XTransferable2.hpp>
83 #include <com/sun/star/text/TextContentAnchorType.hpp>
84 #include <com/sun/star/document/XRedlinesSupplier.hpp>
85 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
87 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
88 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
89 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
90 #include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
91 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
92 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
93 #include <com/sun/star/security/XCertificate.hpp>
95 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
96 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
97 #include <com/sun/star/i18n/ScriptType.hpp>
98 #include <com/sun/star/lang/DisposedException.hpp>
100 #include <editeng/fontitem.hxx>
101 #include <editeng/flstitem.hxx>
102 #include <sfx2/app.hxx>
103 #include <sfx2/objsh.hxx>
104 #include <sfx2/viewsh.hxx>
105 #include <sfx2/viewfrm.hxx>
106 #include <sfx2/msgpool.hxx>
107 #include <sfx2/dispatch.hxx>
108 #include <sfx2/lokcharthelper.hxx>
109 #include <sfx2/DocumentSigner.hxx>
110 #include <svx/dialmgr.hxx>
111 #include <svx/dialogs.hrc>
112 #include <svx/strings.hrc>
113 #include <svx/ruler.hxx>
114 #include <svx/svdview.hxx>
115 #include <svx/svxids.hrc>
116 #include <svx/ucsubset.hxx>
117 #include <vcl/vclevent.hxx>
118 #include <vcl/GestureEvent.hxx>
119 #include <vcl/svapp.hxx>
120 #include <unotools/resmgr.hxx>
121 #include <tools/fract.hxx>
122 #include <svtools/ctrltool.hxx>
123 #include <svtools/langtab.hxx>
124 #include <vcl/floatwin.hxx>
125 #include <vcl/fontcharmap.hxx>
126 #include <vcl/graphicfilter.hxx>
127 #include <vcl/ptrstyle.hxx>
128 #include <vcl/sysdata.hxx>
129 #include <vcl/virdev.hxx>
130 #include <vcl/ImageTree.hxx>
131 #include <vcl/ITiledRenderable.hxx>
132 #include <vcl/IDialogRenderable.hxx>
133 #include <vcl/dialog.hxx>
134 #include <unicode/uchar.h>
135 #include <unotools/configmgr.hxx>
136 #include <unotools/syslocaleoptions.hxx>
137 #include <unotools/mediadescriptor.hxx>
138 #include <unotools/pathoptions.hxx>
139 #include <unotools/tempfile.hxx>
140 #include <unotools/streamwrap.hxx>
141 #include <osl/module.hxx>
142 #include <comphelper/sequence.hxx>
143 #include <sfx2/sfxbasemodel.hxx>
144 #include <svl/undo.hxx>
145 #include <unotools/datetime.hxx>
146 #include <i18nlangtag/mslangid.hxx>
147 #include <i18nlangtag/languagetag.hxx>
148 #include <vcl/builder.hxx>
149 #include <vcl/abstdlg.hxx>
150 #include <tools/diagnose_ex.h>
151 #include <vcl/uitest/uiobject.hxx>
155 #include "../app/cmdlineargs.hxx"
156 // We also need to hackily be able to start the main libreoffice thread:
157 #include "../app/sofficemain.h"
158 #include "../app/officeipcthread.hxx"
159 #include <lib/init.hxx>
161 #include "lokinteractionhandler.hxx"
162 #include "lokclipboard.hxx"
163 #include <officecfg/Office/Impress.hxx>
167 using namespace desktop
;
170 static LibLibreOffice_Impl
*gImpl
= nullptr;
171 static std::weak_ptr
< LibreOfficeKitClass
> gOfficeClass
;
172 static std::weak_ptr
< LibreOfficeKitDocumentClass
> gDocumentClass
;
174 static void SetLastExceptionMsg(const OUString
& s
= OUString())
176 SAL_WARN_IF(!s
.isEmpty(), "lok", "lok exception '" + s
+ "'");
178 gImpl
->maLastExceptionMsg
= s
;
186 const char *filterName
;
191 static const ExtensionMap aWriterExtensionMap
[] =
193 { "doc", "MS Word 97" },
194 { "docm", "MS Word 2007 XML VBA" },
195 { "docx", "MS Word 2007 XML" },
196 { "fodt", "OpenDocument Text Flat XML" },
197 { "html", "HTML (StarWriter)" },
198 { "odt", "writer8" },
199 { "ott", "writer8_template" },
200 { "pdf", "writer_pdf_Export" },
202 { "rtf", "Rich Text Format" },
204 { "xhtml", "XHTML Writer File" },
205 { "png", "writer_png_Export" },
209 static const ExtensionMap aCalcExtensionMap
[] =
211 { "csv", "Text - txt - csv (StarCalc)" },
212 { "fods", "OpenDocument Spreadsheet Flat XML" },
213 { "html", "HTML (StarCalc)" },
215 { "ots", "calc8_template" },
216 { "pdf", "calc_pdf_Export" },
217 { "xhtml", "XHTML Calc File" },
218 { "xls", "MS Excel 97" },
219 { "xlsm", "Calc MS Excel 2007 VBA XML" },
220 { "xlsx", "Calc MS Excel 2007 XML" },
221 { "png", "calc_png_Export" },
225 static const ExtensionMap aImpressExtensionMap
[] =
227 { "fodp", "OpenDocument Presentation Flat XML" },
228 { "html", "impress_html_Export" },
229 { "odg", "impress8_draw" },
230 { "odp", "impress8" },
231 { "otp", "impress8_template" },
232 { "pdf", "impress_pdf_Export" },
233 { "potm", "Impress MS PowerPoint 2007 XML Template" },
234 { "pot", "MS PowerPoint 97 Vorlage" },
235 { "pptm", "Impress MS PowerPoint 2007 XML VBA" },
236 { "pptx", "Impress MS PowerPoint 2007 XML" },
237 { "pps", "MS PowerPoint 97 Autoplay" },
238 { "ppt", "MS PowerPoint 97" },
239 { "svg", "impress_svg_Export" },
240 { "swf", "impress_flash_Export" },
241 { "xhtml", "XHTML Impress File" },
242 { "png", "impress_png_Export"},
246 static const ExtensionMap aDrawExtensionMap
[] =
248 { "fodg", "draw_ODG_FlatXML" },
249 { "html", "draw_html_Export" },
251 { "pdf", "draw_pdf_Export" },
252 { "svg", "draw_svg_Export" },
253 { "swf", "draw_flash_Export" },
254 { "xhtml", "XHTML Draw File" },
255 { "png", "draw_png_Export"},
259 static OUString
getUString(const char* pString
)
261 if (pString
== nullptr)
264 OString
sString(pString
, strlen(pString
));
265 return OStringToOUString(sString
, RTL_TEXTENCODING_UTF8
);
268 // Tolerate embedded \0s etc.
269 static char *convertOString(const OString
&rStr
)
271 char* pMemory
= static_cast<char*>(malloc(rStr
.getLength() + 1));
272 assert(pMemory
); // don't tolerate failed allocations.
273 memcpy(pMemory
, rStr
.getStr(), rStr
.getLength() + 1);
277 static char *convertOUString(const OUString
&aStr
)
279 return convertOString(OUStringToOString(aStr
, RTL_TEXTENCODING_UTF8
));
282 /// Try to convert a relative URL to an absolute one, unless it already looks like a URL.
283 static OUString
getAbsoluteURL(const char* pURL
)
285 OUString
aURL(getUString(pURL
));
289 // convert relative paths to absolute ones
290 OUString aWorkingDir
;
291 osl_getProcessWorkingDir(&aWorkingDir
.pData
);
292 if (!aWorkingDir
.endsWith("/"))
297 return rtl::Uri::convertRelToAbs(aWorkingDir
, aURL
);
299 catch (const rtl::MalformedUriException
&)
306 static uno::Any
jsonToUnoAny(const boost::property_tree::ptree
& aTree
)
311 uno::TypeClass aTypeClass
;
312 uno::Reference
< reflection::XIdlField
> aField
;
313 boost::property_tree::ptree aNodeNull
, aNodeValue
, aNodeField
;
314 const std::string
& rType
= aTree
.get
<std::string
>("type", "");
315 const std::string
& rValue
= aTree
.get
<std::string
>("value", "");
316 uno::Sequence
< uno::Reference
< reflection::XIdlField
> > aFields
;
317 uno::Reference
< reflection:: XIdlClass
> xIdlClass
=
318 css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())->forName(OUString::fromUtf8(rType
.c_str()));
321 aTypeClass
= xIdlClass
->getTypeClass();
322 xIdlClass
->createObject(aAny
);
323 aFields
= xIdlClass
->getFields();
324 nFields
= aFields
.getLength();
325 aNodeValue
= aTree
.get_child("value", aNodeNull
);
326 if (nFields
> 0 && aNodeValue
!= aNodeNull
)
328 for (sal_Int32 itField
= 0; itField
< nFields
; ++itField
)
330 aField
= aFields
[itField
];
331 aNodeField
= aNodeValue
.get_child(aField
->getName().toUtf8().getStr(), aNodeNull
);
332 if (aNodeField
!= aNodeNull
)
334 aValue
= jsonToUnoAny(aNodeField
);
335 aField
->set(aAny
, aValue
);
339 else if (!rValue
.empty())
341 if (aTypeClass
== uno::TypeClass_VOID
)
343 else if (aTypeClass
== uno::TypeClass_BYTE
)
344 aAny
<<= static_cast<sal_Int8
>(OString(rValue
.c_str()).toInt32());
345 else if (aTypeClass
== uno::TypeClass_BOOLEAN
)
346 aAny
<<= OString(rValue
.c_str()).toBoolean();
347 else if (aTypeClass
== uno::TypeClass_SHORT
)
348 aAny
<<= static_cast<sal_Int16
>(OString(rValue
.c_str()).toInt32());
349 else if (aTypeClass
== uno::TypeClass_UNSIGNED_SHORT
)
350 aAny
<<= static_cast<sal_uInt16
>(OString(rValue
.c_str()).toUInt32());
351 else if (aTypeClass
== uno::TypeClass_LONG
)
352 aAny
<<= OString(rValue
.c_str()).toInt32();
353 else if (aTypeClass
== uno::TypeClass_UNSIGNED_LONG
)
354 aAny
<<= static_cast<sal_uInt32
>(OString(rValue
.c_str()).toInt32());
355 else if (aTypeClass
== uno::TypeClass_FLOAT
)
356 aAny
<<= OString(rValue
.c_str()).toFloat();
357 else if (aTypeClass
== uno::TypeClass_DOUBLE
)
358 aAny
<<= OString(rValue
.c_str()).toDouble();
359 else if (aTypeClass
== uno::TypeClass_STRING
)
360 aAny
<<= OUString::fromUtf8(rValue
.c_str());
366 std::vector
<beans::PropertyValue
> desktop::jsonToPropertyValuesVector(const char* pJSON
)
368 std::vector
<beans::PropertyValue
> aArguments
;
369 if (pJSON
&& pJSON
[0] != '\0')
371 boost::property_tree::ptree aTree
, aNodeNull
, aNodeValue
;
372 std::stringstream
aStream(pJSON
);
373 boost::property_tree::read_json(aStream
, aTree
);
375 for (const auto& rPair
: aTree
)
377 const std::string
& rType
= rPair
.second
.get
<std::string
>("type", "");
378 const std::string
& rValue
= rPair
.second
.get
<std::string
>("value", "");
380 beans::PropertyValue aValue
;
381 aValue
.Name
= OUString::fromUtf8(rPair
.first
.c_str());
382 if (rType
== "string")
383 aValue
.Value
<<= OUString::fromUtf8(rValue
.c_str());
384 else if (rType
== "boolean")
385 aValue
.Value
<<= OString(rValue
.c_str()).toBoolean();
386 else if (rType
== "float")
387 aValue
.Value
<<= OString(rValue
.c_str()).toFloat();
388 else if (rType
== "long")
389 aValue
.Value
<<= OString(rValue
.c_str()).toInt32();
390 else if (rType
== "short")
391 aValue
.Value
<<= sal_Int16(OString(rValue
.c_str()).toInt32());
392 else if (rType
== "unsigned short")
393 aValue
.Value
<<= sal_uInt16(OString(rValue
.c_str()).toUInt32());
394 else if (rType
== "int64")
395 aValue
.Value
<<= OString(rValue
.c_str()).toInt64();
396 else if (rType
== "int32")
397 aValue
.Value
<<= OString(rValue
.c_str()).toInt32();
398 else if (rType
== "int16")
399 aValue
.Value
<<= sal_Int16(OString(rValue
.c_str()).toInt32());
400 else if (rType
== "uint64")
401 aValue
.Value
<<= OString(rValue
.c_str()).toUInt64();
402 else if (rType
== "uint32")
403 aValue
.Value
<<= OString(rValue
.c_str()).toUInt32();
404 else if (rType
== "uint16")
405 aValue
.Value
<<= sal_uInt16(OString(rValue
.c_str()).toUInt32());
406 else if (rType
== "[]byte")
408 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
409 if (aNodeValue
!= aNodeNull
&& aNodeValue
.size() == 0)
411 uno::Sequence
< sal_Int8
> aSeqByte(reinterpret_cast<const sal_Int8
*>(rValue
.c_str()), rValue
.size());
412 aValue
.Value
<<= aSeqByte
;
415 else if (rType
== "[]any")
417 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
418 if (aNodeValue
!= aNodeNull
&& !aNodeValue
.empty())
421 uno::Sequence
< uno::Any
> aSeq(aNodeValue
.size());
422 for (const auto& rSeqPair
: aNodeValue
)
423 aSeq
[itSeq
++] = jsonToUnoAny(rSeqPair
.second
);
424 aValue
.Value
<<= aSeq
;
428 SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled type '"<<rType
<<"'");
429 aArguments
.push_back(aValue
);
436 static StringMap
jsonToStringMap(const char* pJSON
)
439 if (pJSON
&& pJSON
[0] != '\0')
441 std::stringstream
aStream(pJSON
);
442 boost::property_tree::ptree aTree
;
443 boost::property_tree::read_json(aStream
, aTree
);
445 for (const auto& rPair
: aTree
)
447 aArgs
[OUString::fromUtf8(rPair
.first
.c_str())] = OUString::fromUtf8(rPair
.second
.get_value
<std::string
>(".").c_str());
454 static boost::property_tree::ptree
unoAnyToPropertyTree(const uno::Any
& anyItem
)
456 boost::property_tree::ptree aTree
;
457 OUString aType
= anyItem
.getValueTypeName();
458 aTree
.put("type", aType
.toUtf8().getStr());
460 if (aType
== "string")
461 aTree
.put("value", anyItem
.get
<OUString
>().toUtf8().getStr());
462 else if (aType
== "unsigned long")
463 aTree
.put("value", OString::number(anyItem
.get
<sal_uInt32
>()).getStr());
464 else if (aType
== "long")
465 aTree
.put("value", OString::number(anyItem
.get
<sal_Int32
>()).getStr());
466 else if (aType
== "[]any")
468 uno::Sequence
<uno::Any
> aSeq
;
469 if (anyItem
>>= aSeq
)
471 boost::property_tree::ptree aSubTree
;
473 for (auto i
= 0; i
< aSeq
.getLength(); ++i
)
475 aSubTree
.add_child(OString::number(i
).getStr(), unoAnyToPropertyTree(aSeq
[i
]));
477 aTree
.add_child("value", aSubTree
);
481 // TODO: Add more as required
488 RectangleAndPart
RectangleAndPart::Create(const std::string
& rPayload
)
490 RectangleAndPart aRet
;
491 if (rPayload
.compare(0, 5, "EMPTY") == 0) // payload starts with "EMPTY"
493 aRet
.m_aRectangle
= tools::Rectangle(0, 0, SfxLokHelper::MaxTwips
, SfxLokHelper::MaxTwips
);
494 if (comphelper::LibreOfficeKit::isPartInInvalidation())
495 aRet
.m_nPart
= std::stol(rPayload
.substr(6));
500 std::istringstream
aStream(rPayload
);
501 long nLeft
, nTop
, nWidth
, nHeight
;
502 long nPart
= INT_MIN
;
504 if (comphelper::LibreOfficeKit::isPartInInvalidation())
506 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
>> nComma
>> nPart
;
510 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
513 if (nWidth
> 0 && nHeight
> 0)
515 // The top-left corner starts at (0, 0).
516 // Anything negative is invalid.
529 if (nWidth
> 0 && nHeight
> 0)
531 aRet
.m_aRectangle
= tools::Rectangle(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
534 // else leave empty rect.
536 aRet
.m_nPart
= nPart
;
540 RectangleAndPart
& CallbackFlushHandler::CallbackData::setRectangleAndPart(const std::string
& payload
)
542 setRectangleAndPart(RectangleAndPart::Create(payload
));
544 // Return reference to the cached object.
545 return boost::get
<RectangleAndPart
>(PayloadObject
);
548 void CallbackFlushHandler::CallbackData::setRectangleAndPart(const RectangleAndPart
& rRectAndPart
)
550 PayloadString
= rRectAndPart
.toString().getStr();
551 PayloadObject
= rRectAndPart
;
554 const RectangleAndPart
& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
556 assert(PayloadObject
.which() == 1);
557 return boost::get
<RectangleAndPart
>(PayloadObject
);
560 boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::setJson(const std::string
& payload
)
562 boost::property_tree::ptree aTree
;
563 std::stringstream
aStream(payload
);
564 boost::property_tree::read_json(aStream
, aTree
);
566 // Let boost normalize the payload so it always matches the cache.
569 // Return reference to the cached object.
570 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
573 void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree
& rTree
)
575 std::stringstream aJSONStream
;
576 constexpr bool bPretty
= false; // Don't waste time and bloat logs.
577 boost::property_tree::write_json(aJSONStream
, rTree
, bPretty
);
578 PayloadString
= boost::trim_copy(aJSONStream
.str());
580 PayloadObject
= rTree
;
583 const boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::getJson() const
585 assert(PayloadObject
.which() == 2);
586 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
589 bool CallbackFlushHandler::CallbackData::validate() const
591 switch (PayloadObject
.which())
599 return getRectangleAndPart().toString().getStr() == PayloadString
;
604 std::stringstream aJSONStream
;
605 boost::property_tree::write_json(aJSONStream
, getJson(), false);
606 const std::string aExpected
= boost::trim_copy(aJSONStream
.str());
607 return aExpected
== PayloadString
;
611 assert(!"Unknown variant type; please add an entry to validate.");
621 bool lcl_isViewCallbackType(const int type
)
625 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
626 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
627 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
628 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
629 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
637 int lcl_getViewId(const std::string
& payload
)
639 // this is a cheap way how to get the viewId from a JSON message; proper
640 // parsing is terribly expensive, and we just need the viewId here
641 size_t viewIdPos
= payload
.find("viewId");
642 if (viewIdPos
== std::string::npos
)
645 size_t numberPos
= payload
.find(":", viewIdPos
+ 6);
646 if (numberPos
== std::string::npos
)
649 for (++numberPos
; numberPos
< payload
.length(); ++numberPos
)
651 if (payload
[numberPos
] == ',' || payload
[numberPos
] == '}' || (payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9'))
655 if (numberPos
< payload
.length() && payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9')
656 return strtol(payload
.substr(numberPos
).c_str(), nullptr, 10);
661 int lcl_getViewId(const desktop::CallbackFlushHandler::CallbackData
& rCallbackData
)
663 if (rCallbackData
.isCached())
664 return rCallbackData
.getJson().get
<int>("viewId");
665 return lcl_getViewId(rCallbackData
.PayloadString
);
668 std::string
extractCertificate(const std::string
& certificate
)
670 const std::string
header("-----BEGIN CERTIFICATE-----");
671 const std::string
footer("-----END CERTIFICATE-----");
675 size_t pos1
= certificate
.find(header
);
676 if (pos1
== std::string::npos
)
679 size_t pos2
= certificate
.find(footer
, pos1
+ 1);
680 if (pos2
== std::string::npos
)
683 pos1
= pos1
+ header
.length();
686 return certificate
.substr(pos1
, pos2
);
689 std::string
extractPrivateKey(const std::string
& privateKey
)
691 const std::string
header("-----BEGIN PRIVATE KEY-----");
692 const std::string
footer("-----END PRIVATE KEY-----");
696 size_t pos1
= privateKey
.find(header
);
697 if (pos1
== std::string::npos
)
700 size_t pos2
= privateKey
.find(footer
, pos1
+ 1);
701 if (pos2
== std::string::npos
)
704 pos1
= pos1
+ header
.length();
707 return privateKey
.substr(pos1
, pos2
);
710 } // end anonymous namespace
712 // Could be anonymous in principle, but for the unit testing purposes, we
713 // declare it in init.hxx.
714 OUString
desktop::extractParameter(OUString
& rOptions
, const OUString
& rName
)
718 OUString
aNameEquals(rName
+ "=");
719 OUString
aCommaNameEquals("," + rName
+ "=");
722 if (rOptions
.startsWith(aNameEquals
))
724 size_t nLen
= aNameEquals
.getLength();
725 int nComma
= rOptions
.indexOf(",", nLen
);
728 aValue
= rOptions
.copy(nLen
, nComma
- nLen
);
729 rOptions
= rOptions
.copy(nComma
+ 1);
733 aValue
= rOptions
.copy(nLen
);
737 else if ((nIndex
= rOptions
.indexOf(aCommaNameEquals
)) >= 0)
739 size_t nLen
= aCommaNameEquals
.getLength();
740 int nComma
= rOptions
.indexOf(",", nIndex
+ nLen
);
743 aValue
= rOptions
.copy(nIndex
+ nLen
, nComma
- nIndex
- nLen
);
744 rOptions
= rOptions
.copy(0, nIndex
) + rOptions
.copy(nComma
);
748 aValue
= rOptions
.copy(nIndex
+ nLen
);
749 rOptions
= rOptions
.copy(0, nIndex
);
759 static void doc_destroy(LibreOfficeKitDocument
* pThis
);
760 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* pUrl
, const char* pFormat
, const char* pFilterOptions
);
761 static int doc_getDocumentType(LibreOfficeKitDocument
* pThis
);
762 static int doc_getParts(LibreOfficeKitDocument
* pThis
);
763 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
);
764 static int doc_getPart(LibreOfficeKitDocument
* pThis
);
765 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
);
766 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
);
767 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
);
768 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
);
769 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
, int nPartMode
);
770 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
771 unsigned char* pBuffer
,
772 const int nCanvasWidth
, const int nCanvasHeight
,
773 const int nTilePosX
, const int nTilePosY
,
774 const int nTileWidth
, const int nTileHeight
);
776 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
778 const int nCanvasWidth
, const int nCanvasHeight
,
779 const int nTilePosX
, const int nTilePosY
,
780 const int nTileWidth
, const int nTileHeight
);
782 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
783 unsigned char* pBuffer
,
785 const int nCanvasWidth
, const int nCanvasHeight
,
786 const int nTilePosX
, const int nTilePosY
,
787 const int nTileWidth
, const int nTileHeight
);
788 static int doc_getTileMode(LibreOfficeKitDocument
* pThis
);
789 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
792 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
793 const char* pArguments
);
795 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
796 LibreOfficeKitCallback pCallback
,
798 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
,
802 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
,
806 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
,
807 unsigned nLOKWindowId
,
810 static void doc_sendDialogEvent(LibreOfficeKitDocument
* pThis
,
811 unsigned nLOKWindowId
,
812 const char* pArguments
);
813 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* pThis
,
814 unsigned nLOKWindowId
,
818 static void doc_postMouseEvent (LibreOfficeKitDocument
* pThis
,
825 static void doc_postWindowMouseEvent (LibreOfficeKitDocument
* pThis
,
826 unsigned nLOKWindowId
,
833 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* pThis
,
834 unsigned nLOKWindowId
,
839 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
,
840 const char* pCommand
,
841 const char* pArguments
,
842 bool bNotifyWhenFinished
);
843 static void doc_setTextSelection (LibreOfficeKitDocument
* pThis
,
847 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
,
848 const char* pMimeType
,
849 char** pUsedMimeType
);
850 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
);
851 static int doc_getClipboard (LibreOfficeKitDocument
* pThis
,
852 const char **pMimeTypes
,
854 char ***pOutMimeTypes
,
856 char ***pOutStreams
);
857 static int doc_setClipboard (LibreOfficeKitDocument
* pThis
,
858 const size_t nInCount
,
859 const char **pInMimeTypes
,
860 const size_t *pInSizes
,
861 const char **pInStreams
);
862 static bool doc_paste(LibreOfficeKitDocument
* pThis
,
863 const char* pMimeType
,
866 static void doc_setGraphicSelection (LibreOfficeKitDocument
* pThis
,
870 static void doc_resetSelection (LibreOfficeKitDocument
* pThis
);
871 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
);
872 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
,
874 int nTilePixelHeight
,
876 int nTileTwipHeight
);
877 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
);
878 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
);
879 static int doc_createView(LibreOfficeKitDocument
* pThis
);
880 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
, const char* pOptions
);
881 static void doc_destroyView(LibreOfficeKitDocument
* pThis
, int nId
);
882 static void doc_setView(LibreOfficeKitDocument
* pThis
, int nId
);
883 static int doc_getView(LibreOfficeKitDocument
* pThis
);
884 static int doc_getViewsCount(LibreOfficeKitDocument
* pThis
);
885 static bool doc_getViewIds(LibreOfficeKitDocument
* pThis
, int* pArray
, size_t nSize
);
886 static void doc_setViewLanguage(LibreOfficeKitDocument
* pThis
, int nId
, const char* language
);
887 static unsigned char* doc_renderFontOrientation(LibreOfficeKitDocument
* pThis
,
888 const char *pFontName
,
893 static unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
894 const char *pFontName
,
898 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
);
900 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
901 const int nX
, const int nY
,
902 const int nWidth
, const int nHeight
);
904 static void doc_paintWindowDPI(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
);
909 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
910 const int nX
, const int nY
,
911 const int nWidth
, const int nHeight
,
912 const double fDPIScale
, int viewId
);
914 static void doc_postWindow(LibreOfficeKitDocument
* pThis
, unsigned
915 nLOKWindowId
, int nAction
, const char* pData
);
917 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
);
919 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
920 const unsigned char* pCertificateBinary
,
921 const int nCertificateBinarySize
,
922 const unsigned char* pPrivateKeyBinary
,
923 const int nPrivateKeyBinarySize
);
925 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
926 const unsigned char* pCertificateBinary
,
927 const int nCertificateBinarySize
);
929 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
);
931 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
);
933 static void doc_resizeWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
934 const int nWidth
, const int nHeight
);
936 static void doc_completeFunction(LibreOfficeKitDocument
* pThis
, int nIndex
);
940 ITiledRenderable
* getTiledRenderable(LibreOfficeKitDocument
* pThis
)
942 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
943 return dynamic_cast<ITiledRenderable
*>(pDocument
->mxComponent
.get());
949 * Unfortunately clipboard creation using UNO is insanely baroque.
950 * we also need to ensure that this works for the first view which
951 * has no clear 'createView' called for it (unfortunately).
953 rtl::Reference
<LOKClipboard
> forceSetClipboardForCurrentView(LibreOfficeKitDocument
*pThis
)
955 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
956 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
958 SAL_INFO("lok", "Set to clipboard for view " << xClip
.get());
959 // FIXME: using a hammer here - should not be necessary if all tests used createView.
960 pDoc
->setClipboard(uno::Reference
<datatransfer::clipboard::XClipboard
>(xClip
->getXI(), UNO_QUERY
));
967 } // anonymous namespace
969 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference
<css::lang::XComponent
> &xComponent
)
970 : mxComponent(xComponent
)
972 if (!(m_pDocumentClass
= gDocumentClass
.lock()))
974 m_pDocumentClass
.reset(new LibreOfficeKitDocumentClass
);
976 m_pDocumentClass
->nSize
= sizeof(LibreOfficeKitDocumentClass
);
978 m_pDocumentClass
->destroy
= doc_destroy
;
979 m_pDocumentClass
->saveAs
= doc_saveAs
;
980 m_pDocumentClass
->getDocumentType
= doc_getDocumentType
;
981 m_pDocumentClass
->getParts
= doc_getParts
;
982 m_pDocumentClass
->getPartPageRectangles
= doc_getPartPageRectangles
;
983 m_pDocumentClass
->getPart
= doc_getPart
;
984 m_pDocumentClass
->setPart
= doc_setPart
;
985 m_pDocumentClass
->selectPart
= doc_selectPart
;
986 m_pDocumentClass
->moveSelectedParts
= doc_moveSelectedParts
;
987 m_pDocumentClass
->getPartName
= doc_getPartName
;
988 m_pDocumentClass
->setPartMode
= doc_setPartMode
;
989 m_pDocumentClass
->paintTile
= doc_paintTile
;
991 m_pDocumentClass
->paintTileToCGContext
= doc_paintTileToCGContext
;
993 m_pDocumentClass
->paintPartTile
= doc_paintPartTile
;
994 m_pDocumentClass
->getTileMode
= doc_getTileMode
;
995 m_pDocumentClass
->getDocumentSize
= doc_getDocumentSize
;
996 m_pDocumentClass
->initializeForRendering
= doc_initializeForRendering
;
997 m_pDocumentClass
->registerCallback
= doc_registerCallback
;
998 m_pDocumentClass
->postKeyEvent
= doc_postKeyEvent
;
999 m_pDocumentClass
->postWindowExtTextInputEvent
= doc_postWindowExtTextInputEvent
;
1000 m_pDocumentClass
->removeTextContext
= doc_removeTextContext
;
1001 m_pDocumentClass
->postWindowKeyEvent
= doc_postWindowKeyEvent
;
1002 m_pDocumentClass
->postMouseEvent
= doc_postMouseEvent
;
1003 m_pDocumentClass
->postWindowMouseEvent
= doc_postWindowMouseEvent
;
1004 m_pDocumentClass
->sendDialogEvent
= doc_sendDialogEvent
;
1005 m_pDocumentClass
->postUnoCommand
= doc_postUnoCommand
;
1006 m_pDocumentClass
->setTextSelection
= doc_setTextSelection
;
1007 m_pDocumentClass
->getTextSelection
= doc_getTextSelection
;
1008 m_pDocumentClass
->getSelectionType
= doc_getSelectionType
;
1009 m_pDocumentClass
->getClipboard
= doc_getClipboard
;
1010 m_pDocumentClass
->setClipboard
= doc_setClipboard
;
1011 m_pDocumentClass
->paste
= doc_paste
;
1012 m_pDocumentClass
->setGraphicSelection
= doc_setGraphicSelection
;
1013 m_pDocumentClass
->resetSelection
= doc_resetSelection
;
1014 m_pDocumentClass
->getCommandValues
= doc_getCommandValues
;
1015 m_pDocumentClass
->setClientZoom
= doc_setClientZoom
;
1016 m_pDocumentClass
->setClientVisibleArea
= doc_setClientVisibleArea
;
1017 m_pDocumentClass
->setOutlineState
= doc_setOutlineState
;
1019 m_pDocumentClass
->createView
= doc_createView
;
1020 m_pDocumentClass
->destroyView
= doc_destroyView
;
1021 m_pDocumentClass
->setView
= doc_setView
;
1022 m_pDocumentClass
->getView
= doc_getView
;
1023 m_pDocumentClass
->getViewsCount
= doc_getViewsCount
;
1024 m_pDocumentClass
->getViewIds
= doc_getViewIds
;
1026 m_pDocumentClass
->renderFont
= doc_renderFont
;
1027 m_pDocumentClass
->renderFontOrientation
= doc_renderFontOrientation
;
1028 m_pDocumentClass
->getPartHash
= doc_getPartHash
;
1030 m_pDocumentClass
->paintWindow
= doc_paintWindow
;
1031 m_pDocumentClass
->paintWindowDPI
= doc_paintWindowDPI
;
1032 m_pDocumentClass
->paintWindowForView
= doc_paintWindowForView
;
1033 m_pDocumentClass
->postWindow
= doc_postWindow
;
1034 m_pDocumentClass
->resizeWindow
= doc_resizeWindow
;
1036 m_pDocumentClass
->setViewLanguage
= doc_setViewLanguage
;
1038 m_pDocumentClass
->getPartInfo
= doc_getPartInfo
;
1040 m_pDocumentClass
->insertCertificate
= doc_insertCertificate
;
1041 m_pDocumentClass
->addCertificate
= doc_addCertificate
;
1042 m_pDocumentClass
->getSignatureState
= doc_getSignatureState
;
1044 m_pDocumentClass
->renderShapeSelection
= doc_renderShapeSelection
;
1045 m_pDocumentClass
->postWindowGestureEvent
= doc_postWindowGestureEvent
;
1047 m_pDocumentClass
->createViewWithOptions
= doc_createViewWithOptions
;
1048 m_pDocumentClass
->completeFunction
= doc_completeFunction
;
1050 gDocumentClass
= m_pDocumentClass
;
1052 pClass
= m_pDocumentClass
.get();
1055 forceSetClipboardForCurrentView(this);
1059 LibLODocument_Impl::~LibLODocument_Impl()
1063 mxComponent
->dispose();
1065 catch (const css::lang::DisposedException
& rException
)
1067 SAL_WARN("lok", "failed to dispose document:" << rException
.Message
);
1071 static OUString
getGenerator()
1073 OUString
sGenerator(
1074 Translate::ExpandVariables("%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)"));
1075 OUString
os("$_OS");
1076 ::rtl::Bootstrap::expandMacros(os
);
1077 return sGenerator
.replaceFirst("%1", os
);
1082 CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument
* pDocument
, LibreOfficeKitCallback pCallback
, void* pData
)
1083 : Idle( "lokit timer callback" ),
1084 m_pDocument(pDocument
),
1085 m_pCallback(pCallback
),
1087 m_nDisableCallbacks(0),
1088 m_bEventLatch(false)
1090 SetPriority(TaskPriority::POST_PAINT
);
1092 // Add the states that are safe to skip duplicates on, even when
1093 // not consequent (i.e. do no emit them if unchanged from last).
1094 m_states
.emplace(LOK_CALLBACK_TEXT_SELECTION
, "NIL");
1095 m_states
.emplace(LOK_CALLBACK_GRAPHIC_SELECTION
, "NIL");
1096 m_states
.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
, "NIL");
1097 m_states
.emplace(LOK_CALLBACK_STATE_CHANGED
, "NIL");
1098 m_states
.emplace(LOK_CALLBACK_MOUSE_POINTER
, "NIL");
1099 m_states
.emplace(LOK_CALLBACK_CELL_CURSOR
, "NIL");
1100 m_states
.emplace(LOK_CALLBACK_CELL_FORMULA
, "NIL");
1101 m_states
.emplace(LOK_CALLBACK_CELL_ADDRESS
, "NIL");
1102 m_states
.emplace(LOK_CALLBACK_CURSOR_VISIBLE
, "NIL");
1103 m_states
.emplace(LOK_CALLBACK_SET_PART
, "NIL");
1108 CallbackFlushHandler::~CallbackFlushHandler()
1113 void CallbackFlushHandler::callback(const int type
, const char* payload
, void* data
)
1115 CallbackFlushHandler
* self
= static_cast<CallbackFlushHandler
*>(data
);
1118 self
->queue(type
, payload
);
1122 void CallbackFlushHandler::queue(const int type
, const char* data
)
1124 comphelper::ProfileZone
aZone("CallbackFlushHander::queue");
1126 CallbackData
aCallbackData(type
, (data
? data
: "(nil)"));
1127 const std::string
& payload
= aCallbackData
.PayloadString
;
1128 SAL_INFO("lok", "Queue: [" << type
<< "]: [" << payload
<< "] on " << m_queue
.size() << " entries.");
1130 bool bIsChartActive
= false;
1131 if (type
== LOK_CALLBACK_GRAPHIC_SELECTION
)
1133 LokChartHelper
aChartHelper(SfxViewShell::Current());
1134 bIsChartActive
= aChartHelper
.GetWindow() != nullptr;
1137 if (callbacksDisabled() && !bIsChartActive
)
1139 // We drop notifications when this is set, except for important ones.
1140 // When we issue a complex command (such as .uno:InsertAnnotation)
1141 // there will be multiple notifications. On the first invalidation
1142 // we will start painting, but other events will get fired
1143 // while the complex command in question executes.
1144 // We don't want to suppress everything here on the wrong assumption
1145 // that no new events are fired during painting.
1146 if (type
!= LOK_CALLBACK_STATE_CHANGED
&&
1147 type
!= LOK_CALLBACK_INVALIDATE_TILES
&&
1148 type
!= LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1149 type
!= LOK_CALLBACK_CURSOR_VISIBLE
&&
1150 type
!= LOK_CALLBACK_VIEW_CURSOR_VISIBLE
&&
1151 type
!= LOK_CALLBACK_TEXT_SELECTION
&&
1152 type
!= LOK_CALLBACK_REFERENCE_MARKS
)
1154 SAL_INFO("lok", "Skipping while painting [" << type
<< "]: [" << payload
<< "].");
1158 // In Writer we drop all notifications during painting.
1159 if (doc_getDocumentType(m_pDocument
) == LOK_DOCTYPE_TEXT
)
1163 // Suppress invalid payloads.
1164 if (type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1165 payload
.find(", 0, 0, ") != std::string::npos
)
1167 // The cursor position is often the relative coordinates of the widget
1168 // issuing it, instead of the absolute one that we expect.
1169 // This is temporary however, and, once the control is created and initialized
1170 // correctly, it eventually emits the correct absolute coordinates.
1171 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
1175 std::unique_lock
<std::mutex
> lock(m_mutex
);
1177 // drop duplicate callbacks for the listed types
1180 case LOK_CALLBACK_TEXT_SELECTION_START
:
1181 case LOK_CALLBACK_TEXT_SELECTION_END
:
1182 case LOK_CALLBACK_TEXT_SELECTION
:
1183 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1184 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1185 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1186 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1187 case LOK_CALLBACK_STATE_CHANGED
:
1188 case LOK_CALLBACK_MOUSE_POINTER
:
1189 case LOK_CALLBACK_CELL_CURSOR
:
1190 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1191 case LOK_CALLBACK_CELL_FORMULA
:
1192 case LOK_CALLBACK_CELL_ADDRESS
:
1193 case LOK_CALLBACK_CURSOR_VISIBLE
:
1194 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1195 case LOK_CALLBACK_SET_PART
:
1196 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1197 case LOK_CALLBACK_INVALIDATE_HEADER
:
1198 case LOK_CALLBACK_WINDOW
:
1199 case LOK_CALLBACK_CALC_FUNCTION_LIST
:
1201 const auto& pos
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1202 [type
] (const queue_type::value_type
& elem
) { return (elem
.Type
== type
); });
1204 if (pos
!= m_queue
.rend() && pos
->PayloadString
== payload
)
1206 SAL_INFO("lok", "Skipping queue duplicate [" << type
<< + "]: [" << payload
<< "].");
1213 if (type
== LOK_CALLBACK_TEXT_SELECTION
&& payload
.empty())
1215 const auto& posStart
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1216 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_START
); });
1217 if (posStart
!= m_queue
.rend())
1218 posStart
->PayloadString
.clear();
1220 const auto& posEnd
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1221 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_END
); });
1222 if (posEnd
!= m_queue
.rend())
1223 posEnd
->PayloadString
.clear();
1226 // When payload is empty discards any previous state.
1227 if (payload
.empty())
1231 case LOK_CALLBACK_TEXT_SELECTION_START
:
1232 case LOK_CALLBACK_TEXT_SELECTION_END
:
1233 case LOK_CALLBACK_TEXT_SELECTION
:
1234 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1235 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1236 case LOK_CALLBACK_INVALIDATE_TILES
:
1238 [type
](const queue_type::value_type
& elem
) { return (elem
.Type
== type
); }))
1239 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << payload
<< "].");
1247 // These are safe to use the latest state and ignore previous
1248 // ones (if any) since the last overrides previous ones.
1249 case LOK_CALLBACK_TEXT_SELECTION_START
:
1250 case LOK_CALLBACK_TEXT_SELECTION_END
:
1251 case LOK_CALLBACK_TEXT_SELECTION
:
1252 case LOK_CALLBACK_MOUSE_POINTER
:
1253 case LOK_CALLBACK_CELL_CURSOR
:
1254 case LOK_CALLBACK_CELL_FORMULA
:
1255 case LOK_CALLBACK_CELL_ADDRESS
:
1256 case LOK_CALLBACK_CURSOR_VISIBLE
:
1257 case LOK_CALLBACK_SET_PART
:
1258 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
:
1259 case LOK_CALLBACK_RULER_UPDATE
:
1262 [type
](const queue_type::value_type
& elem
) { return (elem
.Type
== type
); }))
1263 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << payload
<< "].");
1267 // These are safe to use the latest state and ignore previous
1268 // ones (if any) since the last overrides previous ones,
1269 // but only if the view is the same.
1270 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1271 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1272 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1273 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1274 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1275 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1276 case LOK_CALLBACK_CALC_FUNCTION_LIST
:
1278 const int nViewId
= lcl_getViewId(payload
);
1280 [type
, nViewId
] (const queue_type::value_type
& elem
) {
1281 return (elem
.Type
== type
&& nViewId
== lcl_getViewId(elem
));
1287 case LOK_CALLBACK_INVALIDATE_TILES
:
1288 if (processInvalidateTilesEvent(aCallbackData
))
1292 // State changes with same name override previous ones with a different value.
1293 // Ex. ".uno:PageStatus=Slide 20 of 83" overwrites any previous PageStatus.
1294 case LOK_CALLBACK_STATE_CHANGED
:
1296 // Compare the state name=value and overwrite earlier entries with same name.
1297 const auto pos
= payload
.find('=');
1298 if (pos
!= std::string::npos
)
1300 const std::string name
= payload
.substr(0, pos
+ 1);
1302 [type
, &name
] (const queue_type::value_type
& elem
) {
1303 return (elem
.Type
== type
) && (elem
.PayloadString
.compare(0, name
.size(), name
) == 0);
1310 case LOK_CALLBACK_WINDOW
:
1311 if (processWindowEvent(aCallbackData
))
1315 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1317 // remove only selection ranges and 'EMPTY' messages
1318 // always send 'INPLACE' and 'INPLACE EXIT' messages
1319 removeAll([type
, payload
] (const queue_type::value_type
& elem
)
1320 { return (elem
.Type
== type
&& elem
.PayloadString
[0] != 'I'); });
1326 // Validate that the cached data and the payload string are identical.
1327 assert(aCallbackData
.validate() && "Cached callback payload object and string mismatch!");
1328 m_queue
.emplace_back(aCallbackData
);
1329 SAL_INFO("lok", "Queued #" << (m_queue
.size() - 1) <<
1330 " [" << type
<< "]: [" << payload
<< "] to have " << m_queue
.size() << " entries.");
1334 // Dump the queue state and validate cached data.
1336 std::ostringstream oss
;
1337 if (m_queue
.empty())
1340 oss
<< m_queue
.size() << " items\n";
1341 for (const CallbackData
& c
: m_queue
)
1342 oss
<< i
++ << ": [" << c
.Type
<< "] [" << c
.PayloadString
<< "].\n";
1343 SAL_INFO("lok", "Current Queue: " << oss
.str());
1344 for (const CallbackData
& c
: m_queue
)
1345 assert(c
.validate());
1356 bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData
& aCallbackData
)
1358 const std::string
& payload
= aCallbackData
.PayloadString
;
1359 const int type
= aCallbackData
.Type
;
1361 RectangleAndPart
& rcNew
= aCallbackData
.setRectangleAndPart(payload
);
1362 if (rcNew
.isEmpty())
1364 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
1368 // If we have to invalidate all tiles, we can skip any new tile invalidation.
1369 // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
1371 = std::find_if(m_queue
.rbegin(), m_queue
.rend(), [](const queue_type::value_type
& elem
) {
1372 return (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
);
1374 if (pos
!= m_queue
.rend())
1376 const RectangleAndPart
& rcOld
= pos
->getRectangleAndPart();
1377 if (rcOld
.isInfinite() && (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
))
1379 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
1380 << "] since all tiles need to be invalidated.");
1384 if (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
)
1386 // If fully overlapping.
1387 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1389 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
1390 << "] since overlaps existing all-parts.");
1396 if (rcNew
.isInfinite())
1398 SAL_INFO("lok", "Have Empty [" << type
<< "]: [" << payload
1399 << "] so removing all with part " << rcNew
.m_nPart
<< ".");
1400 removeAll([&rcNew
](const queue_type::value_type
& elem
) {
1401 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1403 // Remove exiting if new is all-encompassing, or if of the same part.
1404 const RectangleAndPart rcOld
= RectangleAndPart::Create(elem
.PayloadString
);
1405 return (rcNew
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
);
1414 const auto rcOrig
= rcNew
;
1416 SAL_INFO("lok", "Have [" << type
<< "]: [" << payload
<< "] so merging overlapping.");
1417 removeAll([&rcNew
](const queue_type::value_type
& elem
) {
1418 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1420 const RectangleAndPart
& rcOld
= elem
.getRectangleAndPart();
1421 if (rcNew
.m_nPart
!= -1 && rcOld
.m_nPart
!= -1 && rcOld
.m_nPart
!= rcNew
.m_nPart
)
1423 SAL_INFO("lok", "Nothing to merge between new: "
1424 << rcNew
.toString() << ", and old: " << rcOld
.toString());
1428 if (rcNew
.m_nPart
== -1)
1430 // Don't merge unless fully overlapped.
1431 SAL_INFO("lok", "New " << rcNew
.toString() << " has " << rcOld
.toString()
1433 if (rcNew
.m_aRectangle
.IsInside(rcOld
.m_aRectangle
))
1435 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
1436 << rcOld
.toString() << ".");
1440 else if (rcOld
.m_nPart
== -1)
1442 // Don't merge unless fully overlapped.
1443 SAL_INFO("lok", "Old " << rcOld
.toString() << " has " << rcNew
.toString()
1445 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1447 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
1448 << rcOld
.toString() << ".");
1454 const tools::Rectangle rcOverlap
1455 = rcNew
.m_aRectangle
.GetIntersection(rcOld
.m_aRectangle
);
1456 const bool bOverlap
= !rcOverlap
.IsEmpty();
1457 SAL_INFO("lok", "Merging " << rcNew
.toString() << " & " << rcOld
.toString()
1458 << " => " << rcOverlap
.toString()
1459 << " Overlap: " << bOverlap
);
1462 rcNew
.m_aRectangle
.Union(rcOld
.m_aRectangle
);
1463 SAL_INFO("lok", "Merged: " << rcNew
.toString());
1473 if (rcNew
.m_aRectangle
!= rcOrig
.m_aRectangle
)
1475 SAL_INFO("lok", "Replacing: " << rcOrig
.toString() << " by " << rcNew
.toString());
1476 if (rcNew
.m_aRectangle
.GetWidth() < rcOrig
.m_aRectangle
.GetWidth()
1477 || rcNew
.m_aRectangle
.GetHeight() < rcOrig
.m_aRectangle
.GetHeight())
1479 SAL_WARN("lok", "Error: merged rect smaller.");
1484 aCallbackData
.setRectangleAndPart(rcNew
);
1489 bool CallbackFlushHandler::processWindowEvent(CallbackData
& aCallbackData
)
1491 const std::string
& payload
= aCallbackData
.PayloadString
;
1492 const int type
= aCallbackData
.Type
;
1494 boost::property_tree::ptree
& aTree
= aCallbackData
.setJson(payload
);
1495 const unsigned nLOKWindowId
= aTree
.get
<unsigned>("id", 0);
1496 const std::string aAction
= aTree
.get
<std::string
>("action", "");
1497 if (aAction
== "invalidate")
1499 std::string aRectStr
= aTree
.get
<std::string
>("rectangle", "");
1500 // no 'rectangle' field => invalidate all of the window =>
1501 // remove all previous window part invalidations
1502 if (aRectStr
.empty())
1504 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1505 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1507 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1508 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
1509 && aOldTree
.get
<std::string
>("action", "") == "invalidate")
1519 // if we have to invalidate all of the window, ignore
1520 // any part invalidation message
1521 const auto invAllExist
= std::any_of(m_queue
.rbegin(), m_queue
.rend(),
1522 [&nLOKWindowId
] (const queue_type::value_type
& elem
)
1524 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1527 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1528 return nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
1529 && aOldTree
.get
<std::string
>("action", "") == "invalidate"
1530 && aOldTree
.get
<std::string
>("rectangle", "").empty();
1533 // we found a invalidate-all window callback
1536 SAL_INFO("lok.dialog", "Skipping queue ["
1537 << type
<< "]: [" << payload
1538 << "] since whole window needs to be invalidated.");
1542 std::istringstream
aRectStream(aRectStr
);
1543 long nLeft
, nTop
, nWidth
, nHeight
;
1545 aRectStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
1546 tools::Rectangle
aNewRect(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
1547 bool currentIsRedundant
= false;
1548 removeAll([&aNewRect
, &nLOKWindowId
,
1549 ¤tIsRedundant
](const queue_type::value_type
& elem
) {
1550 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1553 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1554 if (aOldTree
.get
<std::string
>("action", "") == "invalidate")
1556 // Not possible that we encounter an empty rectangle here; we already handled this case above.
1557 std::istringstream
aOldRectStream(aOldTree
.get
<std::string
>("rectangle", ""));
1558 long nOldLeft
, nOldTop
, nOldWidth
, nOldHeight
;
1560 aOldRectStream
>> nOldLeft
>> nOldComma
>> nOldTop
>> nOldComma
>> nOldWidth
1561 >> nOldComma
>> nOldHeight
;
1562 const tools::Rectangle aOldRect
= tools::Rectangle(
1563 nOldLeft
, nOldTop
, nOldLeft
+ nOldWidth
, nOldTop
+ nOldHeight
);
1565 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1567 if (aNewRect
== aOldRect
)
1569 SAL_INFO("lok.dialog", "Duplicate rect [" << aNewRect
.toString()
1570 << "]. Skipping new.");
1571 // We have a rectangle in the queue already that makes the current Callback useless.
1572 currentIsRedundant
= true;
1575 // new one engulfs the old one?
1576 else if (aNewRect
.IsInside(aOldRect
))
1578 SAL_INFO("lok.dialog",
1579 "New rect [" << aNewRect
.toString() << "] engulfs old ["
1580 << aOldRect
.toString() << "]. Replacing old.");
1583 // old one engulfs the new one?
1584 else if (aOldRect
.IsInside(aNewRect
))
1586 SAL_INFO("lok.dialog",
1587 "Old rect [" << aOldRect
.toString() << "] engulfs new ["
1588 << aNewRect
.toString() << "]. Skipping new.");
1589 // We have a rectangle in the queue already that makes the current Callback useless.
1590 currentIsRedundant
= true;
1595 // Overlapping rects.
1596 const tools::Rectangle aPreMergeRect
= aNewRect
;
1597 aNewRect
.Union(aOldRect
);
1598 SAL_INFO("lok.dialog", "Merging rects ["
1599 << aPreMergeRect
.toString() << "] & ["
1600 << aOldRect
.toString() << "] = ["
1601 << aNewRect
.toString()
1602 << "]. Replacing old.");
1612 // Do not enqueue if redundant.
1613 if (currentIsRedundant
)
1616 aTree
.put("rectangle", aNewRect
.toString().getStr());
1617 aCallbackData
.setJson(aTree
);
1618 assert(aCallbackData
.validate() && "Validation after setJson failed!");
1621 else if (aAction
== "created")
1623 // Remove all previous actions on same dialog, if we are creating it anew.
1624 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1625 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1627 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1628 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1634 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
1637 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
1642 auto xClip
= forceSetClipboardForCurrentView(m_pDocument
);
1644 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(xClip
.get());
1645 pWindow
->SetClipboard(xClipboard
);
1648 else if (aAction
== "size_changed")
1650 // A size change is practically re-creation of the window.
1651 // But at a minimum it's a full invalidation.
1652 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1653 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1655 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1656 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1658 const std::string aOldAction
= aOldTree
.get
<std::string
>("action", "");
1659 if (aOldAction
== "invalidate")
1671 void CallbackFlushHandler::Invoke()
1673 comphelper::ProfileZone
aZone("CallbackFlushHander::Invoke");
1675 if (m_pCallback
&& !m_bEventLatch
)
1677 std::scoped_lock
<std::mutex
> lock(m_mutex
);
1679 SAL_INFO("lok", "Flushing " << m_queue
.size() << " elements.");
1680 for (const auto& rCallbackData
: m_queue
)
1682 const int type
= rCallbackData
.Type
;
1683 const auto& payload
= rCallbackData
.PayloadString
;
1684 const int viewId
= lcl_isViewCallbackType(type
) ? lcl_getViewId(rCallbackData
) : -1;
1688 const auto stateIt
= m_states
.find(type
);
1689 if (stateIt
!= m_states
.end())
1691 // If the state didn't change, it's safe to ignore.
1692 if (stateIt
->second
== payload
)
1694 SAL_INFO("lok", "Skipping duplicate [" << type
<< "]: [" << payload
<< "].");
1698 stateIt
->second
= payload
;
1703 const auto statesIt
= m_viewStates
.find(viewId
);
1704 if (statesIt
!= m_viewStates
.end())
1706 auto& states
= statesIt
->second
;
1707 const auto stateIt
= states
.find(type
);
1708 if (stateIt
!= states
.end())
1710 // If the state didn't change, it's safe to ignore.
1711 if (stateIt
->second
== payload
)
1713 SAL_INFO("lok", "Skipping view duplicate [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
1717 SAL_INFO("lok", "Replacing an element in view states [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
1718 stateIt
->second
= payload
;
1722 SAL_INFO("lok", "Inserted a new element in view states: [" << type
<< ',' << viewId
<< "]: [" << payload
<< "]");
1723 states
.emplace(type
, payload
);
1729 m_pCallback(type
, payload
.c_str(), m_pData
);
1736 bool CallbackFlushHandler::removeAll(const std::function
<bool (const CallbackFlushHandler::queue_type::value_type
&)>& rTestFunc
)
1738 auto newEnd
= std::remove_if(m_queue
.begin(), m_queue
.end(), rTestFunc
);
1739 if (newEnd
!= m_queue
.end())
1741 m_queue
.erase(newEnd
, m_queue
.end());
1748 void CallbackFlushHandler::addViewStates(int viewId
)
1750 const auto& result
= m_viewStates
.emplace(viewId
, decltype(m_viewStates
)::mapped_type());
1751 if (!result
.second
&& result
.first
!= m_viewStates
.end())
1753 result
.first
->second
.clear();
1757 void CallbackFlushHandler::removeViewStates(int viewId
)
1759 m_viewStates
.erase(viewId
);
1763 static void doc_destroy(LibreOfficeKitDocument
*pThis
)
1765 comphelper::ProfileZone
aZone("doc_destroy");
1767 SolarMutexGuard aGuard
;
1769 LOKClipboardFactory::releaseClipboardForView(-1);
1771 LibLODocument_Impl
*pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1775 static void lo_destroy (LibreOfficeKit
* pThis
);
1776 static int lo_initialize (LibreOfficeKit
* pThis
, const char* pInstallPath
, const char* pUserProfilePath
);
1777 static LibreOfficeKitDocument
* lo_documentLoad (LibreOfficeKit
* pThis
, const char* pURL
);
1778 static char * lo_getError (LibreOfficeKit
* pThis
);
1779 static void lo_freeError (char* pFree
);
1780 static LibreOfficeKitDocument
* lo_documentLoadWithOptions (LibreOfficeKit
* pThis
,
1782 const char* pOptions
);
1783 static void lo_registerCallback (LibreOfficeKit
* pThis
,
1784 LibreOfficeKitCallback pCallback
,
1786 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
);
1787 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long features
);
1788 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
1790 const char* pPassword
);
1791 static char* lo_getVersionInfo(LibreOfficeKit
* pThis
);
1792 static int lo_runMacro (LibreOfficeKit
* pThis
, const char* pURL
);
1794 static bool lo_signDocument(LibreOfficeKit
* pThis
,
1796 const unsigned char* pCertificateBinary
,
1797 const int nCertificateBinarySize
,
1798 const unsigned char* pPrivateKeyBinary
,
1799 const int nPrivateKeyBinarySize
);
1801 static void lo_runLoop(LibreOfficeKit
* pThis
,
1802 LibreOfficeKitPollCallback pPollCallback
,
1803 LibreOfficeKitWakeCallback pWakeCallback
,
1806 LibLibreOffice_Impl::LibLibreOffice_Impl()
1807 : m_pOfficeClass( gOfficeClass
.lock() )
1809 , mpCallback(nullptr)
1810 , mpCallbackData(nullptr)
1811 , mOptionalFeatures(0)
1813 if(!m_pOfficeClass
) {
1814 m_pOfficeClass
.reset(new LibreOfficeKitClass
);
1815 m_pOfficeClass
->nSize
= sizeof(LibreOfficeKitClass
);
1817 m_pOfficeClass
->destroy
= lo_destroy
;
1818 m_pOfficeClass
->documentLoad
= lo_documentLoad
;
1819 m_pOfficeClass
->getError
= lo_getError
;
1820 m_pOfficeClass
->freeError
= lo_freeError
;
1821 m_pOfficeClass
->documentLoadWithOptions
= lo_documentLoadWithOptions
;
1822 m_pOfficeClass
->registerCallback
= lo_registerCallback
;
1823 m_pOfficeClass
->getFilterTypes
= lo_getFilterTypes
;
1824 m_pOfficeClass
->setOptionalFeatures
= lo_setOptionalFeatures
;
1825 m_pOfficeClass
->setDocumentPassword
= lo_setDocumentPassword
;
1826 m_pOfficeClass
->getVersionInfo
= lo_getVersionInfo
;
1827 m_pOfficeClass
->runMacro
= lo_runMacro
;
1828 m_pOfficeClass
->signDocument
= lo_signDocument
;
1829 m_pOfficeClass
->runLoop
= lo_runLoop
;
1831 gOfficeClass
= m_pOfficeClass
;
1834 pClass
= m_pOfficeClass
.get();
1837 LibLibreOffice_Impl::~LibLibreOffice_Impl()
1845 void paintTileToCGContext(ITiledRenderable
* pDocument
,
1846 void* rCGContext
, const Size nCanvasSize
,
1847 const int nTilePosX
, const int nTilePosY
,
1848 const int nTileWidth
, const int nTileHeight
)
1850 SystemGraphicsData aData
;
1851 aData
.rCGContext
= reinterpret_cast<CGContextRef
>(rCGContext
);
1853 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::DEFAULT
);
1854 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
1855 pDevice
->SetOutputSizePixel(nCanvasSize
);
1856 pDocument
->paintTile(*pDevice
, nCanvasSize
.Width(), nCanvasSize
.Height(),
1857 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
1860 void paintTileIOS(LibreOfficeKitDocument
* pThis
,
1861 unsigned char* pBuffer
,
1862 const int nCanvasWidth
, const int nCanvasHeight
, const double fDPIScale
,
1863 const int nTilePosX
, const int nTilePosY
,
1864 const int nTileWidth
, const int nTileHeight
)
1866 CGContextRef pCGContext
= CGBitmapContextCreate(pBuffer
, nCanvasWidth
, nCanvasHeight
, 8,
1867 nCanvasWidth
* 4, CGColorSpaceCreateDeviceRGB(),
1868 kCGImageAlphaPremultipliedFirst
| kCGImageByteOrder32Little
);
1870 CGContextTranslateCTM(pCGContext
, 0, nCanvasHeight
);
1871 CGContextScaleCTM(pCGContext
, fDPIScale
, -fDPIScale
);
1873 doc_paintTileToCGContext(pThis
, (void*) pCGContext
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
1875 CGContextRelease(pCGContext
);
1879 } // anonymous namespace
1881 // Wonder global state ...
1882 static uno::Reference
<css::uno::XComponentContext
> xContext
;
1883 static uno::Reference
<css::lang::XMultiServiceFactory
> xSFactory
;
1884 static uno::Reference
<css::lang::XMultiComponentFactory
> xFactory
;
1886 static LibreOfficeKitDocument
* lo_documentLoad(LibreOfficeKit
* pThis
, const char* pURL
)
1888 return lo_documentLoadWithOptions(pThis
, pURL
, nullptr);
1891 static LibreOfficeKitDocument
* lo_documentLoadWithOptions(LibreOfficeKit
* pThis
, const char* pURL
, const char* pOptions
)
1893 comphelper::ProfileZone
aZone("lo_documentLoadWithOptions");
1895 SolarMutexGuard aGuard
;
1897 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
1898 pLib
->maLastExceptionMsg
.clear();
1900 OUString
aURL(getAbsoluteURL(pURL
));
1903 pLib
->maLastExceptionMsg
= "Filename to load was not provided.";
1904 SAL_INFO("lok", "URL for load is empty");
1908 pLib
->maLastExceptionMsg
.clear();
1912 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
1913 SAL_INFO("lok", "ComponentContext is not available");
1917 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
1919 if (!xComponentLoader
.is())
1921 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
1922 SAL_INFO("lok", "ComponentLoader is not available");
1928 // 'Language=...' is an option that LOK consumes by itself, and does
1929 // not pass it as a parameter to the filter
1930 OUString aOptions
= getUString(pOptions
);
1931 const OUString aLanguage
= extractParameter(aOptions
, "Language");
1933 if (!aLanguage
.isEmpty())
1935 // use with care - it sets it for the entire core, not just the
1937 SvtSysLocaleOptions aSysLocaleOptions
;
1938 aSysLocaleOptions
.SetLocaleConfigString(aLanguage
);
1939 aSysLocaleOptions
.SetUILocaleConfigString(aLanguage
);
1940 // Set the LOK language tag, used for dialog tunneling.
1941 comphelper::LibreOfficeKit::setLanguageTag(aSysLocaleOptions
.GetLanguageTag());
1944 uno::Sequence
<css::beans::PropertyValue
> aFilterOptions(2);
1945 aFilterOptions
[0] = css::beans::PropertyValue( "FilterOptions",
1947 uno::makeAny(aOptions
),
1948 beans::PropertyState_DIRECT_VALUE
);
1950 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
1951 new LOKInteractionHandler("load", pLib
));
1952 auto const pair(pLib
->mInteractionMap
.insert(std::make_pair(aURL
.toUtf8(), pInteraction
)));
1953 comphelper::ScopeGuard
const g([&] () {
1956 pLib
->mInteractionMap
.erase(aURL
.toUtf8());
1959 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
1960 aFilterOptions
[1].Name
= "InteractionHandler";
1961 aFilterOptions
[1].Value
<<= xInteraction
;
1964 sal_Int16 nMacroExecMode = document::MacroExecMode::USE_CONFIG;
1965 aFilterOptions[2].Name = "MacroExecutionMode";
1966 aFilterOptions[2].Value <<= nMacroExecMode;
1968 sal_Int16 nUpdateDoc = document::UpdateDocMode::ACCORDING_TO_CONFIG;
1969 aFilterOptions[3].Name = "UpdateDocMode";
1970 aFilterOptions[3].Value <<= nUpdateDoc;
1973 uno::Reference
<lang::XComponent
> xComponent
= xComponentLoader
->loadComponentFromURL(
1977 assert(!xComponent
.is() || pair
.second
); // concurrent loading of same URL ought to fail
1979 if (!xComponent
.is())
1981 pLib
->maLastExceptionMsg
= "loadComponentFromURL returned an empty reference";
1982 SAL_INFO("lok", "Document can't be loaded - " << pLib
->maLastExceptionMsg
);
1986 LibLODocument_Impl
* pDocument
= new LibLODocument_Impl(xComponent
);
1987 if (pLib
->mpCallback
)
1989 int nState
= doc_getSignatureState(pDocument
);
1990 pLib
->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS
, OString::number(nState
).getStr(), pLib
->mpCallbackData
);
1994 catch (const uno::Exception
& exception
)
1996 pLib
->maLastExceptionMsg
= exception
.Message
;
1997 TOOLS_INFO_EXCEPTION("lok", "Document can't be loaded");
2003 static int lo_runMacro(LibreOfficeKit
* pThis
, const char *pURL
)
2005 comphelper::ProfileZone
aZone("lo_runMacro");
2007 SolarMutexGuard aGuard
;
2009 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2010 pLib
->maLastExceptionMsg
.clear();
2012 OUString
sURL( pURL
, strlen(pURL
), RTL_TEXTENCODING_UTF8
);
2015 pLib
->maLastExceptionMsg
= "Macro to run was not provided.";
2016 SAL_INFO("lok", "Macro URL is empty");
2020 if (!sURL
.startsWith("macro://"))
2022 pLib
->maLastExceptionMsg
= "This doesn't look like macro URL";
2023 SAL_INFO("lok", "Macro URL is invalid");
2027 pLib
->maLastExceptionMsg
.clear();
2031 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
2032 SAL_INFO("lok", "ComponentContext is not available");
2037 aURL
.Complete
= sURL
;
2039 uno::Reference
< util::XURLTransformer
> xParser( util::URLTransformer::create( xContext
) );
2042 xParser
->parseStrict( aURL
);
2044 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
2046 if (!xComponentLoader
.is())
2048 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
2049 SAL_INFO("lok", "ComponentLoader is not available");
2053 xFactory
= xContext
->getServiceManager();
2057 uno::Reference
<frame::XDispatchProvider
> xDP
;
2058 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
2059 xDP
.set( xSFactory
->createInstance("com.sun.star.comp.sfx2.SfxMacroLoader"), uno::UNO_QUERY
);
2060 uno::Reference
<frame::XDispatch
> xD
= xDP
->queryDispatch( aURL
, OUString(), 0);
2064 pLib
->maLastExceptionMsg
= "Macro loader is not available";
2065 SAL_INFO("lok", "Macro loader is not available");
2069 uno::Reference
< frame::XSynchronousDispatch
> xSyncDisp( xD
, uno::UNO_QUERY_THROW
);
2070 uno::Sequence
<css::beans::PropertyValue
> aEmpty
;
2071 css::beans::PropertyValue aErr
;
2072 uno::Any aRet
= xSyncDisp
->dispatchWithReturnValue( aURL
, aEmpty
);
2075 if (aErr
.Name
== "ErrorCode")
2077 sal_uInt32 nErrCode
= 0; // ERRCODE_NONE
2078 aErr
.Value
>>= nErrCode
;
2080 pLib
->maLastExceptionMsg
= "An error occurred running macro (error code: " + OUString::number( nErrCode
) + ")";
2081 SAL_INFO("lok", "Macro execution terminated with error code " << nErrCode
);
2092 static bool lo_signDocument(LibreOfficeKit
* /*pThis*/,
2094 const unsigned char* pCertificateBinary
,
2095 const int nCertificateBinarySize
,
2096 const unsigned char* pPrivateKeyBinary
,
2097 const int nPrivateKeyBinarySize
)
2099 comphelper::ProfileZone
aZone("lo_signDocument");
2101 OUString
aURL(getAbsoluteURL(pURL
));
2108 uno::Sequence
<sal_Int8
> aCertificateSequence
;
2110 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
2111 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
2112 if (!aCertificateBase64String
.empty())
2114 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
2115 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
2119 aCertificateSequence
.realloc(nCertificateBinarySize
);
2120 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
2123 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
2124 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeyBinarySize
);
2125 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
2126 if (!aPrivateKeyBase64String
.empty())
2128 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
2129 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
2133 aPrivateKeySequence
.realloc(nPrivateKeyBinarySize
);
2134 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeyBinarySize
, aPrivateKeySequence
.begin());
2137 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
2138 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
2139 if (!xSecurityContext
.is())
2142 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
2143 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
2145 if (!xCertificateCreator
.is())
2148 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
2150 if (!xCertificate
.is())
2153 sfx2::DocumentSigner
aDocumentSigner(aURL
);
2154 if (!aDocumentSigner
.signDocument(xCertificate
))
2160 static void lo_registerCallback (LibreOfficeKit
* pThis
,
2161 LibreOfficeKitCallback pCallback
,
2164 SolarMutexGuard aGuard
;
2166 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2167 pLib
->maLastExceptionMsg
.clear();
2169 pLib
->mpCallback
= pCallback
;
2170 pLib
->mpCallbackData
= pData
;
2173 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* sUrl
, const char* pFormat
, const char* pFilterOptions
)
2175 comphelper::ProfileZone
aZone("doc_saveAs");
2177 SolarMutexGuard aGuard
;
2178 SetLastExceptionMsg();
2180 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2182 OUString sFormat
= getUString(pFormat
);
2183 OUString
aURL(getAbsoluteURL(sUrl
));
2186 SetLastExceptionMsg("Filename to save to was not provided.");
2187 SAL_INFO("lok", "URL for save is empty");
2193 const ExtensionMap
* pMap
;
2195 switch (doc_getDocumentType(pThis
))
2197 case LOK_DOCTYPE_SPREADSHEET
:
2198 pMap
= aCalcExtensionMap
;
2200 case LOK_DOCTYPE_PRESENTATION
:
2201 pMap
= aImpressExtensionMap
;
2203 case LOK_DOCTYPE_DRAWING
:
2204 pMap
= aDrawExtensionMap
;
2206 case LOK_DOCTYPE_TEXT
:
2207 pMap
= aWriterExtensionMap
;
2209 case LOK_DOCTYPE_OTHER
:
2211 SAL_INFO("lok", "Can't save document - unsupported document type.");
2215 if (pFormat
== nullptr)
2217 // sniff from the extension
2218 sal_Int32 idx
= aURL
.lastIndexOf(".");
2221 sFormat
= aURL
.copy( idx
+ 1 );
2225 SetLastExceptionMsg("input filename without a suffix");
2230 OUString aFilterName
;
2231 for (sal_Int32 i
= 0; pMap
[i
].extn
; ++i
)
2233 if (sFormat
.equalsIgnoreAsciiCaseAscii(pMap
[i
].extn
))
2235 aFilterName
= getUString(pMap
[i
].filterName
);
2239 if (aFilterName
.isEmpty())
2241 SetLastExceptionMsg("no output filter found for provided suffix");
2245 OUString aFilterOptions
= getUString(pFilterOptions
);
2247 // Check if watermark for pdf is passed by filteroptions...
2248 // It is not a real filter option so it must be filtered out.
2249 OUString watermarkText
, sFullSheetPreview
;
2251 if ((aIndex
= aFilterOptions
.indexOf(",Watermark=")) >= 0)
2253 int bIndex
= aFilterOptions
.indexOf("WATERMARKEND");
2254 watermarkText
= aFilterOptions
.copy(aIndex
+11, bIndex
-(aIndex
+11));
2256 OUString temp
= aFilterOptions
.copy(0, aIndex
);
2257 aFilterOptions
= temp
+ aFilterOptions
.copy(bIndex
+12);
2261 if ((aIndex
= aFilterOptions
.indexOf(",FullSheetPreview=")) >= 0)
2263 int bIndex
= aFilterOptions
.indexOf("FULLSHEETPREVEND");
2264 sFullSheetPreview
= aFilterOptions
.copy(aIndex
+18, bIndex
-(aIndex
+18));
2266 OUString temp
= aFilterOptions
.copy(0, aIndex
);
2267 aFilterOptions
= temp
+ aFilterOptions
.copy(bIndex
+16);
2270 bool bFullSheetPreview
= sFullSheetPreview
== "true";
2272 // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
2273 // gets a new name). When this is not provided, the meaning of
2274 // saveAs() is more like save-a-copy, which allows saving to any
2275 // random format like PDF or PNG.
2276 // It is not a real filter option, so we have to filter it out.
2277 const uno::Sequence
<OUString
> aOptionSeq
= comphelper::string::convertCommaSeparated(aFilterOptions
);
2278 std::vector
<OUString
> aFilteredOptionVec
;
2279 bool bTakeOwnership
= false;
2280 MediaDescriptor aSaveMediaDescriptor
;
2281 for (const auto& rOption
: aOptionSeq
)
2283 if (rOption
== "TakeOwnership")
2284 bTakeOwnership
= true;
2285 else if (rOption
== "NoFileSync")
2286 aSaveMediaDescriptor
["NoFileSync"] <<= true;
2288 aFilteredOptionVec
.push_back(rOption
);
2291 aSaveMediaDescriptor
["Overwrite"] <<= true;
2292 aSaveMediaDescriptor
["FilterName"] <<= aFilterName
;
2294 auto aFilteredOptionSeq
= comphelper::containerToSequence
<OUString
>(aFilteredOptionVec
);
2295 aFilterOptions
= comphelper::string::convertCommaSeparated(aFilteredOptionSeq
);
2296 aSaveMediaDescriptor
[MediaDescriptor::PROP_FILTEROPTIONS()] <<= aFilterOptions
;
2298 if(!watermarkText
.isEmpty() || bFullSheetPreview
)
2300 uno::Sequence
< beans::PropertyValue
> aFilterData( static_cast<int>(bFullSheetPreview
) + static_cast<int>(!watermarkText
.isEmpty()) );
2302 if (!watermarkText
.isEmpty())
2304 aFilterData
[ 0 ].Name
= "TiledWatermark";
2305 aFilterData
[ 0 ].Value
<<= watermarkText
;
2308 if (bFullSheetPreview
)
2310 int nOptIndex
= static_cast<int>(!watermarkText
.isEmpty());
2312 aFilterData
[ nOptIndex
].Name
= "SinglePageSheets";
2313 aFilterData
[ nOptIndex
].Value
<<= true;
2316 aSaveMediaDescriptor
["FilterData"] <<= aFilterData
;
2319 // add interaction handler too
2322 // gImpl does not have to exist when running from a unit test
2323 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
2324 new LOKInteractionHandler("saveas", gImpl
, pDocument
));
2325 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
2327 aSaveMediaDescriptor
[MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteraction
;
2330 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2333 xStorable
->storeAsURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
2335 xStorable
->storeToURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
2339 catch (const uno::Exception
& exception
)
2341 SetLastExceptionMsg("exception: " + exception
.Message
);
2346 static void doc_iniUnoCommands ()
2348 SolarMutexGuard aGuard
;
2349 SetLastExceptionMsg();
2351 OUString sUnoCommands
[] =
2353 OUString(".uno:AlignLeft"),
2354 OUString(".uno:AlignHorizontalCenter"),
2355 OUString(".uno:AlignRight"),
2356 OUString(".uno:BackColor"),
2357 OUString(".uno:BackgroundColor"),
2358 OUString(".uno:TableCellBackgroundColor"),
2359 OUString(".uno:Bold"),
2360 OUString(".uno:CenterPara"),
2361 OUString(".uno:CharBackColor"),
2362 OUString(".uno:CharBackgroundExt"),
2363 OUString(".uno:CharFontName"),
2364 OUString(".uno:Color"),
2365 OUString(".uno:ControlCodes"),
2366 OUString(".uno:DecrementIndent"),
2367 OUString(".uno:DefaultBullet"),
2368 OUString(".uno:DefaultNumbering"),
2369 OUString(".uno:FontColor"),
2370 OUString(".uno:FontHeight"),
2371 OUString(".uno:IncrementIndent"),
2372 OUString(".uno:Italic"),
2373 OUString(".uno:JustifyPara"),
2374 OUString(".uno:OutlineFont"),
2375 OUString(".uno:LeftPara"),
2376 OUString(".uno:LanguageStatus"),
2377 OUString(".uno:RightPara"),
2378 OUString(".uno:Shadowed"),
2379 OUString(".uno:SubScript"),
2380 OUString(".uno:SuperScript"),
2381 OUString(".uno:Strikeout"),
2382 OUString(".uno:StyleApply"),
2383 OUString(".uno:Underline"),
2384 OUString(".uno:ModifiedStatus"),
2385 OUString(".uno:Undo"),
2386 OUString(".uno:Redo"),
2387 OUString(".uno:InsertPage"),
2388 OUString(".uno:DeletePage"),
2389 OUString(".uno:DuplicatePage"),
2390 OUString(".uno:Cut"),
2391 OUString(".uno:Copy"),
2392 OUString(".uno:Paste"),
2393 OUString(".uno:SelectAll"),
2394 OUString(".uno:InsertAnnotation"),
2395 OUString(".uno:DeleteAnnotation"),
2396 OUString(".uno:ReplyComment"),
2397 OUString(".uno:ResolveComment"),
2398 OUString(".uno:InsertRowsBefore"),
2399 OUString(".uno:InsertRowsAfter"),
2400 OUString(".uno:InsertColumnsBefore"),
2401 OUString(".uno:InsertColumnsAfter"),
2402 OUString(".uno:DeleteRows"),
2403 OUString(".uno:DeleteColumns"),
2404 OUString(".uno:DeleteTable"),
2405 OUString(".uno:SelectTable"),
2406 OUString(".uno:EntireRow"),
2407 OUString(".uno:EntireColumn"),
2408 OUString(".uno:EntireCell"),
2409 OUString(".uno:AssignLayout"),
2410 OUString(".uno:StatusDocPos"),
2411 OUString(".uno:RowColSelCount"),
2412 OUString(".uno:StatusPageStyle"),
2413 OUString(".uno:InsertMode"),
2414 OUString(".uno:SpellOnline"),
2415 OUString(".uno:StatusSelectionMode"),
2416 OUString(".uno:StateTableCell"),
2417 OUString(".uno:StatusBarFunc"),
2418 OUString(".uno:StatePageNumber"),
2419 OUString(".uno:StateWordCount"),
2420 OUString(".uno:SelectionMode"),
2421 OUString(".uno:PageStatus"),
2422 OUString(".uno:LayoutStatus"),
2423 OUString(".uno:Context"),
2424 OUString(".uno:WrapText"),
2425 OUString(".uno:ToggleMergeCells"),
2426 OUString(".uno:NumberFormatCurrency"),
2427 OUString(".uno:NumberFormatPercent"),
2428 OUString(".uno:NumberFormatDate"),
2429 OUString(".uno:SortAscending"),
2430 OUString(".uno:SortDescending"),
2431 OUString(".uno:TrackChanges"),
2432 OUString(".uno:ShowTrackedChanges"),
2433 OUString(".uno:NextTrackedChange"),
2434 OUString(".uno:PreviousTrackedChange"),
2435 OUString(".uno:AcceptAllTrackedChanges"),
2436 OUString(".uno:RejectAllTrackedChanges"),
2437 OUString(".uno:TableDialog"),
2438 OUString(".uno:FormatCellDialog"),
2439 OUString(".uno:FontDialog"),
2440 OUString(".uno:ParagraphDialog"),
2441 OUString(".uno:OutlineBullet"),
2442 OUString(".uno:InsertIndexesEntry"),
2443 OUString(".uno:DocumentRepair"),
2444 OUString(".uno:TransformDialog"),
2445 OUString(".uno:InsertPageHeader"),
2446 OUString(".uno:InsertPageFooter"),
2447 OUString(".uno:OnlineAutoFormat"),
2448 OUString(".uno:InsertSymbol"),
2449 OUString(".uno:EditRegion"),
2450 OUString(".uno:ThesaurusDialog")
2453 util::URL aCommandURL
;
2454 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2455 SfxViewFrame
* pViewFrame
= pViewShell
? pViewShell
->GetViewFrame(): nullptr;
2457 // check if Frame-Controller were created.
2460 SAL_WARN("lok", "iniUnoCommands: No Frame-Controller created.");
2465 xContext
= comphelper::getProcessComponentContext();
2468 SAL_WARN("lok", "iniUnoCommands: Component context is not available");
2472 SfxSlotPool
& rSlotPool
= SfxSlotPool::GetSlotPool(pViewFrame
);
2473 uno::Reference
<util::XURLTransformer
> xParser(util::URLTransformer::create(xContext
));
2475 for (const auto & sUnoCommand
: sUnoCommands
)
2477 aCommandURL
.Complete
= sUnoCommand
;
2478 xParser
->parseStrict(aCommandURL
);
2480 // when null, this command is not supported by the given component
2481 // (like eg. Calc does not have ".uno:DefaultBullet" etc.)
2482 if (const SfxSlot
* pSlot
= rSlotPool
.GetUnoSlot(aCommandURL
.Path
))
2484 // Initialize slot to dispatch .uno: Command.
2485 pViewFrame
->GetBindings().GetDispatch(pSlot
, aCommandURL
, false);
2490 static int doc_getDocumentType (LibreOfficeKitDocument
* pThis
)
2492 comphelper::ProfileZone
aZone("doc_getDocumentType");
2494 SolarMutexGuard aGuard
;
2495 SetLastExceptionMsg();
2497 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2501 uno::Reference
<lang::XServiceInfo
> xDocument(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2503 if (xDocument
->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
2505 return LOK_DOCTYPE_SPREADSHEET
;
2507 else if (xDocument
->supportsService("com.sun.star.presentation.PresentationDocument"))
2509 return LOK_DOCTYPE_PRESENTATION
;
2511 else if (xDocument
->supportsService("com.sun.star.drawing.DrawingDocument"))
2513 return LOK_DOCTYPE_DRAWING
;
2515 else if (xDocument
->supportsService("com.sun.star.text.TextDocument") || xDocument
->supportsService("com.sun.star.text.WebDocument"))
2517 return LOK_DOCTYPE_TEXT
;
2521 SetLastExceptionMsg("unknown document type");
2524 catch (const uno::Exception
& exception
)
2526 SetLastExceptionMsg("exception: " + exception
.Message
);
2528 return LOK_DOCTYPE_OTHER
;
2531 static int doc_getParts (LibreOfficeKitDocument
* pThis
)
2533 comphelper::ProfileZone
aZone("doc_getParts");
2535 SolarMutexGuard aGuard
;
2537 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2540 SetLastExceptionMsg("Document doesn't support tiled rendering");
2544 return pDoc
->getParts();
2547 static int doc_getPart (LibreOfficeKitDocument
* pThis
)
2549 comphelper::ProfileZone
aZone("doc_getPart");
2551 SolarMutexGuard aGuard
;
2552 SetLastExceptionMsg();
2554 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2557 SetLastExceptionMsg("Document doesn't support tiled rendering");
2561 return pDoc
->getPart();
2564 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
)
2566 comphelper::ProfileZone
aZone("doc_setPart");
2568 SolarMutexGuard aGuard
;
2569 SetLastExceptionMsg();
2571 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2574 SetLastExceptionMsg("Document doesn't support tiled rendering");
2578 pDoc
->setPart( nPart
);
2581 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
)
2583 comphelper::ProfileZone
aZone("doc_getPartInfo");
2585 SolarMutexGuard aGuard
;
2586 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2589 SetLastExceptionMsg("Document doesn't support tiled rendering");
2593 return convertOUString(pDoc
->getPartInfo(nPart
));
2596 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
)
2598 SolarMutexGuard aGuard
;
2600 gImpl
->maLastExceptionMsg
.clear();
2602 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2605 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2609 pDoc
->selectPart( nPart
, nSelect
);
2612 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
)
2614 SolarMutexGuard aGuard
;
2616 gImpl
->maLastExceptionMsg
.clear();
2618 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2621 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2625 pDoc
->moveSelectedParts(nPosition
, bDuplicate
);
2628 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
)
2630 comphelper::ProfileZone
aZone("doc_getPartPageRectangles");
2632 SolarMutexGuard aGuard
;
2633 SetLastExceptionMsg();
2635 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2638 SetLastExceptionMsg("Document doesn't support tiled rendering");
2642 return convertOUString(pDoc
->getPartPageRectangles());
2645 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
)
2647 comphelper::ProfileZone
aZone("doc_getPartName");
2649 SolarMutexGuard aGuard
;
2650 SetLastExceptionMsg();
2652 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2655 SetLastExceptionMsg("Document doesn't support tiled rendering");
2659 return convertOUString(pDoc
->getPartName(nPart
));
2662 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
)
2664 comphelper::ProfileZone
aZone("doc_getPartHash");
2666 SolarMutexGuard aGuard
;
2667 SetLastExceptionMsg();
2669 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2672 SetLastExceptionMsg("Document doesn't support tiled rendering");
2676 return convertOUString(pDoc
->getPartHash(nPart
));
2679 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
,
2682 comphelper::ProfileZone
aZone("doc_setPartMode");
2684 SolarMutexGuard aGuard
;
2685 SetLastExceptionMsg();
2687 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2690 SetLastExceptionMsg("Document doesn't support tiled rendering");
2695 int nCurrentPart
= pDoc
->getPart();
2697 pDoc
->setPartMode(nPartMode
);
2699 // We need to make sure the internal state is updated, just changing the mode
2700 // might not update the relevant shells (i.e. impress will keep rendering the
2701 // previous mode unless we do this).
2702 // TODO: we might want to do this within the relevant components rather than
2703 // here, but that's also dependent on how we implement embedded object
2704 // rendering I guess?
2705 // TODO: we could be clever and e.g. set to 0 when we change to/from
2706 // embedded object mode, and not when changing between slide/notes/combined
2708 if ( nCurrentPart
< pDoc
->getParts() )
2710 pDoc
->setPart( nCurrentPart
);
2718 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
2719 unsigned char* pBuffer
,
2720 const int nCanvasWidth
, const int nCanvasHeight
,
2721 const int nTilePosX
, const int nTilePosY
,
2722 const int nTileWidth
, const int nTileHeight
)
2724 comphelper::ProfileZone
aZone("doc_paintTile");
2726 SolarMutexGuard aGuard
;
2727 SetLastExceptionMsg();
2729 SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth
<< "x" << nTileHeight
<<
2730 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
2731 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2733 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2736 SetLastExceptionMsg("Document doesn't support tiled rendering");
2740 #if defined(UNX) && !defined(MACOSX) && !defined(ENABLE_HEADLESS)
2742 // Painting of zoomed or HiDPI spreadsheets is special, we actually draw everything at 100%,
2743 // and only set cairo's (or CoreGraphic's, in the iOS case) scale factor accordingly, so that
2744 // everything is painted bigger or smaller. This is different to what Calc's internal scaling
2745 // would do - because that one is trying to fit the lines between cells to integer multiples of
2747 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
2750 double fDPIScaleX
= 1.0;
2751 paintTileIOS(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, fDPIScaleX
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2753 ScopedVclPtrInstance
< VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
2755 #if HAVE_FEATURE_ANDROID_LOK
2756 // Set background to transparent by default.
2757 // [Unless it is the 'old' (JNI-based) Android app - no idea why it
2758 // needs avoiding this.]
2759 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
2762 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
2763 Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(),
2766 pDoc
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
,
2767 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2769 static bool bDebug
= getenv("LOK_DEBUG_TILES") != nullptr;
2772 // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
2773 tools::Rectangle
aRect(0, 0, 5, 5);
2774 aRect
= pDevice
->PixelToLogic(aRect
);
2775 pDevice
->Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
2776 pDevice
->SetFillColor(COL_LIGHTRED
);
2777 pDevice
->SetLineColor();
2778 pDevice
->DrawRect(aRect
);
2790 // This function is separate only to be used by LibreOfficeLight. If that app can be retired, this
2791 // function's code can be inlined.
2792 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
2794 const int nCanvasWidth
, const int nCanvasHeight
,
2795 const int nTilePosX
, const int nTilePosY
,
2796 const int nTileWidth
, const int nTileHeight
)
2798 SolarMutexGuard aGuard
;
2799 SetLastExceptionMsg();
2801 SAL_INFO( "lok.tiledrendering", "paintTileToCGContext: painting [" << nTileWidth
<< "x" << nTileHeight
<<
2802 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
2803 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2805 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2808 SetLastExceptionMsg("Document doesn't support tiled rendering");
2812 Size
aCanvasSize(nCanvasWidth
, nCanvasHeight
);
2813 paintTileToCGContext(pDoc
, rCGContext
, aCanvasSize
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2818 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
2819 unsigned char* pBuffer
,
2821 const int nCanvasWidth
, const int nCanvasHeight
,
2822 const int nTilePosX
, const int nTilePosY
,
2823 const int nTileWidth
, const int nTileHeight
)
2825 comphelper::ProfileZone
aZone("doc_paintPartTile");
2827 SolarMutexGuard aGuard
;
2828 SetLastExceptionMsg();
2830 SAL_INFO( "lok.tiledrendering", "paintPartTile: painting @ " << nPart
<< " ["
2831 << nTileWidth
<< "x" << nTileHeight
<< "]@("
2832 << nTilePosX
<< ", " << nTilePosY
<< ") to ["
2833 << nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
2835 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2836 int nOrigViewId
= doc_getView(pThis
);
2838 if (nOrigViewId
< 0)
2840 // tile painting always needs a SfxViewShell::Current(), but actually
2841 // it does not really matter which one - all of them should paint the
2843 int viewCount
= doc_getViewsCount(pThis
);
2847 std::vector
<int> viewIds(viewCount
);
2848 doc_getViewIds(pThis
, viewIds
.data(), viewCount
);
2850 nOrigViewId
= viewIds
[0];
2851 doc_setView(pThis
, nOrigViewId
);
2854 // Disable callbacks while we are painting.
2855 if (nOrigViewId
>= 0)
2857 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
2858 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
2859 handlerIt
->second
->disableCallbacks();
2864 // Text documents have a single coordinate system; don't change part.
2866 const bool isText
= (doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
);
2867 int nViewId
= nOrigViewId
;
2870 // Check if just switching to another view is enough, that has
2871 // less side-effects.
2872 if (nPart
!= doc_getPart(pThis
))
2874 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
2877 if (pViewShell
->getPart() == nPart
)
2879 nViewId
= static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
2880 doc_setView(pThis
, nViewId
);
2883 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
2887 nOrigPart
= doc_getPart(pThis
);
2888 if (nPart
!= nOrigPart
)
2890 doc_setPart(pThis
, nPart
);
2894 doc_paintTile(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2896 if (!isText
&& nPart
!= nOrigPart
)
2898 doc_setPart(pThis
, nOrigPart
);
2900 if (!isText
&& nViewId
!= nOrigViewId
)
2902 doc_setView(pThis
, nOrigViewId
);
2905 catch (const std::exception
&)
2907 // Nothing to do but restore the PartTilePainting flag.
2910 if (nOrigViewId
>= 0)
2912 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
2913 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
2914 handlerIt
->second
->enableCallbacks();
2918 static int doc_getTileMode(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
2920 SetLastExceptionMsg();
2921 return LOK_TILEMODE_BGRA
;
2924 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
2928 comphelper::ProfileZone
aZone("doc_getDocumentSize");
2930 SolarMutexGuard aGuard
;
2931 SetLastExceptionMsg();
2933 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2936 Size aDocumentSize
= pDoc
->getDocumentSize();
2937 *pWidth
= aDocumentSize
.Width();
2938 *pHeight
= aDocumentSize
.Height();
2942 SetLastExceptionMsg("Document doesn't support tiled rendering");
2946 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
2947 const char* pArguments
)
2949 comphelper::ProfileZone
aZone("doc_initializeForRendering");
2951 SolarMutexGuard aGuard
;
2952 SetLastExceptionMsg();
2954 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2957 doc_iniUnoCommands();
2958 pDoc
->initializeForTiledRendering(
2959 comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments
)));
2963 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
2964 LibreOfficeKitCallback pCallback
,
2967 SolarMutexGuard aGuard
;
2968 SetLastExceptionMsg();
2970 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2972 int nView
= SfxLokHelper::getView();
2976 if (pCallback
!= nullptr)
2979 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
2981 if (pair
.first
== nId
)
2984 pair
.second
->addViewStates(nView
);
2990 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
2992 if (pair
.first
== nId
)
2995 pair
.second
->removeViewStates(nView
);
2999 pDocument
->mpCallbackFlushHandlers
[nView
].reset(new CallbackFlushHandler(pThis
, pCallback
, pData
));
3001 if (pCallback
!= nullptr)
3004 for (const auto& pair
: pDocument
->mpCallbackFlushHandlers
)
3006 if (pair
.first
== nId
)
3009 pDocument
->mpCallbackFlushHandlers
[nView
]->addViewStates(pair
.first
);
3013 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
3015 pViewShell
->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback
, pDocument
->mpCallbackFlushHandlers
[nView
].get());
3019 /// Returns the JSON representation of all the comments in the document
3020 static char* getPostIts(LibreOfficeKitDocument
* pThis
)
3022 SetLastExceptionMsg();
3023 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3026 SetLastExceptionMsg("Document doesn't support tiled rendering");
3029 OUString aComments
= pDoc
->getPostIts();
3030 return strdup(aComments
.toUtf8().getStr());
3033 /// Returns the JSON representation of the positions of all the comments in the document
3034 static char* getPostItsPos(LibreOfficeKitDocument
* pThis
)
3036 SetLastExceptionMsg();
3037 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3040 SetLastExceptionMsg("Document doesn't support tiled rendering");
3043 OUString aComments
= pDoc
->getPostItsPos();
3044 return strdup(aComments
.toUtf8().getStr());
3047 static char* getRulerState(LibreOfficeKitDocument
* pThis
)
3049 SetLastExceptionMsg();
3050 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3053 SetLastExceptionMsg("Document doesn't support tiled rendering");
3056 OUString state
= pDoc
->getRulerState();
3057 return strdup(state
.toUtf8().getStr());
3060 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nCharCode
, int nKeyCode
)
3062 comphelper::ProfileZone
aZone("doc_postKeyEvent");
3064 SolarMutexGuard aGuard
;
3065 SetLastExceptionMsg();
3067 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3070 SetLastExceptionMsg("Document doesn't support tiled rendering");
3074 pDoc
->postKeyEvent(nType
, nCharCode
, nKeyCode
);
3077 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
, unsigned nWindowId
, int nType
, const char* pText
)
3079 comphelper::ProfileZone
aZone("doc_postWindowExtTextInputEvent");
3081 SolarMutexGuard aGuard
;
3082 VclPtr
<vcl::Window
> pWindow
;
3085 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3088 SetLastExceptionMsg("Document doesn't support tiled rendering");
3091 pWindow
= pDoc
->getDocWindow();
3095 pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
3100 SetLastExceptionMsg("No window found for window id: " + OUString::number(nWindowId
));
3104 SfxLokHelper::postExtTextEventAsync(pWindow
, nType
, OUString::fromUtf8(OString(pText
, strlen(pText
))));
3107 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, int nCharBefore
, int nCharAfter
)
3109 SolarMutexGuard aGuard
;
3110 VclPtr
<vcl::Window
> pWindow
;
3111 if (nLOKWindowId
== 0)
3113 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3116 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3119 pWindow
= pDoc
->getDocWindow();
3123 pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3128 gImpl
->maLastExceptionMsg
= "No window found for window id: " + OUString::number(nLOKWindowId
);
3132 // Annoyingly - backspace and delete are handled in the apps via an accelerator
3133 // which are PostMessage'd by SfxViewShell::ExecKey_Impl so to stay in the same
3134 // order we do this synchronously here, unless we're in a dialog.
3135 if (nCharBefore
> 0)
3138 if (nLOKWindowId
== 0)
3140 KeyEvent
aEvt(8, 1283);
3141 for (int i
= 0; i
< nCharBefore
; ++i
)
3142 pWindow
->KeyInput(aEvt
);
3145 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 8, 1283, nCharBefore
- 1);
3151 if (nLOKWindowId
== 0)
3153 KeyEvent
aEvt(46, 1286);
3154 for (int i
= 0; i
< nCharAfter
; ++i
)
3155 pWindow
->KeyInput(aEvt
);
3158 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 46, 1286, nCharAfter
- 1);
3162 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nCharCode
, int nKeyCode
)
3164 comphelper::ProfileZone
aZone("doc_postWindowKeyEvent");
3166 SolarMutexGuard aGuard
;
3167 SetLastExceptionMsg();
3169 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3172 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3176 KeyEvent
aEvent(nCharCode
, nKeyCode
, 0);
3180 case LOK_KEYEVENT_KEYINPUT
:
3181 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
3183 case LOK_KEYEVENT_KEYUP
:
3184 Application::PostKeyEvent(VclEventId::WindowKeyUp
, pWindow
, &aEvent
);
3192 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
)
3194 comphelper::ProfileZone
aZone("doc_renderShapeSelection");
3196 SolarMutexGuard aGuard
;
3197 SetLastExceptionMsg();
3199 LokChartHelper
aChartHelper(SfxViewShell::Current());
3201 if (aChartHelper
.GetWindow())
3206 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3208 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
3210 SvMemoryStream aOutStream
;
3211 uno::Reference
<io::XOutputStream
> xOut
= new utl::OOutputStreamWrapper(aOutStream
);
3213 utl::MediaDescriptor aMediaDescriptor
;
3214 switch (doc_getDocumentType(pThis
))
3216 case LOK_DOCTYPE_PRESENTATION
:
3217 aMediaDescriptor
["FilterName"] <<= OUString("impress_svg_Export");
3219 case LOK_DOCTYPE_TEXT
:
3220 aMediaDescriptor
["FilterName"] <<= OUString("writer_svg_Export");
3222 case LOK_DOCTYPE_SPREADSHEET
:
3223 aMediaDescriptor
["FilterName"] <<= OUString("calc_svg_Export");
3226 SAL_WARN("lok", "Failed to render shape selection: Document type is not supported");
3228 aMediaDescriptor
["SelectionOnly"] <<= true;
3229 aMediaDescriptor
["OutputStream"] <<= xOut
;
3231 xStorable
->storeToURL("private:stream", aMediaDescriptor
.getAsConstPropertyValueList());
3235 const size_t nOutputSize
= aOutStream
.GetEndOfData();
3236 *pOutput
= static_cast<char*>(malloc(nOutputSize
));
3239 std::memcpy(*pOutput
, aOutStream
.GetData(), nOutputSize
);
3244 catch (const uno::Exception
& exception
)
3246 css::uno::Any
exAny( cppu::getCaughtException() );
3247 SetLastExceptionMsg(exception
.Message
);
3248 SAL_WARN("lok", "Failed to render shape selection: " << exceptionToString(exAny
));
3256 /** Class to react on finishing of a dispatched command.
3258 This will call a LOK_COMMAND_FINISHED callback when postUnoCommand was
3259 called with the parameter requesting the notification.
3261 @see LibreOfficeKitCallbackType::LOK_CALLBACK_UNO_COMMAND_RESULT.
3263 class DispatchResultListener
: public cppu::WeakImplHelper
<css::frame::XDispatchResultListener
>
3265 OString maCommand
; ///< Command for which this is the result.
3266 std::shared_ptr
<CallbackFlushHandler
> mpCallback
; ///< Callback to call.
3269 DispatchResultListener(const char* pCommand
, std::shared_ptr
<CallbackFlushHandler
> const & pCallback
)
3270 : maCommand(pCommand
)
3271 , mpCallback(pCallback
)
3276 virtual void SAL_CALL
dispatchFinished(const css::frame::DispatchResultEvent
& rEvent
) override
3278 boost::property_tree::ptree aTree
;
3279 aTree
.put("commandName", maCommand
.getStr());
3281 if (rEvent
.State
!= frame::DispatchResultState::DONTKNOW
)
3283 bool bSuccess
= (rEvent
.State
== frame::DispatchResultState::SUCCESS
);
3284 aTree
.put("success", bSuccess
);
3287 aTree
.add_child("result", unoAnyToPropertyTree(rEvent
.Result
));
3289 std::stringstream aStream
;
3290 boost::property_tree::write_json(aStream
, aTree
);
3291 OString aPayload
= aStream
.str().c_str();
3292 mpCallback
->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
3295 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
{}
3300 static void doc_sendDialogEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nWindowId
, const char* pArguments
)
3302 SolarMutexGuard aGuard
;
3304 StringMap
aMap(jsonToStringMap(pArguments
));
3305 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
3308 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3311 else if (aMap
.find("id") != aMap
.end())
3313 const OUString
sClickAction("CLICK");
3314 const OUString
sSelectAction("SELECT");
3315 const OUString
sClearAction("CLEAR");
3316 const OUString
sTypeAction("TYPE");
3317 const OUString
sUpAction("UP");
3318 const OUString
sDownAction("DOWN");
3322 WindowUIObject
aUIObject(pWindow
);
3323 std::unique_ptr
<UIObject
> pUIWindow(aUIObject
.get_child(aMap
["id"]));
3325 bool bIsClickAction
= false;
3327 if (aMap
.find("cmd") != aMap
.end()) {
3328 if (aMap
["cmd"] == "selected")
3330 aMap
["POS"] = aMap
["data"];
3331 aMap
["TEXT"] = aMap
["data"];
3333 pUIWindow
->execute(sSelectAction
, aMap
);
3335 else if (aMap
["cmd"] == "plus")
3337 pUIWindow
->execute(sUpAction
, aMap
);
3339 else if (aMap
["cmd"] == "minus")
3341 pUIWindow
->execute(sDownAction
, aMap
);
3343 else if (aMap
["cmd"] == "set")
3345 aMap
["TEXT"] = aMap
["data"];
3347 pUIWindow
->execute(sClearAction
, aMap
);
3348 pUIWindow
->execute(sTypeAction
, aMap
);
3351 bIsClickAction
= true;
3354 bIsClickAction
= true;
3357 pUIWindow
->execute(sClickAction
, aMap
);
3362 pWindow
->GetParent()->Hide();
3363 pWindow
->GetParent()->Show();
3367 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
, const char* pCommand
, const char* pArguments
, bool bNotifyWhenFinished
)
3369 comphelper::ProfileZone
aZone("doc_postUnoCommand");
3371 SolarMutexGuard aGuard
;
3372 SetLastExceptionMsg();
3374 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
3375 OUString
aCommand(pCommand
, strlen(pCommand
), RTL_TEXTENCODING_UTF8
);
3376 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3378 std::vector
<beans::PropertyValue
> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments
));
3380 if (!vcl::lok::isUnipoll())
3382 beans::PropertyValue aSynchronMode
;
3383 aSynchronMode
.Name
= "SynchronMode";
3384 aSynchronMode
.Value
<<= false;
3385 aPropertyValuesVector
.push_back(aSynchronMode
);
3388 int nView
= SfxLokHelper::getView();
3392 // Set/unset mobile view for LOK
3393 if (gImpl
&& aCommand
== ".uno:LOKSetMobile")
3395 comphelper::LibreOfficeKit::setMobile(nView
);
3398 else if (gImpl
&& aCommand
== ".uno:LOKUnSetMobile")
3400 comphelper::LibreOfficeKit::setMobile(nView
, false);
3404 // handle potential interaction
3405 if (gImpl
&& aCommand
== ".uno:Save")
3407 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
3408 new LOKInteractionHandler("save", gImpl
, pDocument
));
3409 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
3411 beans::PropertyValue aValue
;
3412 aValue
.Name
= "InteractionHandler";
3413 aValue
.Value
<<= xInteraction
;
3414 aPropertyValuesVector
.push_back(aValue
);
3416 bool bDontSaveIfUnmodified
= false;
3417 aPropertyValuesVector
.erase(std::remove_if(aPropertyValuesVector
.begin(),
3418 aPropertyValuesVector
.end(),
3419 [&bDontSaveIfUnmodified
](const beans::PropertyValue
& aItem
){
3420 if (aItem
.Name
== "DontSaveIfUnmodified")
3422 bDontSaveIfUnmodified
= aItem
.Value
.get
<bool>();
3426 }), aPropertyValuesVector
.end());
3428 // skip saving and tell the result via UNO_COMMAND_RESULT
3429 if (bDontSaveIfUnmodified
&& !pDocSh
->IsModified())
3431 boost::property_tree::ptree aTree
;
3432 aTree
.put("commandName", pCommand
);
3433 aTree
.put("success", false);
3435 // Add the reason for not saving
3436 const uno::Any aResultValue
= uno::makeAny(OUString("unmodified"));
3437 aTree
.add_child("result", unoAnyToPropertyTree(aResultValue
));
3439 std::stringstream aStream
;
3440 boost::property_tree::write_json(aStream
, aTree
);
3441 OString aPayload
= aStream
.str().c_str();
3442 pDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
3446 else if (gImpl
&& aCommand
== ".uno:TransformDialog")
3448 bool bNeedConversion
= false;
3449 SfxViewShell
* pViewShell
= SfxViewShell::Current();
3450 LokChartHelper
aChartHelper(pViewShell
);
3452 if (aChartHelper
.GetWindow() )
3454 bNeedConversion
= true;
3456 else if (const SdrView
* pView
= pViewShell
->GetDrawView())
3458 if (OutputDevice
* pOutputDevice
= pView
->GetFirstOutputDevice())
3460 bNeedConversion
= (pOutputDevice
->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
);
3464 if (bNeedConversion
)
3467 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
3469 if (rPropValue
.Name
== "TransformPosX"
3470 || rPropValue
.Name
== "TransformPosY"
3471 || rPropValue
.Name
== "TransformWidth"
3472 || rPropValue
.Name
== "TransformHeight"
3473 || rPropValue
.Name
== "TransformRotationX"
3474 || rPropValue
.Name
== "TransformRotationY")
3476 rPropValue
.Value
>>= value
;
3477 value
= OutputDevice::LogicToLogic(value
, MapUnit::MapTwip
, MapUnit::Map100thMM
);
3478 rPropValue
.Value
<<= value
;
3483 if (aChartHelper
.GetWindow() && aPropertyValuesVector
.size() > 0)
3485 if (aPropertyValuesVector
[0].Name
!= "Action")
3487 tools::Rectangle aChartBB
= aChartHelper
.GetChartBoundingBox();
3488 int nLeft
= OutputDevice::LogicToLogic(aChartBB
.Left(), MapUnit::MapTwip
, MapUnit::Map100thMM
);
3489 int nTop
= OutputDevice::LogicToLogic(aChartBB
.Top(), MapUnit::MapTwip
, MapUnit::Map100thMM
);
3492 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
3494 if (rPropValue
.Name
== "TransformPosX" || rPropValue
.Name
== "TransformRotationX")
3496 rPropValue
.Value
>>= value
;
3497 rPropValue
.Value
<<= value
- nLeft
;
3499 else if (rPropValue
.Name
== "TransformPosY" || rPropValue
.Name
== "TransformRotationY")
3501 rPropValue
.Value
>>= value
;
3502 rPropValue
.Value
<<= value
- nTop
;
3506 util::URL aCommandURL
;
3507 aCommandURL
.Path
= "LOKTransform";
3508 css::uno::Reference
<css::frame::XDispatch
>& aChartDispatcher
= aChartHelper
.GetXDispatcher();
3509 aChartDispatcher
->dispatch(aCommandURL
, comphelper::containerToSequence(aPropertyValuesVector
));
3514 bool bResult
= false;
3515 LokChartHelper
aChartHelper(SfxViewShell::Current());
3517 if (aChartHelper
.GetWindow() )
3519 util::URL aCommandURL
;
3520 aCommandURL
.Path
= aCommand
.copy(5);
3521 css::uno::Reference
<css::frame::XDispatch
>& aChartDispatcher
= aChartHelper
.GetXDispatcher();
3522 aChartDispatcher
->dispatch(aCommandURL
, comphelper::containerToSequence(aPropertyValuesVector
));
3525 else if (bNotifyWhenFinished
&& pDocument
->mpCallbackFlushHandlers
.count(nView
))
3527 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
),
3528 new DispatchResultListener(pCommand
, pDocument
->mpCallbackFlushHandlers
[nView
]));
3531 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
));
3535 SetLastExceptionMsg("Failed to dispatch the .uno: command");
3539 static void doc_postMouseEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
3541 comphelper::ProfileZone
aZone("doc_postMouseEvent");
3543 SolarMutexGuard aGuard
;
3544 SetLastExceptionMsg();
3546 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3549 SetLastExceptionMsg("Document doesn't support tiled rendering");
3553 pDoc
->postMouseEvent(nType
, nX
, nY
, nCount
, nButtons
, nModifier
);
3556 static void doc_postWindowMouseEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
3558 comphelper::ProfileZone
aZone("doc_postWindowMouseEvent");
3560 SolarMutexGuard aGuard
;
3561 SetLastExceptionMsg();
3563 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3566 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3570 const Point
aPos(nX
, nY
);
3571 MouseEvent
aEvent(aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
, nButtons
, nModifier
);
3573 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
3575 pDialog
->EnableInput();
3580 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN
:
3581 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown
, pWindow
, &aEvent
);
3583 case LOK_MOUSEEVENT_MOUSEBUTTONUP
:
3584 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp
, pWindow
, &aEvent
);
3586 case LOK_MOUSEEVENT_MOUSEMOVE
:
3587 Application::PostMouseEvent(VclEventId::WindowMouseMove
, pWindow
, &aEvent
);
3595 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, const char* pType
, int nX
, int nY
, int nOffset
)
3597 comphelper::ProfileZone
aZone("doc_postWindowGestureEvent");
3599 SolarMutexGuard aGuard
;
3600 SetLastExceptionMsg();
3602 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3605 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3609 OString
aType(pType
);
3610 GestureEventType eEventType
= GestureEventType::PanningUpdate
;
3612 if (aType
== "panBegin")
3613 eEventType
= GestureEventType::PanningBegin
;
3614 else if (aType
== "panEnd")
3615 eEventType
= GestureEventType::PanningEnd
;
3617 GestureEvent aEvent
{
3622 PanningOrientation::Vertical
,
3625 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
3627 pDialog
->EnableInput();
3630 Application::PostGestureEvent(VclEventId::WindowGestureEvent
, pWindow
, &aEvent
);
3633 static void doc_setTextSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
3635 comphelper::ProfileZone
aZone("doc_setTextSelection");
3637 SolarMutexGuard aGuard
;
3638 SetLastExceptionMsg();
3640 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3643 SetLastExceptionMsg("Document doesn't support tiled rendering");
3647 pDoc
->setTextSelection(nType
, nX
, nY
);
3650 static bool getFromTransferrable(
3651 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3652 const OString
&aInMimeType
, OString
&aRet
);
3654 static bool encodeImageAsHTML(
3655 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3656 const OString
&aMimeType
, OString
&aRet
)
3658 if (!getFromTransferrable(xTransferable
, aMimeType
, aRet
))
3661 // Encode in base64.
3662 auto aSeq
= Sequence
<sal_Int8
>(reinterpret_cast<const sal_Int8
*>(aRet
.getStr()),
3664 OUStringBuffer aBase64Data
;
3665 comphelper::Base64::encode(aBase64Data
, aSeq
);
3668 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
3670 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
3671 "name=\"generator\" content=\""
3672 + getGenerator().toUtf8()
3674 "</head><body><img src=\"data:" + aMimeType
+ ";base64,"
3675 + aBase64Data
.makeStringAndClear().toUtf8() + "\"/></body></html>";
3680 static bool encodeTextAsHTML(
3681 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3682 const OString
&aMimeType
, OString
&aRet
)
3684 if (!getFromTransferrable(xTransferable
, aMimeType
, aRet
))
3687 // Embed in HTML - FIXME: needs some escaping.
3688 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
3690 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
3691 "name=\"generator\" content=\""
3692 + getGenerator().toUtf8()
3693 + "\"/></head><body><pre>" + aRet
+ "</pre></body></html>";
3698 static bool getFromTransferrable(
3699 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
3700 const OString
&aInMimeType
, OString
&aRet
)
3702 OString
aMimeType(aInMimeType
);
3704 // Take care of UTF-8 text here.
3705 bool bConvert
= false;
3706 sal_Int32 nIndex
= 0;
3707 if (aMimeType
.getToken(0, ';', nIndex
) == "text/plain")
3709 if (aMimeType
.getToken(0, ';', nIndex
) == "charset=utf-8")
3711 aMimeType
= "text/plain;charset=utf-16";
3716 datatransfer::DataFlavor aFlavor
;
3717 aFlavor
.MimeType
= OUString::fromUtf8(aMimeType
.getStr());
3718 if (aMimeType
== "text/plain;charset=utf-16")
3719 aFlavor
.DataType
= cppu::UnoType
<OUString
>::get();
3721 aFlavor
.DataType
= cppu::UnoType
< uno::Sequence
<sal_Int8
> >::get();
3723 if (!xTransferable
->isDataFlavorSupported(aFlavor
))
3725 // Try harder for HTML it is our copy/paste meta-file format
3726 if (aInMimeType
== "text/html")
3728 // Desperate measures - convert text to HTML instead.
3729 if (encodeTextAsHTML(xTransferable
, "text/plain;charset=utf-8", aRet
))
3731 // If html is not supported, might be a graphic-selection,
3732 if (encodeImageAsHTML(xTransferable
, "image/png", aRet
))
3736 SetLastExceptionMsg("Flavor " + aFlavor
.MimeType
+ " is not supported");
3743 aAny
= xTransferable
->getTransferData(aFlavor
);
3745 catch (const css::datatransfer::UnsupportedFlavorException
& e
)
3747 SetLastExceptionMsg("Unsupported flavor " + aFlavor
.MimeType
+ " exception " + e
.Message
);
3750 catch (const css::uno::Exception
& e
)
3752 SetLastExceptionMsg("Exception getting " + aFlavor
.MimeType
+ " exception " + e
.Message
);
3756 if (aFlavor
.DataType
== cppu::UnoType
<OUString
>::get())
3761 aRet
= OUStringToOString(aString
, RTL_TEXTENCODING_UTF8
);
3763 aRet
= OString(reinterpret_cast<const sal_Char
*>(aString
.getStr()), aString
.getLength() * sizeof(sal_Unicode
));
3767 uno::Sequence
<sal_Int8
> aSequence
;
3769 aRet
= OString(reinterpret_cast<sal_Char
*>(aSequence
.getArray()), aSequence
.getLength());
3775 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, char** pUsedMimeType
)
3777 comphelper::ProfileZone
aZone("doc_getTextSelection");
3779 SolarMutexGuard aGuard
;
3780 SetLastExceptionMsg();
3782 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3785 SetLastExceptionMsg("Document doesn't support tiled rendering");
3789 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= pDoc
->getSelection();
3792 SetLastExceptionMsg("No selection available");
3796 const char *pType
= pMimeType
;
3797 if (!pType
|| pType
[0] == '\0')
3798 pType
= "text/plain;charset=utf-8";
3801 bool bSuccess
= getFromTransferrable(xTransferable
, OString(pType
), aRet
);
3805 if (pUsedMimeType
) // legacy
3808 *pUsedMimeType
= strdup(pMimeType
);
3810 *pUsedMimeType
= nullptr;
3813 return convertOString(aRet
);
3816 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
)
3818 comphelper::ProfileZone
aZone("doc_getSelectionType");
3820 SolarMutexGuard aGuard
;
3821 SetLastExceptionMsg();
3823 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3826 SetLastExceptionMsg("Document doesn't support tiled rendering");
3827 return LOK_SELTYPE_NONE
;
3830 css::uno::Reference
<css::datatransfer::XTransferable2
> xTransferable(pDoc
->getSelection(), css::uno::UNO_QUERY
);
3833 SetLastExceptionMsg("No selection available");
3834 return LOK_SELTYPE_NONE
;
3837 if (xTransferable
->isComplex())
3838 return LOK_SELTYPE_COMPLEX
;
3841 bool bSuccess
= getFromTransferrable(xTransferable
, "text/plain;charset=utf-8", aRet
);
3843 return LOK_SELTYPE_NONE
;
3845 if (aRet
.getLength() > 10000)
3846 return LOK_SELTYPE_COMPLEX
;
3848 return aRet
.getLength() ? LOK_SELTYPE_TEXT
: LOK_SELTYPE_NONE
;
3851 static int doc_getClipboard(LibreOfficeKitDocument
* pThis
,
3852 const char **pMimeTypes
,
3854 char ***pOutMimeTypes
,
3856 char ***pOutStreams
)
3858 comphelper::ProfileZone
aZone("doc_getClipboard");
3860 SolarMutexGuard aGuard
;
3861 SetLastExceptionMsg();
3864 assert (pOutMimeTypes
);
3866 assert (pOutStreams
);
3869 *pOutMimeTypes
= nullptr;
3870 *pOutSizes
= nullptr;
3871 *pOutStreams
= nullptr;
3873 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3876 SetLastExceptionMsg("Document doesn't support tiled rendering");
3880 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
3882 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= xClip
->getContents();
3883 SAL_INFO("lok", "Got from clip: " << xClip
.get() << " transferrable: " << xTransferable
);
3886 SetLastExceptionMsg("No clipboard content available");
3890 std::vector
<OString
> aMimeTypes
;
3891 if (!pMimeTypes
) // everything
3893 const uno::Sequence
< css::datatransfer::DataFlavor
> flavors
= xTransferable
->getTransferDataFlavors();
3894 if (!flavors
.getLength())
3896 SetLastExceptionMsg("Flavourless selection");
3899 for (const auto &it
: flavors
)
3900 aMimeTypes
.push_back(OUStringToOString(it
.MimeType
, RTL_TEXTENCODING_UTF8
));
3904 for (size_t i
= 0; pMimeTypes
[i
]; ++i
)
3905 aMimeTypes
.push_back(OString(pMimeTypes
[i
]));
3908 *pOutCount
= aMimeTypes
.size();
3909 *pOutSizes
= static_cast<size_t *>(malloc(*pOutCount
* sizeof(size_t)));
3910 *pOutMimeTypes
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
3911 *pOutStreams
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
3912 for (size_t i
= 0; i
< aMimeTypes
.size(); ++i
)
3914 if (aMimeTypes
[i
] == "text/plain;charset=utf-16")
3915 (*pOutMimeTypes
)[i
] = strdup("text/plain;charset=utf-8");
3917 (*pOutMimeTypes
)[i
] = strdup(aMimeTypes
[i
].getStr());
3920 bool bSuccess
= getFromTransferrable(xTransferable
, (*pOutMimeTypes
)[i
], aRet
);
3921 if (!bSuccess
|| aRet
.getLength() < 1)
3923 (*pOutSizes
)[i
] = 0;
3924 (*pOutStreams
)[i
] = nullptr;
3928 (*pOutSizes
)[i
] = aRet
.getLength();
3929 (*pOutStreams
)[i
] = convertOString(aRet
);
3936 static int doc_setClipboard(LibreOfficeKitDocument
* pThis
,
3937 const size_t nInCount
,
3938 const char **pInMimeTypes
,
3939 const size_t *pInSizes
,
3940 const char **pInStreams
)
3945 (void) pInMimeTypes
;
3949 comphelper::ProfileZone
aZone("doc_setClipboard");
3951 SolarMutexGuard aGuard
;
3952 SetLastExceptionMsg();
3954 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3957 SetLastExceptionMsg("Document doesn't support tiled rendering");
3961 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(nInCount
, pInMimeTypes
, pInSizes
, pInStreams
));
3963 auto xClip
= forceSetClipboardForCurrentView(pThis
);
3964 xClip
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
3966 SAL_INFO("lok", "Set clip: " << xClip
.get() << " to: " << xTransferable
);
3968 if (!pDoc
->isMimeTypeSupported())
3970 SetLastExceptionMsg("Document doesn't support this mime type");
3977 static bool doc_paste(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, const char* pData
, size_t nSize
)
3979 comphelper::ProfileZone
aZone("doc_paste");
3981 SolarMutexGuard aGuard
;
3983 const char *pInMimeTypes
[1];
3984 const char *pInStreams
[1];
3986 pInMimeTypes
[0] = pMimeType
;
3987 pInSizes
[0] = nSize
;
3988 pInStreams
[0] = pData
;
3990 if (!doc_setClipboard(pThis
, 1, pInMimeTypes
, pInSizes
, pInStreams
))
3993 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
3995 {"AnchorType", uno::makeAny(static_cast<sal_uInt16
>(text::TextContentAnchorType_AS_CHARACTER
))},
3996 {"IgnoreComments", uno::makeAny(true)},
3998 if (!comphelper::dispatchCommand(".uno:Paste", aPropertyValues
))
4000 SetLastExceptionMsg("Failed to dispatch the .uno: command");
4007 static void doc_setGraphicSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
4009 comphelper::ProfileZone
aZone("doc_setGraphicSelection");
4011 SolarMutexGuard aGuard
;
4012 SetLastExceptionMsg();
4014 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4017 SetLastExceptionMsg("Document doesn't support tiled rendering");
4021 pDoc
->setGraphicSelection(nType
, nX
, nY
);
4024 static void doc_resetSelection(LibreOfficeKitDocument
* pThis
)
4026 comphelper::ProfileZone
aZone("doc_resetSelection");
4028 SolarMutexGuard aGuard
;
4029 SetLastExceptionMsg();
4031 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4034 SetLastExceptionMsg("Document doesn't support tiled rendering");
4038 pDoc
->resetSelection();
4041 static char* getLanguages(const char* pCommand
)
4043 css::uno::Sequence
< css::lang::Locale
> aLocales
;
4047 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
4050 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
4052 aLocales
= xSpell
->getLocales();
4056 boost::property_tree::ptree aTree
;
4057 aTree
.put("commandName", pCommand
);
4058 boost::property_tree::ptree aValues
;
4059 boost::property_tree::ptree aChild
;
4061 for ( sal_Int32 itLocale
= 0; itLocale
< aLocales
.getLength(); itLocale
++ )
4063 const LanguageTag
aLanguageTag( aLocales
[itLocale
]);
4064 sLanguage
= SvtLanguageTable::GetLanguageString(aLanguageTag
.getLanguageType());
4065 if (sLanguage
.startsWith("{") && sLanguage
.endsWith("}"))
4068 sLanguage
+= ";" + aLanguageTag
.getBcp47(false);
4069 aChild
.put("", sLanguage
.toUtf8());
4070 aValues
.push_back(std::make_pair("", aChild
));
4072 aTree
.add_child("commandValues", aValues
);
4073 std::stringstream aStream
;
4074 boost::property_tree::write_json(aStream
, aTree
);
4075 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4076 assert(pJson
); // Don't handle OOM conditions
4077 strcpy(pJson
, aStream
.str().c_str());
4078 pJson
[aStream
.str().size()] = '\0';
4082 static char* getFonts (const char* pCommand
)
4084 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4085 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4086 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4087 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4089 boost::property_tree::ptree aTree
;
4090 aTree
.put("commandName", pCommand
);
4091 boost::property_tree::ptree aValues
;
4094 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4095 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
4097 boost::property_tree::ptree aChildren
;
4098 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
4099 const sal_IntPtr
* pAry
= pList
->GetSizeAry(rFontMetric
);
4100 sal_uInt16 nSizeCount
= 0;
4101 while (pAry
[nSizeCount
])
4103 boost::property_tree::ptree aChild
;
4104 aChild
.put("", static_cast<float>(pAry
[nSizeCount
]) / 10);
4105 aChildren
.push_back(std::make_pair("", aChild
));
4108 aValues
.add_child(rFontMetric
.GetFamilyName().toUtf8().getStr(), aChildren
);
4111 aTree
.add_child("commandValues", aValues
);
4112 std::stringstream aStream
;
4113 boost::property_tree::write_json(aStream
, aTree
);
4114 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4115 assert(pJson
); // Don't handle OOM conditions
4116 strcpy(pJson
, aStream
.str().c_str());
4117 pJson
[aStream
.str().size()] = '\0';
4121 static char* getFontSubset (const OString
& aFontName
)
4123 OUString
aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName
, RTL_TEXTENCODING_UTF8
), rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
));
4124 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4125 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4126 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4127 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4129 boost::property_tree::ptree aTree
;
4130 aTree
.put("commandName", ".uno:FontSubset");
4131 boost::property_tree::ptree aValues
;
4133 if ( pList
&& !aFoundFont
.isEmpty() )
4135 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4136 sal_uInt16 nItFont
= 0;
4137 for (; nItFont
< nFontCount
; ++nItFont
)
4139 if (aFoundFont
== pList
->GetFontName(nItFont
).GetFamilyName())
4145 if ( nItFont
< nFontCount
)
4147 FontCharMapRef
xFontCharMap (new FontCharMap());
4148 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
));
4149 const vcl::Font
& aFont(pList
->GetFontName(nItFont
));
4151 aDevice
->SetFont(aFont
);
4152 aDevice
->GetFontCharMap(xFontCharMap
);
4153 SubsetMap
aSubMap(xFontCharMap
);
4155 for (auto const& subset
: aSubMap
.GetSubsetMap())
4157 boost::property_tree::ptree aChild
;
4158 aChild
.put("", static_cast<int>(ublock_getCode(subset
.GetRangeMin())));
4159 aValues
.push_back(std::make_pair("", aChild
));
4164 aTree
.add_child("commandValues", aValues
);
4165 std::stringstream aStream
;
4166 boost::property_tree::write_json(aStream
, aTree
);
4167 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4168 assert(pJson
); // Don't handle OOM conditions
4169 strcpy(pJson
, aStream
.str().c_str());
4170 pJson
[aStream
.str().size()] = '\0';
4174 static char* getStyles(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
4176 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4178 boost::property_tree::ptree aTree
;
4179 aTree
.put("commandName", pCommand
);
4180 uno::Reference
<css::style::XStyleFamiliesSupplier
> xStyleFamiliesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
4181 uno::Reference
<container::XNameAccess
> xStyleFamilies
= xStyleFamiliesSupplier
->getStyleFamilies();
4182 uno::Sequence
<OUString
> aStyleFamilies
= xStyleFamilies
->getElementNames();
4184 static const std::vector
<OUString
> aWriterStyles
=
4195 // We need to keep a list of the default style names
4196 // in order to filter these out later when processing
4197 // the full list of styles.
4198 std::set
<OUString
> aDefaultStyleNames
;
4200 boost::property_tree::ptree aValues
;
4201 for (sal_Int32 nStyleFam
= 0; nStyleFam
< aStyleFamilies
.getLength(); ++nStyleFam
)
4203 boost::property_tree::ptree aChildren
;
4204 OUString sStyleFam
= aStyleFamilies
[nStyleFam
];
4205 uno::Reference
<container::XNameAccess
> xStyleFamily(xStyleFamilies
->getByName(sStyleFam
), uno::UNO_QUERY
);
4207 // Writer provides a huge number of styles, we have a list of 7 "default" styles which
4208 // should be shown in the normal dropdown, which we should add to the start of the list
4209 // to simplify their selection.
4210 if (sStyleFam
== "ParagraphStyles"
4211 && doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
)
4213 for (const OUString
& rStyle
: aWriterStyles
)
4215 aDefaultStyleNames
.insert( rStyle
);
4217 boost::property_tree::ptree aChild
;
4218 aChild
.put("", rStyle
.toUtf8());
4219 aChildren
.push_back(std::make_pair("", aChild
));
4223 const uno::Sequence
<OUString
> aStyles
= xStyleFamily
->getElementNames();
4224 for (const OUString
& rStyle
: aStyles
)
4226 // Filter out the default styles - they are already at the top
4228 if (aDefaultStyleNames
.find(rStyle
) == aDefaultStyleNames
.end() ||
4229 (sStyleFam
!= "ParagraphStyles" || doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
) )
4231 boost::property_tree::ptree aChild
;
4232 aChild
.put("", rStyle
.toUtf8());
4233 aChildren
.push_back(std::make_pair("", aChild
));
4236 aValues
.add_child(sStyleFam
.toUtf8().getStr(), aChildren
);
4239 // Header & Footer Styles
4242 boost::property_tree::ptree aChild
;
4243 boost::property_tree::ptree aChildren
;
4244 const OUString
sPageStyles("PageStyles");
4245 uno::Reference
<beans::XPropertySet
> xProperty
;
4246 uno::Reference
<container::XNameContainer
> xContainer
;
4248 if (xStyleFamilies
->hasByName(sPageStyles
) && (xStyleFamilies
->getByName(sPageStyles
) >>= xContainer
))
4250 uno::Sequence
<OUString
> aSeqNames
= xContainer
->getElementNames();
4251 for (sal_Int32 itName
= 0; itName
< aSeqNames
.getLength(); itName
++)
4254 sName
= aSeqNames
[itName
];
4255 xProperty
.set(xContainer
->getByName(sName
), uno::UNO_QUERY
);
4256 if (xProperty
.is() && (xProperty
->getPropertyValue("IsPhysical") >>= bIsPhysical
) && bIsPhysical
)
4258 xProperty
->getPropertyValue("DisplayName") >>= sName
;
4259 aChild
.put("", sName
.toUtf8());
4260 aChildren
.push_back(std::make_pair("", aChild
));
4263 aValues
.add_child("HeaderFooter", aChildren
);
4268 boost::property_tree::ptree aCommandList
;
4271 boost::property_tree::ptree aChild
;
4273 OUString sClearFormat
= SvxResId(RID_SVXSTR_CLEARFORM
);
4275 boost::property_tree::ptree aName
;
4276 aName
.put("", sClearFormat
.toUtf8());
4277 aChild
.push_back(std::make_pair("text", aName
));
4279 boost::property_tree::ptree aCommand
;
4280 aCommand
.put("", ".uno:ResetAttributes");
4281 aChild
.push_back(std::make_pair("id", aCommand
));
4283 aCommandList
.push_back(std::make_pair("", aChild
));
4286 aValues
.add_child("Commands", aCommandList
);
4289 aTree
.add_child("commandValues", aValues
);
4290 std::stringstream aStream
;
4291 boost::property_tree::write_json(aStream
, aTree
);
4292 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4293 assert(pJson
); // Don't handle OOM conditions
4294 strcpy(pJson
, aStream
.str().c_str());
4295 pJson
[aStream
.str().size()] = '\0';
4301 enum class UndoOrRedo
4309 /// Returns the JSON representation of either an undo or a redo stack.
4310 static char* getUndoOrRedo(LibreOfficeKitDocument
* pThis
, UndoOrRedo eCommand
)
4312 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4314 auto pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
4318 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
4322 SfxUndoManager
* pUndoManager
= pObjectShell
->GetUndoManager();
4327 if (eCommand
== UndoOrRedo::UNDO
)
4328 aString
= pUndoManager
->GetUndoActionsInfo();
4330 aString
= pUndoManager
->GetRedoActionsInfo();
4331 char* pJson
= strdup(aString
.toUtf8().getStr());
4335 /// Returns the JSON representation of the redline stack.
4336 static char* getTrackedChanges(LibreOfficeKitDocument
* pThis
)
4338 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4340 uno::Reference
<document::XRedlinesSupplier
> xRedlinesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
4341 std::stringstream aStream
;
4342 // We want positions of the track changes also which is not possible from
4343 // UNO. Enable positioning information for text documents only for now, so
4344 // construct the tracked changes JSON from inside the sw/, not here using UNO
4345 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
&& xRedlinesSupplier
.is())
4347 uno::Reference
<container::XEnumeration
> xRedlines
= xRedlinesSupplier
->getRedlines()->createEnumeration();
4348 boost::property_tree::ptree aRedlines
;
4349 for (size_t nIndex
= 0; xRedlines
->hasMoreElements(); ++nIndex
)
4351 uno::Reference
<beans::XPropertySet
> xRedline(xRedlines
->nextElement(), uno::UNO_QUERY
);
4352 boost::property_tree::ptree aRedline
;
4353 aRedline
.put("index", nIndex
);
4356 xRedline
->getPropertyValue("RedlineAuthor") >>= sAuthor
;
4357 aRedline
.put("author", sAuthor
.toUtf8().getStr());
4360 xRedline
->getPropertyValue("RedlineType") >>= sType
;
4361 aRedline
.put("type", sType
.toUtf8().getStr());
4364 xRedline
->getPropertyValue("RedlineComment") >>= sComment
;
4365 aRedline
.put("comment", sComment
.toUtf8().getStr());
4367 OUString sDescription
;
4368 xRedline
->getPropertyValue("RedlineDescription") >>= sDescription
;
4369 aRedline
.put("description", sDescription
.toUtf8().getStr());
4371 util::DateTime aDateTime
;
4372 xRedline
->getPropertyValue("RedlineDateTime") >>= aDateTime
;
4373 OUString sDateTime
= utl::toISO8601(aDateTime
);
4374 aRedline
.put("dateTime", sDateTime
.toUtf8().getStr());
4376 aRedlines
.push_back(std::make_pair("", aRedline
));
4379 boost::property_tree::ptree aTree
;
4380 aTree
.add_child("redlines", aRedlines
);
4381 boost::property_tree::write_json(aStream
, aTree
);
4385 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4388 SetLastExceptionMsg("Document doesn't support tiled rendering");
4391 OUString aTrackedChanges
= pDoc
->getTrackedChanges();
4392 aStream
<< aTrackedChanges
.toUtf8();
4395 char* pJson
= strdup(aStream
.str().c_str());
4400 /// Returns the JSON representation of the redline author table.
4401 static char* getTrackedChangeAuthors(LibreOfficeKitDocument
* pThis
)
4403 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4406 SetLastExceptionMsg("Document doesn't support tiled rendering");
4409 OUString aAuthors
= pDoc
->getTrackedChangeAuthors();
4410 return strdup(aAuthors
.toUtf8().getStr());
4413 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
4415 comphelper::ProfileZone
aZone("doc_getCommandValues");
4417 SolarMutexGuard aGuard
;
4418 SetLastExceptionMsg();
4420 OString
aCommand(pCommand
);
4421 static const OString
aViewRowColumnHeaders(".uno:ViewRowColumnHeaders");
4422 static const OString
aCellCursor(".uno:CellCursor");
4423 static const OString
aFontSubset(".uno:FontSubset&name=");
4425 if (!strcmp(pCommand
, ".uno:LanguageStatus"))
4427 return getLanguages(pCommand
);
4429 else if (!strcmp(pCommand
, ".uno:CharFontName"))
4431 return getFonts(pCommand
);
4433 else if (!strcmp(pCommand
, ".uno:StyleApply"))
4435 return getStyles(pThis
, pCommand
);
4437 else if (aCommand
== ".uno:Undo")
4439 return getUndoOrRedo(pThis
, UndoOrRedo::UNDO
);
4441 else if (aCommand
== ".uno:Redo")
4443 return getUndoOrRedo(pThis
, UndoOrRedo::REDO
);
4445 else if (aCommand
== ".uno:AcceptTrackedChanges")
4447 return getTrackedChanges(pThis
);
4449 else if (aCommand
== ".uno:TrackedChangeAuthors")
4451 return getTrackedChangeAuthors(pThis
);
4453 else if (aCommand
== ".uno:ViewAnnotations")
4455 return getPostIts(pThis
);
4457 else if (aCommand
== ".uno:ViewAnnotationsPosition")
4459 return getPostItsPos(pThis
);
4461 else if (aCommand
== ".uno:RulerState")
4463 return getRulerState(pThis
);
4465 else if (aCommand
.startsWith(aViewRowColumnHeaders
))
4467 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4470 SetLastExceptionMsg("Document doesn't support tiled rendering");
4474 tools::Rectangle aRectangle
;
4475 if (aCommand
.getLength() > aViewRowColumnHeaders
.getLength())
4477 // Command has parameters.
4482 OString aArguments
= aCommand
.copy(aViewRowColumnHeaders
.getLength() + 1);
4483 sal_Int32 nParamIndex
= 0;
4486 OString aParamToken
= aArguments
.getToken(0, '&', nParamIndex
);
4487 sal_Int32 nIndex
= 0;
4492 OString aToken
= aParamToken
.getToken(0, '=', nIndex
);
4493 if (!aKey
.getLength())
4498 while (nIndex
>= 0);
4500 nX
= aValue
.toInt32();
4501 else if (aKey
== "y")
4502 nY
= aValue
.toInt32();
4503 else if (aKey
== "width")
4504 nWidth
= aValue
.toInt32();
4505 else if (aKey
== "height")
4506 nHeight
= aValue
.toInt32();
4508 while (nParamIndex
>= 0);
4510 aRectangle
= tools::Rectangle(nX
, nY
, nX
+ nWidth
, nY
+ nHeight
);
4513 OUString aHeaders
= pDoc
->getRowColumnHeaders(aRectangle
);
4514 if (aHeaders
.isEmpty())
4517 return convertOUString(aHeaders
);
4519 else if (aCommand
.startsWith(aCellCursor
))
4521 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4524 SetLastExceptionMsg("Document doesn't support tiled rendering");
4527 // Ignore command's deprecated parameters.
4528 return convertOString(pDoc
->getCellCursor());
4530 else if (aCommand
.startsWith(aFontSubset
))
4532 return getFontSubset(OString(pCommand
+ aFontSubset
.getLength()));
4536 SetLastExceptionMsg("Unknown command, no values returned");
4541 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
, int nTilePixelWidth
, int nTilePixelHeight
,
4542 int nTileTwipWidth
, int nTileTwipHeight
)
4544 comphelper::ProfileZone
aZone("doc_setClientZoom");
4546 SolarMutexGuard aGuard
;
4547 SetLastExceptionMsg();
4549 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4552 SetLastExceptionMsg("Document doesn't support tiled rendering");
4556 pDoc
->setClientZoom(nTilePixelWidth
, nTilePixelHeight
, nTileTwipWidth
, nTileTwipHeight
);
4559 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
)
4561 comphelper::ProfileZone
aZone("doc_setClientVisibleArea");
4563 SolarMutexGuard aGuard
;
4564 SetLastExceptionMsg();
4566 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4569 SetLastExceptionMsg("Document doesn't support tiled rendering");
4573 tools::Rectangle
aRectangle(Point(nX
, nY
), Size(nWidth
, nHeight
));
4574 pDoc
->setClientVisibleArea(aRectangle
);
4577 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
)
4579 comphelper::ProfileZone
aZone("doc_setOutlineState");
4581 SolarMutexGuard aGuard
;
4582 SetLastExceptionMsg();
4584 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4587 SetLastExceptionMsg("Document doesn't support tiled rendering");
4591 pDoc
->setOutlineState(bColumn
, nLevel
, nIndex
, bHidden
);
4594 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
,
4595 const char* pOptions
)
4597 comphelper::ProfileZone
aZone("doc_createView");
4599 SolarMutexGuard aGuard
;
4600 SetLastExceptionMsg();
4602 OUString aOptions
= getUString(pOptions
);
4603 const OUString aLanguage
= extractParameter(aOptions
, "Language");
4605 if (!aLanguage
.isEmpty())
4607 // Set the LOK language tag, used for dialog tunneling.
4608 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage
));
4611 int nId
= SfxLokHelper::createView();
4616 forceSetClipboardForCurrentView(pThis
);
4622 static int doc_createView(LibreOfficeKitDocument
* pThis
)
4624 return doc_createViewWithOptions(pThis
, nullptr); // No options.
4627 static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
)
4629 comphelper::ProfileZone
aZone("doc_destroyView");
4631 SolarMutexGuard aGuard
;
4632 SetLastExceptionMsg();
4634 LOKClipboardFactory::releaseClipboardForView(nId
);
4636 SfxLokHelper::destroyView(nId
);
4639 static void doc_setView(LibreOfficeKitDocument
* pThis
, int nId
)
4641 comphelper::ProfileZone
aZone("doc_setView");
4643 SolarMutexGuard aGuard
;
4644 SetLastExceptionMsg();
4646 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4647 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nId
);
4648 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4649 handlerIt
->second
->disableCallbacks();
4653 SfxLokHelper::setView(nId
);
4655 catch (const std::exception
&)
4659 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4660 handlerIt
->second
->enableCallbacks();
4663 static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
4665 comphelper::ProfileZone
aZone("doc_getView");
4667 SolarMutexGuard aGuard
;
4668 SetLastExceptionMsg();
4670 return SfxLokHelper::getView();
4673 static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
4675 comphelper::ProfileZone
aZone("doc_getViewsCount");
4677 SolarMutexGuard aGuard
;
4678 SetLastExceptionMsg();
4680 return SfxLokHelper::getViewsCount();
4683 static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int* pArray
, size_t nSize
)
4685 comphelper::ProfileZone
aZone("doc_getViewsIds");
4687 SolarMutexGuard aGuard
;
4688 SetLastExceptionMsg();
4690 return SfxLokHelper::getViewIds(pArray
, nSize
);
4693 static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
, const char* language
)
4695 comphelper::ProfileZone
aZone("doc_setViewLanguage");
4697 SolarMutexGuard aGuard
;
4698 SetLastExceptionMsg();
4700 SfxLokHelper::setViewLanguage(nId
, OStringToOUString(language
, RTL_TEXTENCODING_UTF8
));
4705 unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
4706 const char* pFontName
,
4711 return doc_renderFontOrientation(pThis
, pFontName
, pChar
, pFontWidth
, pFontHeight
, 0);
4714 unsigned char* doc_renderFontOrientation(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/,
4715 const char* pFontName
,
4721 comphelper::ProfileZone
aZone("doc_renderFont");
4723 SolarMutexGuard aGuard
;
4724 SetLastExceptionMsg();
4726 OString
aSearchedFontName(pFontName
);
4727 OUString
aText(OStringToOUString(pChar
, RTL_TEXTENCODING_UTF8
));
4728 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4729 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4730 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4731 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4733 const int nDefaultFontSize
= 25;
4737 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4738 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
4740 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
4741 const OUString
& aFontName
= rFontMetric
.GetFamilyName();
4742 if (aSearchedFontName
!= aFontName
.toUtf8())
4745 if (aText
.isEmpty())
4746 aText
= rFontMetric
.GetFamilyName();
4748 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
));
4749 ::tools::Rectangle aRect
;
4750 vcl::Font
aFont(rFontMetric
);
4751 aFont
.SetFontSize(Size(0, nDefaultFontSize
));
4752 aFont
.SetOrientation(pOrientation
);
4753 aDevice
->SetFont(aFont
);
4754 aDevice
->GetTextBoundRect(aRect
, aText
);
4755 if (aRect
.IsEmpty())
4758 int nFontWidth
= aRect
.BottomRight().X() + 1;
4759 int nFontHeight
= aRect
.BottomRight().Y() + 1;
4761 if (!(nFontWidth
> 0 && nFontHeight
> 0))
4764 if (*pFontWidth
> 0 && *pFontHeight
> 0)
4766 double fScaleX
= *pFontWidth
/ static_cast<double>(nFontWidth
) / 1.5;
4767 double fScaleY
= *pFontHeight
/ static_cast<double>(nFontHeight
) / 1.5;
4769 double fScale
= std::min(fScaleX
, fScaleY
);
4773 int nFontSize
= fScale
* nDefaultFontSize
;
4774 aFont
.SetFontSize(Size(0, nFontSize
));
4775 aDevice
->SetFont(aFont
);
4778 aRect
= tools::Rectangle(0, 0, *pFontWidth
, *pFontHeight
);
4780 nFontWidth
= *pFontWidth
;
4781 nFontHeight
= *pFontHeight
;
4785 unsigned char* pBuffer
= static_cast<unsigned char*>(malloc(4 * nFontWidth
* nFontHeight
));
4789 memset(pBuffer
, 0, nFontWidth
* nFontHeight
* 4);
4790 aDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
4791 aDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
4792 Size(nFontWidth
, nFontHeight
), Fraction(1.0), Point(),
4795 if (*pFontWidth
> 0 && *pFontHeight
> 0)
4797 DrawTextFlags
const nStyle
=
4798 DrawTextFlags::Center
4799 | DrawTextFlags::VCenter
4800 | DrawTextFlags::Bottom
4801 | DrawTextFlags::MultiLine
4802 | DrawTextFlags::WordBreak
;// | DrawTextFlags::WordBreakHyphenation ;
4804 aDevice
->DrawText(aRect
, aText
, nStyle
);
4808 *pFontWidth
= nFontWidth
;
4809 *pFontHeight
= nFontHeight
;
4811 aDevice
->DrawText(Point(0,0), aText
);
4822 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
4823 unsigned char* pBuffer
,
4824 const int nX
, const int nY
,
4825 const int nWidth
, const int nHeight
)
4827 doc_paintWindowDPI(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, 1.0);
4830 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
4831 unsigned char* pBuffer
,
4832 const int nX
, const int nY
,
4833 const int nWidth
, const int nHeight
,
4834 const double fDPIScale
)
4836 doc_paintWindowForView(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, fDPIScale
, -1);
4839 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
4840 unsigned char* pBuffer
, const int nX
, const int nY
,
4841 const int nWidth
, const int nHeight
,
4842 const double fDPIScale
, int viewId
)
4844 comphelper::ProfileZone
aZone("doc_paintWindowDPI");
4846 SolarMutexGuard aGuard
;
4847 SetLastExceptionMsg();
4849 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4852 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4856 // Used to avoid work in setView if set.
4857 comphelper::LibreOfficeKit::setDialogPainting(true);
4860 doc_setView(pThis
, viewId
);
4862 // Setup cairo (or CoreGraphics, in the iOS case) to draw with the changed DPI scale (and return
4863 // back to 1.0 when the painting finishes)
4864 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
4865 comphelper::LibreOfficeKit::setDPIScale(fDPIScale
);
4869 CGContextRef cgc
= CGBitmapContextCreate(pBuffer
, nWidth
, nHeight
, 8, nWidth
*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst
| kCGImageByteOrder32Little
);
4871 CGContextTranslateCTM(cgc
, 0, nHeight
);
4872 CGContextScaleCTM(cgc
, fDPIScale
, -fDPIScale
);
4874 SystemGraphicsData aData
;
4875 aData
.rCGContext
= cgc
;
4877 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::DEFAULT
);
4878 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
4880 pDevice
->SetOutputSizePixel(Size(nWidth
, nHeight
));
4882 MapMode
aMapMode(pDevice
->GetMapMode());
4883 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
4884 pDevice
->SetMapMode(aMapMode
);
4886 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0), Size());
4888 CGContextRelease(cgc
);
4892 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
4893 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
4895 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(Size(nWidth
, nHeight
), Fraction(1.0), Point(), pBuffer
);
4897 MapMode
aMapMode(pDevice
->GetMapMode());
4898 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
4899 pDevice
->SetMapMode(aMapMode
);
4901 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0), Size());
4904 comphelper::LibreOfficeKit::setDialogPainting(false);
4907 static void doc_postWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nAction
, const char* pData
)
4909 comphelper::ProfileZone
aZone("doc_postWindow");
4911 SolarMutexGuard aGuard
;
4912 SetLastExceptionMsg();
4914 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4917 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4921 if (nAction
== LOK_WINDOW_CLOSE
)
4923 if (Dialog
* pDialog
= dynamic_cast<Dialog
*>(pWindow
.get()))
4925 else if (FloatingWindow
* pFloatWin
= dynamic_cast<FloatingWindow
*>(pWindow
.get()))
4926 pFloatWin
->EndPopupMode(FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
);
4928 else if (nAction
== LOK_WINDOW_PASTE
)
4931 css::uno::Sequence
<sal_Int8
> aData
;
4932 std::vector
<beans::PropertyValue
> aArgs(jsonToPropertyValuesVector(pData
));
4934 aArgs
.size() == 2 &&
4935 aArgs
[0].Name
== "MimeType" && (aArgs
[0].Value
>>= aMimeType
) &&
4936 aArgs
[1].Name
== "Data" && (aArgs
[1].Value
>>= aData
);
4939 if (!aMimeType
.isEmpty() && aData
.hasElements())
4941 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(aMimeType
, aData
));
4942 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(new LOKClipboard
);
4943 xClipboard
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
4944 pWindow
->SetClipboard(xClipboard
);
4946 KeyEvent
aEvent(0, KEY_PASTE
, 0);
4947 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
4950 SetLastExceptionMsg("Window command 'paste': wrong parameters.");
4954 // CERTIFICATE AND DOCUMENT SIGNING
4955 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
4956 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
,
4957 const unsigned char* pPrivateKeyBinary
, const int nPrivateKeySize
)
4959 comphelper::ProfileZone
aZone("doc_insertCertificate");
4964 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4966 if (!pDocument
->mxComponent
.is())
4969 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
4973 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
4978 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
4979 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
4980 if (!xSecurityContext
.is())
4983 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
4984 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
4986 if (!xCertificateCreator
.is())
4989 uno::Sequence
<sal_Int8
> aCertificateSequence
;
4991 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
4992 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
4993 if (!aCertificateBase64String
.empty())
4995 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
4996 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
5000 aCertificateSequence
.realloc(nCertificateBinarySize
);
5001 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
5004 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
5005 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeySize
);
5006 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
5007 if (!aPrivateKeyBase64String
.empty())
5009 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
5010 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
5014 aPrivateKeySequence
.realloc(nPrivateKeySize
);
5015 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeySize
, aPrivateKeySequence
.begin());
5018 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
5020 if (!xCertificate
.is())
5023 SolarMutexGuard aGuard
;
5025 return pObjectShell
->SignDocumentContentUsingCertificate(xCertificate
);
5028 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
5029 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
)
5031 comphelper::ProfileZone
aZone("doc_addCertificate");
5036 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5038 if (!pDocument
->mxComponent
.is())
5041 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
5045 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
5050 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
5051 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
5052 if (!xSecurityContext
.is())
5055 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
5056 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
5058 if (!xCertificateCreator
.is())
5061 uno::Sequence
<sal_Int8
> aCertificateSequence
;
5063 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
5064 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
5065 if (!aCertificateBase64String
.empty())
5067 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
5068 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
5072 aCertificateSequence
.realloc(nCertificateBinarySize
);
5073 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
5076 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->addDERCertificateToTheDatabase(aCertificateSequence
, "TCu,Cu,Tu");
5078 if (!xCertificate
.is())
5081 SAL_INFO("lok", "Certificate Added = IssuerName: " << xCertificate
->getIssuerName() << " SubjectName: " << xCertificate
->getSubjectName());
5086 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
)
5088 comphelper::ProfileZone
aZone("doc_getSignatureState");
5090 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5092 if (!pDocument
->mxComponent
.is())
5093 return int(SignatureState::UNKNOWN
);
5095 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
5097 return int(SignatureState::UNKNOWN
);
5099 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
5101 return int(SignatureState::UNKNOWN
);
5103 SolarMutexGuard aGuard
;
5105 pObjectShell
->RecheckSignature(false);
5107 return int(pObjectShell
->GetDocumentSignatureState());
5110 static void doc_resizeWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
,
5111 const int nWidth
, const int nHeight
)
5113 SolarMutexGuard aGuard
;
5115 gImpl
->maLastExceptionMsg
.clear();
5117 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5120 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog resizing, or window not found.";
5124 pWindow
->SetSizePixel(Size(nWidth
, nHeight
));
5127 static void doc_completeFunction(LibreOfficeKitDocument
* pThis
, int nIndex
)
5129 SolarMutexGuard aGuard
;
5130 SetLastExceptionMsg();
5132 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5135 SetLastExceptionMsg("Document doesn't support tiled rendering");
5139 pDoc
->completeFunction(nIndex
);
5142 static char* lo_getError (LibreOfficeKit
*pThis
)
5144 comphelper::ProfileZone
aZone("lo_getError");
5146 SolarMutexGuard aGuard
;
5148 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5149 return convertOUString(pLib
->maLastExceptionMsg
);
5152 static void lo_freeError(char* pFree
)
5157 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
)
5159 SolarMutexGuard aGuard
;
5160 SetLastExceptionMsg();
5162 LibLibreOffice_Impl
* pImpl
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5164 if (!xSFactory
.is())
5165 xSFactory
= comphelper::getProcessServiceFactory();
5167 if (!xSFactory
.is())
5169 pImpl
->maLastExceptionMsg
= "Service factory is not available";
5173 uno::Reference
<container::XNameAccess
> xTypeDetection(xSFactory
->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY
);
5174 const uno::Sequence
<OUString
> aTypes
= xTypeDetection
->getElementNames();
5175 boost::property_tree::ptree aTree
;
5176 for (const OUString
& rType
: aTypes
)
5178 uno::Sequence
<beans::PropertyValue
> aValues
;
5179 if (xTypeDetection
->getByName(rType
) >>= aValues
)
5181 auto it
= std::find_if(aValues
.begin(), aValues
.end(), [](const beans::PropertyValue
& rValue
) { return rValue
.Name
== "MediaType"; });
5183 if (it
!= aValues
.end() && (it
->Value
>>= aValue
) && !aValue
.isEmpty())
5185 boost::property_tree::ptree aChild
;
5186 aChild
.put("MediaType", aValue
.toUtf8());
5187 aTree
.add_child(rType
.toUtf8().getStr(), aChild
);
5191 std::stringstream aStream
;
5192 boost::property_tree::write_json(aStream
, aTree
);
5193 return strdup(aStream
.str().c_str());
5196 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long const features
)
5198 comphelper::ProfileZone
aZone("lo_setOptionalFeatures");
5200 SolarMutexGuard aGuard
;
5201 SetLastExceptionMsg();
5203 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5204 pLib
->mOptionalFeatures
= features
;
5205 if (features
& LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK
)
5206 comphelper::LibreOfficeKit::setPartInInvalidation(true);
5207 if (features
& LOK_FEATURE_NO_TILED_ANNOTATIONS
)
5208 comphelper::LibreOfficeKit::setTiledAnnotations(false);
5209 if (features
& LOK_FEATURE_RANGE_HEADERS
)
5210 comphelper::LibreOfficeKit::setRangeHeaders(true);
5211 if (features
& LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK
)
5212 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
5215 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
5216 const char* pURL
, const char* pPassword
)
5218 comphelper::ProfileZone
aZone("lo_setDocumentPassword");
5220 SolarMutexGuard aGuard
;
5221 SetLastExceptionMsg();
5225 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5226 assert(pLib
->mInteractionMap
.find(OString(pURL
)) != pLib
->mInteractionMap
.end());
5227 pLib
->mInteractionMap
.find(OString(pURL
))->second
->SetPassword(pPassword
);
5230 static char* lo_getVersionInfo(SAL_UNUSED_PARAMETER LibreOfficeKit
* /*pThis*/)
5232 SetLastExceptionMsg();
5233 const OUString
sVersionStrTemplate(
5235 "\"ProductName\": \"%PRODUCTNAME\", "
5236 "\"ProductVersion\": \"%PRODUCTVERSION\", "
5237 "\"ProductExtension\": \"%PRODUCTEXTENSION\", "
5238 "\"BuildId\": \"%BUILDID\" "
5241 return convertOUString(ReplaceStringHookProc(sVersionStrTemplate
));
5244 static void force_c_locale()
5246 // force locale (and resource files loaded) to en-US
5247 OUString
aLangISO("en-US");
5248 SvtSysLocaleOptions aLocalOptions
;
5249 aLocalOptions
.SetLocaleConfigString(aLangISO
);
5250 aLocalOptions
.SetUILocaleConfigString(aLangISO
);
5253 static void aBasicErrorFunc(const OUString
& rError
, const OUString
& rAction
)
5255 OString aBuffer
= "Unexpected dialog: " +
5256 OUStringToOString(rAction
, RTL_TEXTENCODING_ASCII_US
) +
5258 OUStringToOString(rError
, RTL_TEXTENCODING_ASCII_US
);
5260 fprintf(stderr
, "Unexpected basic error dialog '%s'\n", aBuffer
.getStr());
5263 static bool initialize_uno(const OUString
& aAppProgramURL
)
5266 // For iOS we already hardcode the inifile as "rc" in the .app directory.
5267 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("fundamental"));
5268 xContext
= cppu::defaultBootstrap_InitialComponentContext(aAppProgramURL
+ "/rc");
5269 #elif defined MACOSX
5270 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/../Resources/" SAL_CONFIGFILE("soffice"));
5271 xContext
= cppu::defaultBootstrap_InitialComponentContext();
5273 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("soffice"));
5274 xContext
= cppu::defaultBootstrap_InitialComponentContext();
5279 SetLastExceptionMsg("XComponentContext could not be created");
5280 SAL_INFO("lok", "XComponentContext could not be created");
5284 xFactory
= xContext
->getServiceManager();
5287 SetLastExceptionMsg("XMultiComponentFactory could not be created");
5288 SAL_INFO("lok", "XMultiComponentFactory could not be created");
5292 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
5293 comphelper::setProcessServiceFactory(xSFactory
);
5295 SAL_INFO("lok", "Uno initialized - " << xContext
.is());
5297 // set UserInstallation to user profile dir in test/user-template
5298 // rtl::Bootstrap aDefaultVars;
5299 // aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
5300 // configmgr setup ?
5305 // pre-unipoll version.
5306 static void lo_startmain(void*)
5308 osl_setThreadName("lo_startmain");
5310 if (comphelper::SolarMutex::get())
5311 Application::GetSolarMutex().tryToAcquire();
5313 Application::UpdateMainThread();
5317 Application::ReleaseSolarMutex();
5321 static void lo_runLoop(LibreOfficeKit
* /*pThis*/,
5322 LibreOfficeKitPollCallback pPollCallback
,
5323 LibreOfficeKitWakeCallback pWakeCallback
,
5326 #if defined(IOS) || defined(ANDROID)
5327 Application::GetSolarMutex().acquire();
5331 SolarMutexGuard aGuard
;
5333 vcl::lok::registerPollCallbacks(pPollCallback
, pWakeCallback
, pData
);
5334 Application::UpdateMainThread();
5337 #if defined(IOS) || defined(ANDROID)
5338 vcl::lok::unregisterPollCallbacks();
5339 Application::ReleaseSolarMutex();
5343 static bool bInitialized
= false;
5345 static void lo_status_indicator_callback(void *data
, comphelper::LibreOfficeKit::statusIndicatorCallbackType type
, int percent
)
5347 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(data
);
5349 if (!pLib
->mpCallback
)
5354 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start
:
5355 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START
, nullptr, pLib
->mpCallbackData
);
5357 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue
:
5358 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
,
5359 OUString(OUString::number(percent
)).toUtf8().getStr(), pLib
->mpCallbackData
);
5361 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Finish
:
5362 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH
, nullptr, pLib
->mpCallbackData
);
5367 /// Used only by LibreOfficeKit when used by Online to pre-initialize
5368 static void preloadData()
5370 comphelper::ProfileZone
aZone("preload data");
5372 // Create user profile in the temp directory for loading the dictionaries
5374 rtl::Bootstrap::get("UserInstallation", sUserPath
);
5375 utl::TempFile
aTempDir(nullptr, true);
5376 aTempDir
.EnableKillingFile();
5377 rtl::Bootstrap::set("UserInstallation", aTempDir
.GetURL());
5379 // Register the bundled extensions
5380 desktop::Desktop::SynchronizeExtensionRepositories(true);
5381 bool bAbort
= desktop::Desktop::CheckExtensionDependencies();
5383 std::cerr
<< "CheckExtensionDependencies failed" << std::endl
;
5385 // preload all available dictionaries
5386 css::uno::Reference
<css::linguistic2::XLinguServiceManager
> xLngSvcMgr
=
5387 css::linguistic2::LinguServiceManager::create(comphelper::getProcessComponentContext());
5388 css::uno::Reference
<linguistic2::XSpellChecker
> xSpellChecker(xLngSvcMgr
->getSpellChecker());
5390 std::cerr
<< "Preloading dictionaries: ";
5391 css::uno::Reference
<linguistic2::XSupportedLocales
> xSpellLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
5392 uno::Sequence
< css::lang::Locale
> aLocales
= xSpellLocales
->getLocales();
5393 for (auto &it
: aLocales
)
5395 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
5396 css::beans::PropertyValues aNone
;
5397 xSpellChecker
->isValid("forcefed", it
, aNone
);
5401 // preload all available thesauri
5402 css::uno::Reference
<linguistic2::XThesaurus
> xThesaurus(xLngSvcMgr
->getThesaurus());
5403 css::uno::Reference
<linguistic2::XSupportedLocales
> xThesLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
5404 aLocales
= xThesLocales
->getLocales();
5405 std::cerr
<< "Preloading thesauri: ";
5406 for (auto &it
: aLocales
)
5408 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
5409 css::beans::PropertyValues aNone
;
5410 xThesaurus
->queryMeanings("forcefed", it
, aNone
);
5414 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
= css::ui::GlobalAcceleratorConfiguration::create(
5415 comphelper::getProcessComponentContext());
5416 xGlobalCfg
->getAllKeyEvents();
5418 std::cerr
<< "Preload icons\n";
5419 ImageTree
&images
= ImageTree::get();
5420 images
.getImageUrl("forcefed.png", "style", "FO_oo");
5422 std::cerr
<< "Preload languages\n";
5424 // force load language singleton
5425 SvtLanguageTable::HasLanguageType(LANGUAGE_SYSTEM
);
5426 (void)LanguageTag::isValidBcp47("foo", nullptr);
5428 std::cerr
<< "Preload fonts\n";
5430 // Initialize fonts.
5431 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
5434 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
5436 aLocales
= xSpell
->getLocales();
5439 for (const auto& aLocale
: std::as_const(aLocales
))
5441 //TODO: Add more types and cache more aggressively. For now this initializes the fontcache.
5442 using namespace ::com::sun::star::i18n::ScriptType
;
5444 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), LATIN
);
5445 OutputDevice::GetDefaultFont(DefaultFontType::LATIN_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
5446 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), ASIAN
);
5447 OutputDevice::GetDefaultFont(DefaultFontType::CJK_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
5448 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), COMPLEX
);
5449 OutputDevice::GetDefaultFont(DefaultFontType::CTL_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
5452 // Set user profile's path back to the original one
5453 rtl::Bootstrap::set("UserInstallation", sUserPath
);
5458 class ProfileZoneDumper
: public AutoTimer
5460 static const int dumpTimeoutMS
= 5000;
5462 ProfileZoneDumper() : AutoTimer( "zone dumper" )
5464 SetTimeout(dumpTimeoutMS
);
5467 virtual void Invoke() override
5469 const css::uno::Sequence
<OUString
> aEvents
=
5470 comphelper::ProfileRecording::getRecordingAndClear();
5471 OStringBuffer aOutput
;
5472 for (const auto &s
: aEvents
)
5474 aOutput
.append(OUStringToOString(s
, RTL_TEXTENCODING_UTF8
));
5475 aOutput
.append("\n");
5477 OString aChunk
= aOutput
.makeStringAndClear();
5478 if (gImpl
&& gImpl
->mpCallback
)
5479 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: */