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 <sfx2/lokhelper.hxx>
11 #include <config_buildconfig.h>
12 #include <config_features.h>
21 #include <unicode/udata.h>
22 #include <unicode/ucnv.h>
24 #import <Foundation/Foundation.h>
25 #import <CoreGraphics/CoreGraphics.h>
29 #undef HAVE_MALLOC_TRIM
35 # define HAVE_MALLOC_TRIM
40 #include <osl/detail/android-bootstrap.h>
44 #include <osl/detail/emscripten-bootstrap.h>
50 #include <string_view>
52 #include <boost/property_tree/json_parser.hpp>
53 #include <boost/algorithm/string.hpp>
55 #include <LibreOfficeKit/LibreOfficeKit.h>
56 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
58 #include <sal/log.hxx>
60 #include <vcl/errinf.hxx>
61 #include <vcl/lok.hxx>
62 #include <o3tl/any.hxx>
63 #include <o3tl/unit_conversion.hxx>
64 #include <o3tl/string_view.hxx>
65 #include <osl/file.hxx>
66 #include <osl/process.h>
67 #include <osl/thread.h>
68 #include <rtl/bootstrap.hxx>
69 #include <rtl/strbuf.hxx>
70 #include <rtl/uri.hxx>
71 #include <svl/zforlist.hxx>
72 #include <linguistic/misc.hxx>
73 #include <cppuhelper/bootstrap.hxx>
74 #include <comphelper/base64.hxx>
75 #include <comphelper/dispatchcommand.hxx>
76 #include <comphelper/lok.hxx>
77 #include <comphelper/processfactory.hxx>
78 #include <comphelper/string.hxx>
79 #include <comphelper/profilezone.hxx>
80 #include <comphelper/propertysequence.hxx>
81 #include <comphelper/propertyvalue.hxx>
82 #include <comphelper/scopeguard.hxx>
83 #include <comphelper/threadpool.hxx>
84 #include <comphelper/servicehelper.hxx>
85 #include <comphelper/sequenceashashmap.hxx>
87 #include <com/sun/star/document/MacroExecMode.hpp>
88 #include <com/sun/star/beans/XPropertySet.hpp>
89 #include <com/sun/star/container/XNameAccess.hpp>
90 #include <com/sun/star/document/XDocumentLanguages.hpp>
91 #include <com/sun/star/frame/Desktop.hpp>
92 #include <com/sun/star/frame/DispatchResultEvent.hpp>
93 #include <com/sun/star/frame/DispatchResultState.hpp>
94 #include <com/sun/star/frame/XDispatchProvider.hpp>
95 #include <com/sun/star/frame/XDispatchResultListener.hpp>
96 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
97 #include <com/sun/star/frame/XStorable.hpp>
98 #include <com/sun/star/lang/Locale.hpp>
99 #include <com/sun/star/lang/XComponent.hpp>
100 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
101 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
102 #include <com/sun/star/util/URLTransformer.hpp>
103 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
104 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
105 #include <com/sun/star/datatransfer/XTransferable2.hpp>
106 #include <com/sun/star/text/TextContentAnchorType.hpp>
107 #include <com/sun/star/document/XRedlinesSupplier.hpp>
108 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
110 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
111 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
112 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
113 #include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
114 #include <com/sun/star/security/XCertificate.hpp>
116 #include <com/sun/star/linguistic2/LanguageGuessing.hpp>
117 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
118 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
119 #include <com/sun/star/i18n/LocaleCalendar2.hpp>
120 #include <com/sun/star/i18n/ScriptType.hpp>
121 #include <com/sun/star/lang/DisposedException.hpp>
123 #include <editeng/flstitem.hxx>
125 #include <sfx2/app.hxx>
127 #include <sfx2/objsh.hxx>
128 #include <sfx2/docfilt.hxx>
129 #include <sfx2/docfile.hxx>
130 #include <sfx2/viewsh.hxx>
131 #include <sfx2/viewfrm.hxx>
132 #include <sfx2/msgpool.hxx>
133 #include <sfx2/dispatch.hxx>
134 #include <sfx2/lokcomponenthelpers.hxx>
135 #include <sfx2/DocumentSigner.hxx>
136 #include <sfx2/sidebar/SidebarDockingWindow.hxx>
137 #include <sfx2/sidebar/SidebarController.hxx>
138 #include <svl/numformat.hxx>
139 #include <svx/dialmgr.hxx>
140 #include <svx/strings.hrc>
141 #include <svx/svdview.hxx>
142 #include <svx/svxids.hrc>
143 #include <svx/ucsubset.hxx>
144 #include <vcl/vclevent.hxx>
145 #include <vcl/GestureEventPan.hxx>
146 #include <vcl/svapp.hxx>
147 #include <unotools/resmgr.hxx>
148 #include <tools/fract.hxx>
149 #include <tools/json_writer.hxx>
150 #include <svtools/ctrltool.hxx>
151 #include <svtools/langtab.hxx>
152 #include <vcl/fontcharmap.hxx>
154 #include <vcl/sysdata.hxx>
156 #include <vcl/virdev.hxx>
157 #include <vcl/ImageTree.hxx>
158 #include <vcl/ITiledRenderable.hxx>
159 #include <vcl/dialoghelper.hxx>
161 #include <vcl/BitmapReadAccess.hxx>
163 #include <unicode/uchar.h>
164 #include <unotools/securityoptions.hxx>
165 #include <unotools/confignode.hxx>
166 #include <unotools/syslocaleoptions.hxx>
167 #include <unotools/mediadescriptor.hxx>
168 #include <unotools/pathoptions.hxx>
169 #include <unotools/tempfile.hxx>
170 #include <unotools/streamwrap.hxx>
171 #include <osl/module.hxx>
172 #include <comphelper/sequence.hxx>
173 #include <sfx2/sfxbasemodel.hxx>
174 #include <svl/undo.hxx>
175 #include <unotools/datetime.hxx>
176 #include <i18nlangtag/mslangid.hxx>
177 #include <i18nlangtag/languagetag.hxx>
178 #include <vcl/abstdlg.hxx>
179 #include <comphelper/diagnose_ex.hxx>
180 #include <vcl/uitest/uiobject.hxx>
181 #include <vcl/jsdialog/executor.hxx>
183 // Needed for getUndoManager()
184 #include <com/sun/star/document/XUndoManager.hpp>
185 #include <com/sun/star/document/XUndoManagerSupplier.hpp>
186 #include <com/sun/star/document/XLinkTargetSupplier.hpp>
187 #include <editeng/sizeitem.hxx>
188 #include <svx/rulritem.hxx>
189 #include <svx/pageitem.hxx>
193 #include "../app/cmdlineargs.hxx"
194 // We also need to hackily be able to start the main libreoffice thread:
195 #include "../app/sofficemain.h"
196 #include "../app/officeipcthread.hxx"
197 #include <lib/init.hxx>
199 #include "lokinteractionhandler.hxx"
200 #include "lokclipboard.hxx"
201 #include <officecfg/Office/Common.hxx>
202 #include <officecfg/Office/Impress.hxx>
203 #include <officecfg/Office/Linguistic.hxx>
204 #include <unotools/optionsdlg.hxx>
205 #include <svl/ctloptions.hxx>
206 #include <svtools/accessibilityoptions.hxx>
207 #include <svtools/colorcfg.hxx>
208 #include <svtools/miscopt.hxx>
209 #include <svtools/slidesorterbaropt.hxx>
210 #include <unotools/cmdoptions.hxx>
211 #include <unotools/compatibility.hxx>
212 #include <unotools/fltrcfg.hxx>
213 #include <unotools/lingucfg.hxx>
214 #include <unotools/moduleoptions.hxx>
215 #include <unotools/searchopt.hxx>
216 #include <unotools/useroptions.hxx>
217 #include <unotools/viewoptions.hxx>
218 #include <vcl/settings.hxx>
220 #include <officecfg/Setup.hxx>
221 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
222 #include <svtools/acceleratorexecute.hxx>
226 using namespace desktop
;
229 static LibLibreOffice_Impl
*gImpl
= nullptr;
230 static bool lok_preinit_2_called
= false;
231 static std::weak_ptr
< LibreOfficeKitClass
> gOfficeClass
;
232 static std::weak_ptr
< LibreOfficeKitDocumentClass
> gDocumentClass
;
234 static void SetLastExceptionMsg(const OUString
& s
= OUString())
236 SAL_WARN_IF(!s
.isEmpty(), "lok", "lok exception '" + s
+ "'");
238 gImpl
->maLastExceptionMsg
= s
;
246 const char *filterName
;
249 class TraceEventDumper
: public AutoTimer
251 static const int dumpTimeoutMS
= 5000;
254 TraceEventDumper() : AutoTimer( "Trace Event dumper" )
256 SetTimeout(dumpTimeoutMS
);
260 virtual void Invoke() override
265 static void flushRecordings()
267 const css::uno::Sequence
<OUString
> aEvents
=
268 comphelper::TraceEvent::getRecordingAndClear();
269 OStringBuffer aOutput
;
270 for (const auto &s
: aEvents
)
272 aOutput
.append(OUStringToOString(s
, RTL_TEXTENCODING_UTF8
)
275 if (aOutput
.getLength() > 0)
277 OString aChunk
= aOutput
.makeStringAndClear();
278 if (gImpl
&& gImpl
->mpCallback
)
279 gImpl
->mpCallback(LOK_CALLBACK_PROFILE_FRAME
, aChunk
.getStr(), gImpl
->mpCallbackData
);
284 } // unnamed namespace
286 static TraceEventDumper
*traceEventDumper
= nullptr;
288 const ExtensionMap aWriterExtensionMap
[] =
290 { "doc", "MS Word 97" },
291 { "docm", "MS Word 2007 XML VBA" },
292 { "docx", "MS Word 2007 XML" },
293 { "fodt", "OpenDocument Text Flat XML" },
294 { "html", "HTML (StarWriter)" },
295 { "odt", "writer8" },
296 { "ott", "writer8_template" },
297 { "pdf", "writer_pdf_Export" },
299 { "rtf", "Rich Text Format" },
301 { "xhtml", "XHTML Writer File" },
302 { "png", "writer_png_Export" },
303 { "xml", "writer_indexing_export" },
307 const ExtensionMap aCalcExtensionMap
[] =
309 { "csv", "Text - txt - csv (StarCalc)" },
310 { "fods", "OpenDocument Spreadsheet Flat XML" },
311 { "html", "HTML (StarCalc)" },
313 { "ots", "calc8_template" },
314 { "pdf", "calc_pdf_Export" },
315 { "xhtml", "XHTML Calc File" },
316 { "xls", "MS Excel 97" },
317 { "xlsm", "Calc MS Excel 2007 VBA XML" },
318 { "xlsx", "Calc MS Excel 2007 XML" },
319 { "png", "calc_png_Export" },
323 const ExtensionMap aImpressExtensionMap
[] =
325 { "fodp", "OpenDocument Presentation Flat XML" },
326 { "html", "impress_html_Export" },
327 { "odg", "impress8_draw" },
328 { "odp", "impress8" },
329 { "otp", "impress8_template" },
330 { "pdf", "impress_pdf_Export" },
331 { "potm", "Impress MS PowerPoint 2007 XML Template" },
332 { "pot", "MS PowerPoint 97 Vorlage" },
333 { "pptm", "Impress MS PowerPoint 2007 XML VBA" },
334 { "pptx", "Impress MS PowerPoint 2007 XML" },
335 { "pps", "MS PowerPoint 97 Autoplay" },
336 { "ppt", "MS PowerPoint 97" },
337 { "svg", "impress_svg_Export" },
338 { "xhtml", "XHTML Impress File" },
339 { "png", "impress_png_Export"},
343 const ExtensionMap aDrawExtensionMap
[] =
345 { "fodg", "draw_ODG_FlatXML" },
346 { "html", "draw_html_Export" },
348 { "pdf", "draw_pdf_Export" },
349 { "svg", "draw_svg_Export" },
350 { "xhtml", "XHTML Draw File" },
351 { "png", "draw_png_Export"},
355 static OUString
getUString(const char* pString
)
357 if (pString
== nullptr)
360 std::string_view
sString(pString
, strlen(pString
));
361 return OStringToOUString(sString
, RTL_TEXTENCODING_UTF8
);
364 // Tolerate embedded \0s etc.
365 static char *convertOString(const OString
&rStr
)
367 char* pMemory
= static_cast<char*>(malloc(rStr
.getLength() + 1));
368 assert(pMemory
); // don't tolerate failed allocations.
369 memcpy(pMemory
, rStr
.getStr(), rStr
.getLength() + 1);
373 static char *convertOUString(std::u16string_view aStr
)
375 return convertOString(OUStringToOString(aStr
, RTL_TEXTENCODING_UTF8
));
378 /// Try to convert a relative URL to an absolute one, unless it already looks like a URL.
379 static OUString
getAbsoluteURL(const char* pURL
)
381 OUString
aURL(getUString(pURL
));
385 // convert relative paths to absolute ones
386 OUString aWorkingDir
;
387 osl_getProcessWorkingDir(&aWorkingDir
.pData
);
388 if (!aWorkingDir
.endsWith("/"))
393 return rtl::Uri::convertRelToAbs(aWorkingDir
, aURL
);
395 catch (const rtl::MalformedUriException
&)
402 std::vector
<beans::PropertyValue
> desktop::jsonToPropertyValuesVector(const char* pJSON
)
404 std::vector
<beans::PropertyValue
> aArguments
;
405 if (pJSON
&& pJSON
[0] != '\0')
407 aArguments
= comphelper::JsonToPropertyValues(pJSON
);
412 static bool extractLinks(const uno::Reference
< container::XNameAccess
>& xLinks
, bool subcontent
, OUStringBuffer
& jsonText
)
414 const uno::Sequence
< OUString
> aNames( xLinks
->getElementNames() );
416 const sal_uLong nLinks
= aNames
.getLength();
417 const OUString
* pNames
= aNames
.getConstArray();
418 const OUString
aProp_LinkDisplayName( "LinkDisplayName" );
419 const OUString
aProp_LinkTarget( "com.sun.star.document.LinkTarget" );
420 bool bIsTarget
= false;
421 for( sal_uLong i
= 0; i
< nLinks
; i
++ )
424 OUString
aLink( *pNames
++ );
429 aAny
= xLinks
->getByName( aLink
);
431 catch(const uno::Exception
&)
433 // if the name of the target was invalid (like empty headings)
434 // no object can be provided
440 uno::Reference
< beans::XPropertySet
> xTarget
;
441 if( aAny
>>= xTarget
)
445 // get name to display
446 aAny
= xTarget
->getPropertyValue( aProp_LinkDisplayName
);
447 OUString aDisplayName
;
448 aAny
>>= aDisplayName
;
449 OUString
aStrDisplayname ( aDisplayName
);
453 jsonText
.append("\"");
454 jsonText
.append(aStrDisplayname
);
455 jsonText
.append("\": \"");
456 jsonText
.append(aLink
);
457 jsonText
.append("\"");
460 jsonText
.append(", ");
465 uno::Reference
< lang::XServiceInfo
> xSI( xTarget
, uno::UNO_QUERY
);
466 bIsTarget
= xSI
->supportsService( aProp_LinkTarget
);
470 jsonText
.append("}");
473 jsonText
.append(", ");
476 jsonText
.append("\"");
477 jsonText
.append(aStrDisplayname
);
478 jsonText
.append("\": ");
482 jsonText
.append("true");
485 jsonText
.append("{");
488 uno::Reference
< document::XLinkTargetSupplier
> xLTS( xTarget
, uno::UNO_QUERY
);
491 extractLinks(xLTS
->getLinks(), true, jsonText
);
496 SAL_WARN("lok", "extractLinks: Exception");
503 static void unoAnyToJson(tools::JsonWriter
& rJson
, std::string_view pNodeName
, const uno::Any
& anyItem
)
505 auto aNode
= rJson
.startNode(pNodeName
);
506 OUString aType
= anyItem
.getValueTypeName();
507 rJson
.put("type", aType
);
509 if (aType
== "string")
510 rJson
.put("value", anyItem
.get
<OUString
>());
511 else if (aType
== "unsigned long")
512 rJson
.put("value", OString::number(anyItem
.get
<sal_uInt32
>()));
513 else if (aType
== "long")
514 rJson
.put("value", OString::number(anyItem
.get
<sal_Int32
>()));
515 else if (aType
== "[]any")
517 uno::Sequence
<uno::Any
> aSeq
;
518 if (anyItem
>>= aSeq
)
520 auto valueNode
= rJson
.startNode("value");
522 for (auto i
= 0; i
< aSeq
.getLength(); ++i
)
524 unoAnyToJson(rJson
, OString::number(i
), aSeq
[i
]);
530 static int lcl_getViewId(std::string_view payload
);
534 RectangleAndPart
RectangleAndPart::Create(const OString
& rPayload
)
536 RectangleAndPart aRet
;
537 if (rPayload
.startsWith("EMPTY")) // payload starts with "EMPTY"
539 aRet
.m_aRectangle
= tools::Rectangle(0, 0, SfxLokHelper::MaxTwips
, SfxLokHelper::MaxTwips
);
540 if (comphelper::LibreOfficeKit::isPartInInvalidation())
542 int nSeparatorPos
= rPayload
.indexOf(',', 6);
543 bool bHasMode
= nSeparatorPos
> 0;
546 aRet
.m_nPart
= o3tl::toInt32(rPayload
.subView(6, nSeparatorPos
- 6));
547 assert(rPayload
.getLength() > nSeparatorPos
);
548 aRet
.m_nMode
= o3tl::toInt32(rPayload
.subView(nSeparatorPos
+ 1));
552 aRet
.m_nPart
= o3tl::toInt32(rPayload
.subView(6));
560 // Read '<left>, <top>, <width>, <height>[, <part>, <mode>]'. C++ streams are simpler but slower.
561 const char* pos
= rPayload
.getStr();
562 const char* end
= rPayload
.getStr() + rPayload
.getLength();
563 tools::Long nLeft
= rtl_str_toInt64_WithLength(pos
, 10, end
- pos
);
568 tools::Long nTop
= rtl_str_toInt64_WithLength(pos
, 10, end
- pos
);
573 tools::Long nWidth
= rtl_str_toInt64_WithLength(pos
, 10, end
- pos
);
578 tools::Long nHeight
= rtl_str_toInt64_WithLength(pos
, 10, end
- pos
);
579 tools::Long nPart
= INT_MIN
;
580 tools::Long nMode
= 0;
581 if (comphelper::LibreOfficeKit::isPartInInvalidation())
587 nPart
= rtl_str_toInt64_WithLength(pos
, 10, end
- pos
);
589 while( *pos
&& *pos
!= ',' )
595 nMode
= rtl_str_toInt64_WithLength(pos
, 10, end
- pos
);
599 aRet
.m_aRectangle
= SanitizedRectangle(nLeft
, nTop
, nWidth
, nHeight
);
600 aRet
.m_nPart
= nPart
;
601 aRet
.m_nMode
= nMode
;
605 tools::Rectangle
RectangleAndPart::SanitizedRectangle(tools::Long nLeft
, tools::Long nTop
, tools::Long nWidth
, tools::Long nHeight
)
607 if (nWidth
<= 0 || nHeight
<= 0)
608 return tools::Rectangle();
610 // The top-left corner starts at (0, 0).
611 // Anything negative is invalid.
624 if (nWidth
> 0 && nHeight
> 0)
625 return tools::Rectangle(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
626 // Else set empty rect.
627 return tools::Rectangle();
630 tools::Rectangle
RectangleAndPart::SanitizedRectangle(const tools::Rectangle
& rect
)
632 return SanitizedRectangle(rect
.Left(), rect
.Top(), rect
.getOpenWidth(), rect
.getOpenHeight());
635 const OString
& CallbackFlushHandler::CallbackData::getPayload() const
637 if(PayloadString
.isEmpty())
639 // Do to-string conversion on demand, as many calls will get dropped without
640 // needing the string.
641 if(PayloadObject
.which() == 1)
642 PayloadString
= getRectangleAndPart().toString();
644 return PayloadString
;
647 void CallbackFlushHandler::CallbackData::updateRectangleAndPart(const RectangleAndPart
& rRectAndPart
)
649 PayloadObject
= rRectAndPart
;
650 PayloadString
.clear(); // will be set on demand if needed
653 const RectangleAndPart
& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
655 // TODO: In case of unittests, they do not pass invalidations in binary but as text messages.
656 // LO core should preferably always pass binary for performance.
657 if(PayloadObject
.which() != 1)
658 PayloadObject
= RectangleAndPart::Create(PayloadString
);
659 return boost::get
<RectangleAndPart
>(PayloadObject
);
662 boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::setJson(const std::string
& payload
)
664 boost::property_tree::ptree aTree
;
665 std::stringstream
aStream(payload
);
666 boost::property_tree::read_json(aStream
, aTree
);
668 // Let boost normalize the payload so it always matches the cache.
671 // Return reference to the cached object.
672 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
675 void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree
& rTree
)
677 std::stringstream aJSONStream
;
678 constexpr bool bPretty
= false; // Don't waste time and bloat logs.
679 boost::property_tree::write_json(aJSONStream
, rTree
, bPretty
);
680 PayloadString
= OString(o3tl::trim(aJSONStream
.str()));
682 PayloadObject
= rTree
;
685 const boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::getJson() const
687 assert(PayloadObject
.which() == 2);
688 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
691 int CallbackFlushHandler::CallbackData::getViewId() const
695 assert(PayloadObject
.which() == 3);
696 return boost::get
<int>(PayloadObject
);
698 return lcl_getViewId(getPayload());
701 bool CallbackFlushHandler::CallbackData::validate() const
703 switch (PayloadObject
.which())
711 return getRectangleAndPart().toString().getStr() == getPayload();
716 std::stringstream aJSONStream
;
717 boost::property_tree::write_json(aJSONStream
, getJson(), false);
718 const std::string aExpected
= boost::trim_copy(aJSONStream
.str());
719 return getPayload() == std::string_view(aExpected
);
724 return getViewId() == lcl_getViewId( getPayload());
727 assert(!"Unknown variant type; please add an entry to validate.");
733 } // namespace desktop
735 static bool lcl_isViewCallbackType(const int type
)
739 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
740 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
741 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
742 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
743 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
751 static bool isUpdatedType(int type
)
755 case LOK_CALLBACK_TEXT_SELECTION
:
756 case LOK_CALLBACK_TEXT_SELECTION_START
:
757 case LOK_CALLBACK_TEXT_SELECTION_END
:
764 static bool isUpdatedTypePerViewId(int type
)
768 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
769 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
770 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
777 static int lcl_getViewId(std::string_view payload
)
779 // this is a cheap way how to get the viewId from a JSON message; proper
780 // parsing is terribly expensive, and we just need the viewId here
781 size_t viewIdPos
= payload
.find("viewId");
782 if (viewIdPos
== std::string::npos
)
785 size_t numberPos
= payload
.find(":", viewIdPos
+ 6);
786 if (numberPos
== std::string::npos
)
789 for (++numberPos
; numberPos
< payload
.length(); ++numberPos
)
791 if (payload
[numberPos
] == ',' || payload
[numberPos
] == '}' || (payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9'))
795 if (numberPos
< payload
.length() && payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9')
796 return o3tl::toInt32(payload
.substr(numberPos
));
803 std::string
extractCertificate(const std::string
& certificate
)
805 const std::string
header("-----BEGIN CERTIFICATE-----");
806 const std::string
footer("-----END CERTIFICATE-----");
810 size_t pos1
= certificate
.find(header
);
811 if (pos1
== std::string::npos
)
814 size_t pos2
= certificate
.find(footer
, pos1
+ 1);
815 if (pos2
== std::string::npos
)
818 pos1
= pos1
+ header
.length();
821 return certificate
.substr(pos1
, pos2
);
824 std::string
extractPrivateKey(const std::string
& privateKey
)
826 const std::string
header("-----BEGIN PRIVATE KEY-----");
827 const std::string
footer("-----END PRIVATE KEY-----");
831 size_t pos1
= privateKey
.find(header
);
832 if (pos1
== std::string::npos
)
835 size_t pos2
= privateKey
.find(footer
, pos1
+ 1);
836 if (pos2
== std::string::npos
)
839 pos1
= pos1
+ header
.length();
842 return privateKey
.substr(pos1
, pos2
);
845 OUString
lcl_getCurrentDocumentMimeType(const LibLODocument_Impl
* pDocument
)
847 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
851 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
855 SfxMedium
* pMedium
= pObjectShell
->GetMedium();
859 auto pFilter
= pMedium
->GetFilter();
863 return pFilter
->GetMimeType();
866 // Gets an undo manager to enter and exit undo context. Needed by ToggleOrientation
867 css::uno::Reference
< css::document::XUndoManager
> getUndoManager( const css::uno::Reference
< css::frame::XFrame
>& rxFrame
)
869 const css::uno::Reference
< css::frame::XController
>& xController
= rxFrame
->getController();
870 if ( xController
.is() )
872 const css::uno::Reference
< css::frame::XModel
>& xModel
= xController
->getModel();
875 const css::uno::Reference
< css::document::XUndoManagerSupplier
> xSuppUndo( xModel
, css::uno::UNO_QUERY_THROW
);
876 return css::uno::Reference
< css::document::XUndoManager
>( xSuppUndo
->getUndoManager(), css::uno::UNO_SET_THROW
);
880 return css::uno::Reference
< css::document::XUndoManager
> ();
883 // Adjusts page margins for Writer doc. Needed by ToggleOrientation
884 void ExecuteMarginLRChange(
885 const tools::Long nPageLeftMargin
,
886 const tools::Long nPageRightMargin
,
887 SvxLongLRSpaceItem
* pPageLRMarginItem
)
889 pPageLRMarginItem
->SetLeft( nPageLeftMargin
);
890 pPageLRMarginItem
->SetRight( nPageRightMargin
);
891 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_LRSPACE
,
892 SfxCallMode::RECORD
, { pPageLRMarginItem
});
895 // Adjusts page margins for Writer doc. Needed by ToggleOrientation
896 void ExecuteMarginULChange(
897 const tools::Long nPageTopMargin
,
898 const tools::Long nPageBottomMargin
,
899 SvxLongULSpaceItem
* pPageULMarginItem
)
901 pPageULMarginItem
->SetUpper( nPageTopMargin
);
902 pPageULMarginItem
->SetLower( nPageBottomMargin
);
903 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_ULSPACE
,
904 SfxCallMode::RECORD
, { pPageULMarginItem
});
907 // Main function which toggles page orientation of the Writer doc. Needed by ToggleOrientation
908 void ExecuteOrientationChange()
910 SfxViewFrame
* pViewFrm
= SfxViewFrame::Current();
914 std::unique_ptr
<SvxPageItem
> pPageItem(new SvxPageItem(SID_ATTR_PAGE
));
916 // 1mm in twips rounded
917 // This should be in sync with MINBODY in sw/source/uibase/sidebar/PageMarginControl.hxx
918 constexpr tools::Long MINBODY
= o3tl::toTwips(1, o3tl::Length::mm
);
920 css::uno::Reference
< css::document::XUndoManager
> mxUndoManager(
921 getUndoManager( pViewFrm
->GetFrame().GetFrameInterface() ) );
923 if ( mxUndoManager
.is() )
924 mxUndoManager
->enterUndoContext( "" );
927 const SvxSizeItem
* pSizeItem
;
928 pViewFrm
->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_SIZE
, pSizeItem
);
929 std::unique_ptr
<SvxSizeItem
> pPageSizeItem(pSizeItem
->Clone());
931 const SvxLongLRSpaceItem
* pLRSpaceItem
;
932 pViewFrm
->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_LRSPACE
, pLRSpaceItem
);
933 std::unique_ptr
<SvxLongLRSpaceItem
> pPageLRMarginItem(pLRSpaceItem
->Clone());
935 const SvxLongULSpaceItem
* pULSpaceItem
;
936 pViewFrm
->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_ULSPACE
, pULSpaceItem
);
937 std::unique_ptr
<SvxLongULSpaceItem
> pPageULMarginItem(pULSpaceItem
->Clone());
940 bool bIsLandscape
= false;
941 if ( pPageSizeItem
->GetSize().Width() > pPageSizeItem
->GetSize().Height())
944 // toggle page orientation
945 pPageItem
->SetLandscape(!bIsLandscape
);
948 // swap the width and height of the page size
949 const tools::Long nRotatedWidth
= pPageSizeItem
->GetSize().Height();
950 const tools::Long nRotatedHeight
= pPageSizeItem
->GetSize().Width();
951 pPageSizeItem
->SetSize(Size(nRotatedWidth
, nRotatedHeight
));
954 // apply changed attributes
955 if (SfxViewShell::Current())
957 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_SIZE
,
958 SfxCallMode::RECORD
, { pPageSizeItem
.get(), pPageItem
.get() });
963 // check, if margin values still fit to the changed page size.
964 // if not, adjust margin values
966 const tools::Long nML
= pPageLRMarginItem
->GetLeft();
967 const tools::Long nMR
= pPageLRMarginItem
->GetRight();
968 const tools::Long nTmpPW
= nML
+ nMR
+ MINBODY
;
970 const tools::Long nPW
= pPageSizeItem
->GetSize().Width();
976 ExecuteMarginLRChange( pPageLRMarginItem
->GetLeft(), nMR
- (nTmpPW
- nPW
), pPageLRMarginItem
.get() );
980 ExecuteMarginLRChange( nML
- (nTmpPW
- nPW
), pPageLRMarginItem
->GetRight(), pPageLRMarginItem
.get() );
984 const tools::Long nMT
= pPageULMarginItem
->GetUpper();
985 const tools::Long nMB
= pPageULMarginItem
->GetLower();
986 const tools::Long nTmpPH
= nMT
+ nMB
+ MINBODY
;
988 const tools::Long nPH
= pPageSizeItem
->GetSize().Height();
994 ExecuteMarginULChange( pPageULMarginItem
->GetUpper(), nMB
- ( nTmpPH
- nPH
), pPageULMarginItem
.get() );
998 ExecuteMarginULChange( nMT
- ( nTmpPH
- nPH
), pPageULMarginItem
->GetLower(), pPageULMarginItem
.get() );
1003 if ( mxUndoManager
.is() )
1004 mxUndoManager
->leaveUndoContext();
1007 void setupSidebar(std::u16string_view sidebarDeckId
= u
"")
1009 SfxViewShell
* pViewShell
= SfxViewShell::Current();
1010 SfxViewFrame
* pViewFrame
= pViewShell
? &pViewShell
->GetViewFrame() : nullptr;
1013 if (!pViewFrame
->GetChildWindow(SID_SIDEBAR
))
1014 pViewFrame
->SetChildWindow(SID_SIDEBAR
, false /* create it */, true /* focus */);
1016 pViewFrame
->ShowChildWindow(SID_SIDEBAR
, true);
1018 // Force synchronous population of panels
1019 SfxChildWindow
*pChild
= pViewFrame
->GetChildWindow(SID_SIDEBAR
);
1023 auto pDockingWin
= dynamic_cast<sfx2::sidebar::SidebarDockingWindow
*>(pChild
->GetWindow());
1027 pViewFrame
->ShowChildWindow( SID_SIDEBAR
);
1029 const rtl::Reference
<sfx2::sidebar::SidebarController
>& xController
1030 = pDockingWin
->GetOrCreateSidebarController();
1032 xController
->FadeIn();
1033 xController
->RequestOpenDeck();
1035 if (!sidebarDeckId
.empty())
1037 xController
->SwitchToDeck(sidebarDeckId
);
1041 xController
->SwitchToDefaultDeck();
1044 pDockingWin
->SyncUpdate();
1047 SetLastExceptionMsg("No view shell or sidebar");
1052 SfxViewShell
* pViewShell
= SfxViewShell::Current();
1053 SfxViewFrame
* pViewFrame
= pViewShell
? &pViewShell
->GetViewFrame() : nullptr;
1055 pViewFrame
->SetChildWindow(SID_SIDEBAR
, false , false );
1057 SetLastExceptionMsg("No view shell or sidebar");
1060 } // end anonymous namespace
1062 // Could be anonymous in principle, but for the unit testing purposes, we
1063 // declare it in init.hxx.
1064 OUString
desktop::extractParameter(OUString
& rOptions
, std::u16string_view rName
)
1068 OUString
aNameEquals(OUString::Concat(rName
) + "=");
1069 OUString
aCommaNameEquals(OUString::Concat(",") + rName
+ "=");
1072 if (rOptions
.startsWith(aNameEquals
))
1074 size_t nLen
= aNameEquals
.getLength();
1075 int nComma
= rOptions
.indexOf(",", nLen
);
1078 aValue
= rOptions
.copy(nLen
, nComma
- nLen
);
1079 rOptions
= rOptions
.copy(nComma
+ 1);
1083 aValue
= rOptions
.copy(nLen
);
1087 else if ((nIndex
= rOptions
.indexOf(aCommaNameEquals
)) >= 0)
1089 size_t nLen
= aCommaNameEquals
.getLength();
1090 int nComma
= rOptions
.indexOf(",", nIndex
+ nLen
);
1093 aValue
= rOptions
.copy(nIndex
+ nLen
, nComma
- nIndex
- nLen
);
1094 rOptions
= OUString::Concat(rOptions
.subView(0, nIndex
)) + rOptions
.subView(nComma
);
1098 aValue
= rOptions
.copy(nIndex
+ nLen
);
1099 rOptions
= rOptions
.copy(0, nIndex
);
1109 static void doc_destroy(LibreOfficeKitDocument
* pThis
);
1110 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* pUrl
, const char* pFormat
, const char* pFilterOptions
);
1111 static int doc_getDocumentType(LibreOfficeKitDocument
* pThis
);
1112 static int doc_getParts(LibreOfficeKitDocument
* pThis
);
1113 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
);
1114 static int doc_getPart(LibreOfficeKitDocument
* pThis
);
1115 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
);
1116 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
);
1117 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
);
1118 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
);
1119 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
, int nPartMode
);
1120 static int doc_getEditMode(LibreOfficeKitDocument
* pThis
);
1121 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
1122 unsigned char* pBuffer
,
1123 const int nCanvasWidth
, const int nCanvasHeight
,
1124 const int nTilePosX
, const int nTilePosY
,
1125 const int nTileWidth
, const int nTileHeight
);
1126 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
1127 unsigned char* pBuffer
,
1130 const int nCanvasWidth
, const int nCanvasHeight
,
1131 const int nTilePosX
, const int nTilePosY
,
1132 const int nTileWidth
, const int nTileHeight
);
1133 static int doc_getTileMode(LibreOfficeKitDocument
* pThis
);
1134 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
1137 static void doc_getDataArea(LibreOfficeKitDocument
* pThis
,
1141 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
1142 const char* pArguments
);
1144 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
1145 LibreOfficeKitCallback pCallback
,
1147 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
,
1151 static void doc_setBlockedCommandList(LibreOfficeKitDocument
* pThis
,
1153 const char* blockedCommandList
);
1155 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
,
1159 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
,
1160 unsigned nLOKWindowId
,
1163 static void doc_sendDialogEvent(LibreOfficeKitDocument
* pThis
,
1164 unsigned long long int nLOKWindowId
,
1165 const char* pArguments
);
1166 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* pThis
,
1167 unsigned nLOKWindowId
,
1171 static void doc_postMouseEvent (LibreOfficeKitDocument
* pThis
,
1178 static void doc_postWindowMouseEvent (LibreOfficeKitDocument
* pThis
,
1179 unsigned nLOKWindowId
,
1186 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* pThis
,
1187 unsigned nLOKWindowId
,
1192 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
,
1193 const char* pCommand
,
1194 const char* pArguments
,
1195 bool bNotifyWhenFinished
);
1196 static void doc_setWindowTextSelection(LibreOfficeKitDocument
* pThis
,
1197 unsigned nLOKWindowId
,
1201 static void doc_setTextSelection (LibreOfficeKitDocument
* pThis
,
1205 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
,
1206 const char* pMimeType
,
1207 char** pUsedMimeType
);
1208 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
);
1209 static int doc_getSelectionTypeAndText(LibreOfficeKitDocument
* pThis
,
1210 const char* pMimeType
,
1212 char** pUsedMimeType
);
1213 static int doc_getClipboard (LibreOfficeKitDocument
* pThis
,
1214 const char **pMimeTypes
,
1216 char ***pOutMimeTypes
,
1218 char ***pOutStreams
);
1219 static int doc_setClipboard (LibreOfficeKitDocument
* pThis
,
1220 const size_t nInCount
,
1221 const char **pInMimeTypes
,
1222 const size_t *pInSizes
,
1223 const char **pInStreams
);
1224 static bool doc_paste(LibreOfficeKitDocument
* pThis
,
1225 const char* pMimeType
,
1228 static void doc_setGraphicSelection (LibreOfficeKitDocument
* pThis
,
1232 static void doc_resetSelection (LibreOfficeKitDocument
* pThis
);
1233 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
);
1234 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
,
1235 int nTilePixelWidth
,
1236 int nTilePixelHeight
,
1238 int nTileTwipHeight
);
1239 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
);
1240 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
);
1241 static int doc_createView(LibreOfficeKitDocument
* pThis
);
1242 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
, const char* pOptions
);
1243 static void doc_destroyView(LibreOfficeKitDocument
* pThis
, int nId
);
1244 static void doc_setView(LibreOfficeKitDocument
* pThis
, int nId
);
1245 static int doc_getView(LibreOfficeKitDocument
* pThis
);
1246 static int doc_getViewsCount(LibreOfficeKitDocument
* pThis
);
1247 static bool doc_getViewIds(LibreOfficeKitDocument
* pThis
, int* pArray
, size_t nSize
);
1248 static void doc_setViewLanguage(LibreOfficeKitDocument
* pThis
, int nId
, const char* language
);
1249 static unsigned char* doc_renderFontOrientation(LibreOfficeKitDocument
* pThis
,
1250 const char *pFontName
,
1255 static unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
1256 const char *pFontName
,
1260 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
);
1262 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
1263 const int nX
, const int nY
,
1264 const int nWidth
, const int nHeight
);
1266 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
1267 const int nX
, const int nY
,
1268 const int nWidth
, const int nHeight
,
1269 const double fDPIScale
);
1271 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
1272 const int nX
, const int nY
,
1273 const int nWidth
, const int nHeight
,
1274 const double fDPIScale
, int viewId
);
1276 static void doc_postWindow(LibreOfficeKitDocument
* pThis
, unsigned
1277 nLOKWindowId
, int nAction
, const char* pData
);
1279 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
);
1281 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
1282 const unsigned char* pCertificateBinary
,
1283 const int nCertificateBinarySize
,
1284 const unsigned char* pPrivateKeyBinary
,
1285 const int nPrivateKeyBinarySize
);
1287 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
1288 const unsigned char* pCertificateBinary
,
1289 const int nCertificateBinarySize
);
1291 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
);
1293 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
);
1295 static void doc_resizeWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
1296 const int nWidth
, const int nHeight
);
1298 static void doc_completeFunction(LibreOfficeKitDocument
* pThis
, const char*);
1301 static void doc_sendFormFieldEvent(LibreOfficeKitDocument
* pThis
,
1302 const char* pArguments
);
1304 static bool doc_renderSearchResult(LibreOfficeKitDocument
* pThis
,
1305 const char* pSearchResult
, unsigned char** pBitmapBuffer
,
1306 int* pWidth
, int* pHeight
, size_t* pByteSize
);
1308 static void doc_sendContentControlEvent(LibreOfficeKitDocument
* pThis
, const char* pArguments
);
1310 static void doc_setViewTimezone(LibreOfficeKitDocument
* pThis
, int nId
, const char* timezone
);
1312 static void doc_setAccessibilityState(LibreOfficeKitDocument
* pThis
, int nId
, bool bEnabled
);
1314 static char* doc_getA11yFocusedParagraph(LibreOfficeKitDocument
* pThis
);
1316 static int doc_getA11yCaretPosition(LibreOfficeKitDocument
* pThis
);
1320 ITiledRenderable
* getTiledRenderable(LibreOfficeKitDocument
* pThis
)
1322 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1323 return dynamic_cast<ITiledRenderable
*>(pDocument
->mxComponent
.get());
1329 * Unfortunately clipboard creation using UNO is insanely baroque.
1330 * we also need to ensure that this works for the first view which
1331 * has no clear 'createView' called for it (unfortunately).
1333 rtl::Reference
<LOKClipboard
> forceSetClipboardForCurrentView(LibreOfficeKitDocument
*pThis
)
1335 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
1336 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
1338 SAL_INFO("lok", "Set to clipboard for view " << xClip
.get());
1339 // FIXME: using a hammer here - should not be necessary if all tests used createView.
1340 pDoc
->setClipboard(uno::Reference
<datatransfer::clipboard::XClipboard
>(xClip
->getXI(), UNO_QUERY
));
1347 const vcl::Font
* FindFont(std::u16string_view rFontName
)
1349 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
1352 const SvxFontListItem
* pFonts
1353 = static_cast<const SvxFontListItem
*>(pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
1354 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
1355 if (pList
&& !rFontName
.empty())
1356 if (sal_Handle hMetric
= pList
->GetFirstFontMetric(rFontName
))
1357 return &FontList::GetFontMetric(hMetric
);
1361 vcl::Font
FindFont_FallbackToDefault(std::u16string_view rFontName
)
1363 if (auto pFound
= FindFont(rFontName
))
1366 return OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE
, LANGUAGE_NONE
,
1367 GetDefaultFontFlags::NONE
);
1370 int getDocumentType (LibreOfficeKitDocument
* pThis
)
1372 SetLastExceptionMsg();
1374 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1378 uno::Reference
<lang::XServiceInfo
> xDocument(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
1380 if (xDocument
->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
1382 return LOK_DOCTYPE_SPREADSHEET
;
1384 else if (xDocument
->supportsService("com.sun.star.presentation.PresentationDocument"))
1386 return LOK_DOCTYPE_PRESENTATION
;
1388 else if (xDocument
->supportsService("com.sun.star.drawing.DrawingDocument"))
1390 return LOK_DOCTYPE_DRAWING
;
1392 else if (xDocument
->supportsService("com.sun.star.text.TextDocument") || xDocument
->supportsService("com.sun.star.text.WebDocument"))
1394 return LOK_DOCTYPE_TEXT
;
1398 SetLastExceptionMsg("unknown document type");
1401 catch (const uno::Exception
& exception
)
1403 SetLastExceptionMsg("exception: " + exception
.Message
);
1405 return LOK_DOCTYPE_OTHER
;
1408 } // anonymous namespace
1410 LibLODocument_Impl::LibLODocument_Impl(uno::Reference
<css::lang::XComponent
> xComponent
, int nDocumentId
)
1411 : mxComponent(std::move(xComponent
))
1412 , mnDocumentId(nDocumentId
)
1414 assert(nDocumentId
!= -1 && "Cannot set mnDocumentId to -1");
1416 m_pDocumentClass
= gDocumentClass
.lock();
1417 if (!m_pDocumentClass
)
1419 m_pDocumentClass
= std::make_shared
<LibreOfficeKitDocumentClass
>();
1421 m_pDocumentClass
->nSize
= sizeof(LibreOfficeKitDocumentClass
);
1423 m_pDocumentClass
->destroy
= doc_destroy
;
1424 m_pDocumentClass
->saveAs
= doc_saveAs
;
1425 m_pDocumentClass
->getDocumentType
= doc_getDocumentType
;
1426 m_pDocumentClass
->getParts
= doc_getParts
;
1427 m_pDocumentClass
->getPartPageRectangles
= doc_getPartPageRectangles
;
1428 m_pDocumentClass
->getPart
= doc_getPart
;
1429 m_pDocumentClass
->setPart
= doc_setPart
;
1430 m_pDocumentClass
->selectPart
= doc_selectPart
;
1431 m_pDocumentClass
->moveSelectedParts
= doc_moveSelectedParts
;
1432 m_pDocumentClass
->getPartName
= doc_getPartName
;
1433 m_pDocumentClass
->setPartMode
= doc_setPartMode
;
1434 m_pDocumentClass
->getEditMode
= doc_getEditMode
;
1435 m_pDocumentClass
->paintTile
= doc_paintTile
;
1436 m_pDocumentClass
->paintPartTile
= doc_paintPartTile
;
1437 m_pDocumentClass
->getTileMode
= doc_getTileMode
;
1438 m_pDocumentClass
->getDocumentSize
= doc_getDocumentSize
;
1439 m_pDocumentClass
->getDataArea
= doc_getDataArea
;
1440 m_pDocumentClass
->initializeForRendering
= doc_initializeForRendering
;
1441 m_pDocumentClass
->registerCallback
= doc_registerCallback
;
1442 m_pDocumentClass
->postKeyEvent
= doc_postKeyEvent
;
1443 m_pDocumentClass
->postWindowExtTextInputEvent
= doc_postWindowExtTextInputEvent
;
1444 m_pDocumentClass
->removeTextContext
= doc_removeTextContext
;
1445 m_pDocumentClass
->postWindowKeyEvent
= doc_postWindowKeyEvent
;
1446 m_pDocumentClass
->postMouseEvent
= doc_postMouseEvent
;
1447 m_pDocumentClass
->postWindowMouseEvent
= doc_postWindowMouseEvent
;
1448 m_pDocumentClass
->sendDialogEvent
= doc_sendDialogEvent
;
1449 m_pDocumentClass
->postUnoCommand
= doc_postUnoCommand
;
1450 m_pDocumentClass
->setTextSelection
= doc_setTextSelection
;
1451 m_pDocumentClass
->setWindowTextSelection
= doc_setWindowTextSelection
;
1452 m_pDocumentClass
->getTextSelection
= doc_getTextSelection
;
1453 m_pDocumentClass
->getSelectionType
= doc_getSelectionType
;
1454 m_pDocumentClass
->getSelectionTypeAndText
= doc_getSelectionTypeAndText
;
1455 m_pDocumentClass
->getClipboard
= doc_getClipboard
;
1456 m_pDocumentClass
->setClipboard
= doc_setClipboard
;
1457 m_pDocumentClass
->paste
= doc_paste
;
1458 m_pDocumentClass
->setGraphicSelection
= doc_setGraphicSelection
;
1459 m_pDocumentClass
->resetSelection
= doc_resetSelection
;
1460 m_pDocumentClass
->getCommandValues
= doc_getCommandValues
;
1461 m_pDocumentClass
->setClientZoom
= doc_setClientZoom
;
1462 m_pDocumentClass
->setClientVisibleArea
= doc_setClientVisibleArea
;
1463 m_pDocumentClass
->setOutlineState
= doc_setOutlineState
;
1465 m_pDocumentClass
->createView
= doc_createView
;
1466 m_pDocumentClass
->destroyView
= doc_destroyView
;
1467 m_pDocumentClass
->setView
= doc_setView
;
1468 m_pDocumentClass
->getView
= doc_getView
;
1469 m_pDocumentClass
->getViewsCount
= doc_getViewsCount
;
1470 m_pDocumentClass
->getViewIds
= doc_getViewIds
;
1472 m_pDocumentClass
->renderFont
= doc_renderFont
;
1473 m_pDocumentClass
->renderFontOrientation
= doc_renderFontOrientation
;
1474 m_pDocumentClass
->getPartHash
= doc_getPartHash
;
1476 m_pDocumentClass
->paintWindow
= doc_paintWindow
;
1477 m_pDocumentClass
->paintWindowDPI
= doc_paintWindowDPI
;
1478 m_pDocumentClass
->paintWindowForView
= doc_paintWindowForView
;
1479 m_pDocumentClass
->postWindow
= doc_postWindow
;
1480 m_pDocumentClass
->resizeWindow
= doc_resizeWindow
;
1482 m_pDocumentClass
->setViewLanguage
= doc_setViewLanguage
;
1484 m_pDocumentClass
->getPartInfo
= doc_getPartInfo
;
1486 m_pDocumentClass
->insertCertificate
= doc_insertCertificate
;
1487 m_pDocumentClass
->addCertificate
= doc_addCertificate
;
1488 m_pDocumentClass
->getSignatureState
= doc_getSignatureState
;
1490 m_pDocumentClass
->renderShapeSelection
= doc_renderShapeSelection
;
1491 m_pDocumentClass
->postWindowGestureEvent
= doc_postWindowGestureEvent
;
1493 m_pDocumentClass
->createViewWithOptions
= doc_createViewWithOptions
;
1494 m_pDocumentClass
->completeFunction
= doc_completeFunction
;
1496 m_pDocumentClass
->sendFormFieldEvent
= doc_sendFormFieldEvent
;
1497 m_pDocumentClass
->renderSearchResult
= doc_renderSearchResult
;
1499 m_pDocumentClass
->setBlockedCommandList
= doc_setBlockedCommandList
;
1501 m_pDocumentClass
->sendContentControlEvent
= doc_sendContentControlEvent
;
1503 m_pDocumentClass
->setViewTimezone
= doc_setViewTimezone
;
1505 m_pDocumentClass
->setAccessibilityState
= doc_setAccessibilityState
;
1507 m_pDocumentClass
->getA11yFocusedParagraph
= doc_getA11yFocusedParagraph
;
1508 m_pDocumentClass
->getA11yCaretPosition
= doc_getA11yCaretPosition
;
1510 gDocumentClass
= m_pDocumentClass
;
1512 pClass
= m_pDocumentClass
.get();
1515 forceSetClipboardForCurrentView(this);
1519 LibLODocument_Impl::~LibLODocument_Impl()
1523 mxComponent
->dispose();
1525 catch (const css::lang::DisposedException
&)
1527 TOOLS_WARN_EXCEPTION("lok", "failed to dispose document");
1531 static OUString
getGenerator()
1533 OUString
sGenerator(
1534 Translate::ExpandVariables("%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)"));
1535 OUString
os("$_OS");
1536 ::rtl::Bootstrap::expandMacros(os
);
1537 return sGenerator
.replaceFirst("%1", os
);
1542 CallbackFlushHandler::TimeoutIdle::TimeoutIdle( CallbackFlushHandler
* handler
)
1543 : Timer( "lokit timer callback" )
1544 , mHandler( handler
)
1546 // A second timer with higher priority, it'll ensure we flush in reasonable time if we get too busy
1547 // to get POST_PAINT priority processing. Otherwise it could take a long time to flush.
1548 SetPriority(TaskPriority::DEFAULT
);
1549 SetTimeout( 100 ); // 100 ms
1552 void CallbackFlushHandler::TimeoutIdle::Invoke()
1557 // One of these is created per view to handle events cf. doc_registerCallback
1558 CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument
* pDocument
, LibreOfficeKitCallback pCallback
, void* pData
)
1559 : Idle( "lokit idle callback" ),
1560 m_pDocument(pDocument
),
1561 m_pCallback(pCallback
),
1563 m_nDisableCallbacks(0),
1564 m_TimeoutIdle( this )
1566 SetPriority(TaskPriority::POST_PAINT
);
1568 // Add the states that are safe to skip duplicates on, even when
1569 // not consequent (i.e. do no emit them if unchanged from last).
1570 m_states
.emplace(LOK_CALLBACK_TEXT_SELECTION
, "NIL");
1571 m_states
.emplace(LOK_CALLBACK_GRAPHIC_SELECTION
, "NIL");
1572 m_states
.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
, "NIL");
1573 m_states
.emplace(LOK_CALLBACK_STATE_CHANGED
, "NIL");
1574 m_states
.emplace(LOK_CALLBACK_MOUSE_POINTER
, "NIL");
1575 m_states
.emplace(LOK_CALLBACK_CELL_CURSOR
, "NIL");
1576 m_states
.emplace(LOK_CALLBACK_CELL_FORMULA
, "NIL");
1577 m_states
.emplace(LOK_CALLBACK_CELL_ADDRESS
, "NIL");
1578 m_states
.emplace(LOK_CALLBACK_CURSOR_VISIBLE
, "NIL");
1579 m_states
.emplace(LOK_CALLBACK_SET_PART
, "NIL");
1580 m_states
.emplace(LOK_CALLBACK_TABLE_SELECTED
, "NIL");
1581 m_states
.emplace(LOK_CALLBACK_TAB_STOP_LIST
, "NIL");
1582 m_states
.emplace(LOK_CALLBACK_RULER_UPDATE
, "NIL");
1583 m_states
.emplace(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
, "NIL");
1586 CallbackFlushHandler::~CallbackFlushHandler()
1591 CallbackFlushHandler::queue_type2::iterator
CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::iterator pos
)
1593 int delta
= std::distance(m_queue1
.begin(), pos
);
1594 return m_queue2
.begin() + delta
;
1597 CallbackFlushHandler::queue_type2::reverse_iterator
CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::reverse_iterator pos
)
1599 int delta
= std::distance(m_queue1
.rbegin(), pos
);
1600 return m_queue2
.rbegin() + delta
;
1603 void CallbackFlushHandler::setUpdatedType( int nType
, bool value
)
1605 assert(isUpdatedType(nType
));
1606 if( m_updatedTypes
.size() <= o3tl::make_unsigned( nType
))
1607 m_updatedTypes
.resize( nType
+ 1 ); // new are default-constructed, i.e. false
1608 m_updatedTypes
[ nType
] = value
;
1613 void CallbackFlushHandler::resetUpdatedType( int nType
)
1615 setUpdatedType( nType
, false );
1618 void CallbackFlushHandler::setUpdatedTypePerViewId( int nType
, int nViewId
, int nSourceViewId
, bool value
)
1620 assert(isUpdatedTypePerViewId(nType
));
1621 std::vector
<PerViewIdData
>& types
= m_updatedTypesPerViewId
[ nViewId
];
1622 if( types
.size() <= o3tl::make_unsigned( nType
))
1623 types
.resize( nType
+ 1 ); // new are default-constructed, i.e. 'set' is false
1624 types
[ nType
] = PerViewIdData
{ value
, nSourceViewId
};
1629 void CallbackFlushHandler::resetUpdatedTypePerViewId( int nType
, int nViewId
)
1631 assert(isUpdatedTypePerViewId(nType
));
1632 bool allViewIds
= false;
1633 // Handle specially messages that do not have viewId for backwards compatibility.
1634 if( nType
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&& !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
1638 setUpdatedTypePerViewId( nType
, nViewId
, -1, false );
1641 for( auto& it
: m_updatedTypesPerViewId
)
1643 std::vector
<PerViewIdData
>& types
= it
.second
;
1644 if( types
.size() >= o3tl::make_unsigned( nType
))
1645 types
[ nType
].set
= false;
1649 void CallbackFlushHandler::libreOfficeKitViewCallback(int nType
, const OString
& pPayload
)
1651 CallbackData
callbackData(pPayload
);
1652 queue(nType
, callbackData
);
1655 void CallbackFlushHandler::libreOfficeKitViewCallbackWithViewId(int nType
, const OString
& pPayload
, int nViewId
)
1657 CallbackData
callbackData(pPayload
, nViewId
);
1658 queue(nType
, callbackData
);
1661 void CallbackFlushHandler::libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle
* pRect
, int nPart
, int nMode
)
1663 CallbackData
callbackData(pRect
, nPart
, nMode
);
1664 queue(LOK_CALLBACK_INVALIDATE_TILES
, callbackData
);
1667 void CallbackFlushHandler::libreOfficeKitViewUpdatedCallback(int nType
)
1669 assert(isUpdatedType( nType
));
1670 std::unique_lock
<std::recursive_mutex
> lock(m_mutex
);
1671 SAL_INFO("lok", "Updated: [" << nType
<< "]");
1672 setUpdatedType(nType
, true);
1675 void CallbackFlushHandler::libreOfficeKitViewUpdatedCallbackPerViewId(int nType
, int nViewId
, int nSourceViewId
)
1677 assert(isUpdatedTypePerViewId( nType
));
1678 std::unique_lock
<std::recursive_mutex
> lock(m_mutex
);
1679 SAL_INFO("lok", "Updated: [" << nType
<< "]");
1680 setUpdatedTypePerViewId(nType
, nViewId
, nSourceViewId
, true);
1683 void CallbackFlushHandler::dumpState(rtl::OStringBuffer
&rState
)
1686 rState
.append("\nView:\t");
1687 rState
.append(static_cast<sal_Int32
>(m_viewId
));
1688 rState
.append("\n\tDisableCallbacks:\t");
1689 rState
.append(static_cast<sal_Int32
>(m_nDisableCallbacks
));
1690 rState
.append("\n\tStates:\n");
1691 for (const auto &i
: m_states
)
1693 rState
.append("\n\t\t");
1694 rState
.append(static_cast<sal_Int32
>(i
.first
));
1695 rState
.append("\t");
1696 rState
.append(i
.second
);
1700 void CallbackFlushHandler::libreOfficeKitViewAddPendingInvalidateTiles()
1702 // Invoke() will call flushPendingLOKInvalidateTiles(), so just make sure the timer is active.
1706 void CallbackFlushHandler::queue(const int type
, const OString
& data
)
1708 CallbackData
callbackData(data
);
1709 queue(type
, callbackData
);
1712 void CallbackFlushHandler::queue(const int type
, CallbackData
& aCallbackData
)
1714 comphelper::ProfileZone
aZone("CallbackFlushHandler::queue");
1716 SAL_INFO("lok", "Queue: [" << type
<< "]: [" << aCallbackData
.getPayload() << "] on " << m_queue1
.size() << " entries.");
1718 bool bIsChartActive
= false;
1719 bool bIsComment
= false;
1720 if (type
== LOK_CALLBACK_GRAPHIC_SELECTION
)
1722 LokChartHelper
aChartHelper(SfxViewShell::Current());
1723 bIsChartActive
= aChartHelper
.GetWindow() != nullptr;
1725 else if (type
== LOK_CALLBACK_COMMENT
)
1730 if (callbacksDisabled() && !bIsChartActive
&& !bIsComment
)
1732 // We drop notifications when this is set, except for important ones.
1733 // When we issue a complex command (such as .uno:InsertAnnotation)
1734 // there will be multiple notifications. On the first invalidation
1735 // we will start painting, but other events will get fired
1736 // while the complex command in question executes.
1737 // We don't want to suppress everything here on the wrong assumption
1738 // that no new events are fired during painting.
1739 if (type
!= LOK_CALLBACK_STATE_CHANGED
&&
1740 type
!= LOK_CALLBACK_INVALIDATE_TILES
&&
1741 type
!= LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1742 type
!= LOK_CALLBACK_CURSOR_VISIBLE
&&
1743 type
!= LOK_CALLBACK_VIEW_CURSOR_VISIBLE
&&
1744 type
!= LOK_CALLBACK_TEXT_SELECTION
&&
1745 type
!= LOK_CALLBACK_TEXT_SELECTION_START
&&
1746 type
!= LOK_CALLBACK_TEXT_SELECTION_END
&&
1747 type
!= LOK_CALLBACK_MEDIA_SHAPE
&&
1748 type
!= LOK_CALLBACK_REFERENCE_MARKS
)
1750 SAL_INFO("lok", "Skipping while painting [" << type
<< "]: [" << aCallbackData
.getPayload() << "].");
1754 // In Writer we drop all notifications during painting.
1755 if (doc_getDocumentType(m_pDocument
) == LOK_DOCTYPE_TEXT
)
1759 // Suppress invalid payloads.
1760 if (type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1761 aCallbackData
.getPayload().indexOf(", 0, 0, ") != -1 &&
1762 aCallbackData
.getPayload().indexOf("\"hyperlink\":\"\"") == -1 &&
1763 aCallbackData
.getPayload().indexOf("\"hyperlink\": {}") == -1)
1765 // The cursor position is often the relative coordinates of the widget
1766 // issuing it, instead of the absolute one that we expect.
1767 // This is temporary however, and, once the control is created and initialized
1768 // correctly, it eventually emits the correct absolute coordinates.
1769 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << aCallbackData
.getPayload() << "].");
1773 std::unique_lock
<std::recursive_mutex
> lock(m_mutex
);
1775 // Update types should be received via the updated callbacks for performance,
1776 // getting them as normal callbacks is technically not wrong, but probably should be avoided.
1777 // Reset the updated flag if we get a normal message.
1778 if(isUpdatedType(type
))
1780 SAL_INFO("lok", "Received event with updated type [" << type
<< "] as normal callback");
1781 resetUpdatedType(type
);
1783 if(isUpdatedTypePerViewId(type
))
1785 SAL_INFO("lok", "Received event with updated type [" << type
<< "] as normal callback");
1786 resetUpdatedTypePerViewId(type
, aCallbackData
.getViewId());
1789 // drop duplicate callbacks for the listed types
1792 case LOK_CALLBACK_TEXT_SELECTION_START
:
1793 case LOK_CALLBACK_TEXT_SELECTION_END
:
1794 case LOK_CALLBACK_TEXT_SELECTION
:
1795 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1796 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1797 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1798 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1799 case LOK_CALLBACK_STATE_CHANGED
:
1800 case LOK_CALLBACK_MOUSE_POINTER
:
1801 case LOK_CALLBACK_CELL_CURSOR
:
1802 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1803 case LOK_CALLBACK_CELL_FORMULA
:
1804 case LOK_CALLBACK_CELL_ADDRESS
:
1805 case LOK_CALLBACK_CELL_SELECTION_AREA
:
1806 case LOK_CALLBACK_CURSOR_VISIBLE
:
1807 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1808 case LOK_CALLBACK_SET_PART
:
1809 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1810 case LOK_CALLBACK_INVALIDATE_HEADER
:
1811 case LOK_CALLBACK_WINDOW
:
1812 case LOK_CALLBACK_CALC_FUNCTION_LIST
:
1813 case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY
:
1814 case LOK_CALLBACK_REFERENCE_MARKS
:
1815 case LOK_CALLBACK_CELL_AUTO_FILL_AREA
:
1816 case LOK_CALLBACK_A11Y_FOCUS_CHANGED
:
1817 case LOK_CALLBACK_A11Y_CARET_CHANGED
:
1818 case LOK_CALLBACK_A11Y_TEXT_SELECTION_CHANGED
:
1819 case LOK_CALLBACK_COLOR_PALETTES
:
1821 const auto& pos
= std::find(m_queue1
.rbegin(), m_queue1
.rend(), type
);
1822 auto pos2
= toQueue2(pos
);
1823 if (pos
!= m_queue1
.rend() && pos2
->getPayload() == aCallbackData
.getPayload())
1825 SAL_INFO("lok", "Skipping queue duplicate [" << type
<< + "]: [" << aCallbackData
.getPayload() << "].");
1832 if (type
== LOK_CALLBACK_TEXT_SELECTION
&& aCallbackData
.isEmpty())
1834 const auto& posStart
= std::find(m_queue1
.rbegin(), m_queue1
.rend(), LOK_CALLBACK_TEXT_SELECTION_START
);
1835 auto posStart2
= toQueue2(posStart
);
1836 if (posStart
!= m_queue1
.rend())
1839 const auto& posEnd
= std::find(m_queue1
.rbegin(), m_queue1
.rend(), LOK_CALLBACK_TEXT_SELECTION_END
);
1840 auto posEnd2
= toQueue2(posEnd
);
1841 if (posEnd
!= m_queue1
.rend())
1845 // When payload is empty discards any previous state.
1846 if (aCallbackData
.isEmpty())
1850 case LOK_CALLBACK_TEXT_SELECTION_START
:
1851 case LOK_CALLBACK_TEXT_SELECTION_END
:
1852 case LOK_CALLBACK_TEXT_SELECTION
:
1853 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1854 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1855 case LOK_CALLBACK_INVALIDATE_TILES
:
1856 if (removeAll(type
))
1857 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << aCallbackData
.getPayload() << "].");
1865 // These are safe to use the latest state and ignore previous
1866 // ones (if any) since the last overrides previous ones.
1867 case LOK_CALLBACK_TEXT_SELECTION_START
:
1868 case LOK_CALLBACK_TEXT_SELECTION_END
:
1869 case LOK_CALLBACK_TEXT_SELECTION
:
1870 case LOK_CALLBACK_MOUSE_POINTER
:
1871 case LOK_CALLBACK_CELL_CURSOR
:
1872 case LOK_CALLBACK_CELL_FORMULA
:
1873 case LOK_CALLBACK_CELL_ADDRESS
:
1874 case LOK_CALLBACK_CURSOR_VISIBLE
:
1875 case LOK_CALLBACK_SET_PART
:
1876 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
:
1877 case LOK_CALLBACK_RULER_UPDATE
:
1878 case LOK_CALLBACK_A11Y_FOCUS_CHANGED
:
1879 case LOK_CALLBACK_A11Y_CARET_CHANGED
:
1880 case LOK_CALLBACK_A11Y_TEXT_SELECTION_CHANGED
:
1881 case LOK_CALLBACK_COLOR_PALETTES
:
1883 if (removeAll(type
))
1884 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << aCallbackData
.getPayload() << "].");
1888 // These are safe to use the latest state and ignore previous
1889 // ones (if any) since the last overrides previous ones,
1890 // but only if the view is the same.
1891 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1892 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1893 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1894 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1895 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1896 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1897 case LOK_CALLBACK_CALC_FUNCTION_LIST
:
1898 case LOK_CALLBACK_FORM_FIELD_BUTTON
:
1900 // deleting the duplicate of visible cursor message can cause hyperlink popup not to show up on second/or more click on the same place.
1901 // If the hyperlink is not empty we can bypass that to show the popup
1902 const bool hyperLinkException
= type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1903 aCallbackData
.getPayload().indexOf("\"hyperlink\":\"\"") == -1 &&
1904 aCallbackData
.getPayload().indexOf("\"hyperlink\": {}") == -1;
1905 if(!hyperLinkException
)
1907 const int nViewId
= aCallbackData
.getViewId();
1908 removeAll(type
, [nViewId
] (const CallbackData
& elemData
) {
1909 return (nViewId
== elemData
.getViewId());
1916 case LOK_CALLBACK_INVALIDATE_TILES
:
1917 if (processInvalidateTilesEvent(type
, aCallbackData
))
1921 // State changes with same name override previous ones with a different value.
1922 // Ex. ".uno:PageStatus=Slide 20 of 83" overwrites any previous PageStatus.
1923 case LOK_CALLBACK_STATE_CHANGED
:
1925 // Compare the state name=value and overwrite earlier entries with same name.
1926 const auto pos
= aCallbackData
.getPayload().indexOf('=');
1929 const std::string_view name
= aCallbackData
.getPayload().subView(0, pos
+ 1);
1930 // This is needed because otherwise it creates some problems when
1931 // a save occurs while a cell is still edited in Calc.
1932 if (name
!= ".uno:ModifiedStatus=")
1934 removeAll(type
, [&name
] (const CallbackData
& elemData
) {
1935 return elemData
.getPayload().startsWith(name
);
1943 case LOK_CALLBACK_WINDOW
:
1944 if (processWindowEvent(type
, aCallbackData
))
1948 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1950 // remove only selection ranges and 'EMPTY' messages
1951 // always send 'INPLACE' and 'INPLACE EXIT' messages
1952 removeAll(type
, [] (const CallbackData
& elemData
)
1953 { return (elemData
.getPayload().indexOf("INPLACE") == -1); });
1959 // Validate that the cached data and the payload string are identical.
1960 assert(aCallbackData
.validate() && "Cached callback payload object and string mismatch!");
1961 m_queue1
.emplace_back(type
);
1962 m_queue2
.emplace_back(aCallbackData
);
1963 SAL_INFO("lok", "Queued #" << (m_queue1
.size() - 1) <<
1964 " [" << type
<< "]: [" << aCallbackData
.getPayload() << "] to have " << m_queue1
.size() << " entries.");
1968 // Dump the queue state and validate cached data.
1970 std::ostringstream oss
;
1971 if (m_queue1
.empty())
1974 oss
<< m_queue1
.size() << " items\n";
1975 auto it1
= m_queue1
.begin();
1976 auto it2
= m_queue2
.begin();
1977 for (; it1
!= m_queue1
.end(); ++it1
, ++it2
)
1978 oss
<< i
++ << ": [" << *it1
<< "] [" << it2
->getPayload() << "].\n";
1979 SAL_INFO("lok", "Current Queue: " << oss
.str());
1982 m_queue2
.begin(), m_queue2
.end(),
1983 [](const CallbackData
& c
) { return c
.validate(); }));
1991 bool CallbackFlushHandler::processInvalidateTilesEvent(int type
, CallbackData
& aCallbackData
)
1993 RectangleAndPart rcNew
= aCallbackData
.getRectangleAndPart();
1994 if (rcNew
.isEmpty())
1996 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << aCallbackData
.getPayload() << "].");
2000 // If we have to invalidate all tiles, we can skip any new tile invalidation.
2001 // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
2003 = std::find(m_queue1
.rbegin(), m_queue1
.rend(), LOK_CALLBACK_INVALIDATE_TILES
);
2004 if (pos
!= m_queue1
.rend())
2006 auto pos2
= toQueue2(pos
);
2007 const RectangleAndPart
& rcOld
= pos2
->getRectangleAndPart();
2008 if (rcOld
.isInfinite() && (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
) &&
2009 (rcOld
.m_nMode
== rcNew
.m_nMode
))
2011 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << aCallbackData
.getPayload()
2012 << "] since all tiles need to be invalidated.");
2016 if ((rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
) && (rcOld
.m_nMode
== rcNew
.m_nMode
))
2018 // If fully overlapping.
2019 if (rcOld
.m_aRectangle
.Contains(rcNew
.m_aRectangle
))
2021 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << aCallbackData
.getPayload()
2022 << "] since overlaps existing all-parts.");
2028 if (rcNew
.isInfinite())
2030 SAL_INFO("lok", "Have Empty [" << type
<< "]: [" << aCallbackData
.getPayload()
2031 << "] so removing all with part " << rcNew
.m_nPart
<< ".");
2032 removeAll(LOK_CALLBACK_INVALIDATE_TILES
, [&rcNew
](const CallbackData
& elemData
) {
2033 // Remove exiting if new is all-encompassing, or if of the same part.
2034 return ((rcNew
.m_nPart
== -1 || rcNew
.m_nPart
== elemData
.getRectangleAndPart().m_nPart
)
2035 && (rcNew
.m_nMode
== elemData
.getRectangleAndPart().m_nMode
));
2040 const auto rcOrig
= rcNew
;
2042 SAL_INFO("lok", "Have [" << type
<< "]: [" << aCallbackData
.getPayload() << "] so merging overlapping.");
2043 removeAll(LOK_CALLBACK_INVALIDATE_TILES
,[&rcNew
](const CallbackData
& elemData
) {
2044 const RectangleAndPart
& rcOld
= elemData
.getRectangleAndPart();
2045 if (rcNew
.m_nPart
!= -1 && rcOld
.m_nPart
!= -1 &&
2046 (rcOld
.m_nPart
!= rcNew
.m_nPart
|| rcOld
.m_nMode
!= rcNew
.m_nMode
))
2048 SAL_INFO("lok", "Nothing to merge between new: "
2049 << rcNew
.toString() << ", and old: " << rcOld
.toString());
2053 if (rcNew
.m_nPart
== -1)
2055 // Don't merge unless fully overlapped.
2056 SAL_INFO("lok", "New " << rcNew
.toString() << " has " << rcOld
.toString()
2058 if (rcNew
.m_aRectangle
.Contains(rcOld
.m_aRectangle
) && rcOld
.m_nMode
== rcNew
.m_nMode
)
2060 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
2061 << rcOld
.toString() << ".");
2065 else if (rcOld
.m_nPart
== -1)
2067 // Don't merge unless fully overlapped.
2068 SAL_INFO("lok", "Old " << rcOld
.toString() << " has " << rcNew
.toString()
2070 if (rcOld
.m_aRectangle
.Contains(rcNew
.m_aRectangle
) && rcOld
.m_nMode
== rcNew
.m_nMode
)
2072 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
2073 << rcOld
.toString() << ".");
2079 const tools::Rectangle rcOverlap
2080 = rcNew
.m_aRectangle
.GetIntersection(rcOld
.m_aRectangle
);
2081 const bool bOverlap
= !rcOverlap
.IsEmpty() && rcOld
.m_nMode
== rcNew
.m_nMode
;
2082 SAL_INFO("lok", "Merging " << rcNew
.toString() << " & " << rcOld
.toString()
2083 << " => " << rcOverlap
.toString()
2084 << " Overlap: " << bOverlap
);
2087 rcNew
.m_aRectangle
.Union(rcOld
.m_aRectangle
);
2088 SAL_INFO("lok", "Merged: " << rcNew
.toString());
2097 if (rcNew
.m_aRectangle
!= rcOrig
.m_aRectangle
)
2099 SAL_INFO("lok", "Replacing: " << rcOrig
.toString() << " by " << rcNew
.toString());
2100 if (rcNew
.m_aRectangle
.GetWidth() < rcOrig
.m_aRectangle
.GetWidth()
2101 || rcNew
.m_aRectangle
.GetHeight() < rcOrig
.m_aRectangle
.GetHeight())
2103 SAL_WARN("lok", "Error: merged rect smaller.");
2108 aCallbackData
.updateRectangleAndPart(rcNew
);
2113 bool CallbackFlushHandler::processWindowEvent(int type
, CallbackData
& aCallbackData
)
2115 const OString
& payload
= aCallbackData
.getPayload();
2117 boost::property_tree::ptree
& aTree
= aCallbackData
.setJson(std::string(payload
));
2118 const unsigned nLOKWindowId
= aTree
.get
<unsigned>("id", 0);
2119 const std::string aAction
= aTree
.get
<std::string
>("action", "");
2120 if (aAction
== "invalidate")
2122 std::string aRectStr
= aTree
.get
<std::string
>("rectangle", "");
2123 // no 'rectangle' field => invalidate all of the window =>
2124 // remove all previous window part invalidations
2125 if (aRectStr
.empty())
2127 removeAll(LOK_CALLBACK_WINDOW
,[&nLOKWindowId
](const CallbackData
& elemData
) {
2128 const boost::property_tree::ptree
& aOldTree
= elemData
.getJson();
2129 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
2130 && aOldTree
.get
<std::string
>("action", "") == "invalidate")
2139 // if we have to invalidate all of the window, ignore
2140 // any part invalidation message
2141 bool invAllExist
= false;
2142 auto it1
= m_queue1
.rbegin();
2143 auto it2
= m_queue2
.rbegin();
2144 for (;it1
!= m_queue1
.rend(); ++it1
, ++it2
)
2146 if (*it1
!= LOK_CALLBACK_WINDOW
)
2148 const boost::property_tree::ptree
& aOldTree
= it2
->getJson();
2149 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
2150 && aOldTree
.get
<std::string
>("action", "") == "invalidate"
2151 && aOldTree
.get
<std::string
>("rectangle", "").empty())
2158 // we found a invalidate-all window callback
2161 SAL_INFO("lok.dialog", "Skipping queue ["
2162 << type
<< "]: [" << payload
2163 << "] since whole window needs to be invalidated.");
2167 std::istringstream
aRectStream(aRectStr
);
2168 tools::Long nLeft
, nTop
, nWidth
, nHeight
;
2170 aRectStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
2171 tools::Rectangle
aNewRect(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
2172 bool currentIsRedundant
= false;
2173 removeAll(LOK_CALLBACK_WINDOW
, [&aNewRect
, &nLOKWindowId
,
2174 ¤tIsRedundant
](const CallbackData
& elemData
) {
2175 const boost::property_tree::ptree
& aOldTree
= elemData
.getJson();
2176 if (aOldTree
.get
<std::string
>("action", "") == "invalidate")
2178 // Not possible that we encounter an empty rectangle here; we already handled this case above.
2179 std::istringstream
aOldRectStream(aOldTree
.get
<std::string
>("rectangle", ""));
2180 tools::Long nOldLeft
, nOldTop
, nOldWidth
, nOldHeight
;
2182 aOldRectStream
>> nOldLeft
>> nOldComma
>> nOldTop
>> nOldComma
>> nOldWidth
2183 >> nOldComma
>> nOldHeight
;
2184 const tools::Rectangle aOldRect
= tools::Rectangle(
2185 nOldLeft
, nOldTop
, nOldLeft
+ nOldWidth
, nOldTop
+ nOldHeight
);
2187 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
2189 if (aNewRect
== aOldRect
)
2191 SAL_INFO("lok.dialog", "Duplicate rect [" << aNewRect
.toString()
2192 << "]. Skipping new.");
2193 // We have a rectangle in the queue already that makes the current Callback useless.
2194 currentIsRedundant
= true;
2197 // new one engulfs the old one?
2198 else if (aNewRect
.Contains(aOldRect
))
2200 SAL_INFO("lok.dialog",
2201 "New rect [" << aNewRect
.toString() << "] engulfs old ["
2202 << aOldRect
.toString() << "]. Replacing old.");
2205 // old one engulfs the new one?
2206 else if (aOldRect
.Contains(aNewRect
))
2208 SAL_INFO("lok.dialog",
2209 "Old rect [" << aOldRect
.toString() << "] engulfs new ["
2210 << aNewRect
.toString() << "]. Skipping new.");
2211 // We have a rectangle in the queue already that makes the current Callback useless.
2212 currentIsRedundant
= true;
2217 // Overlapping rects.
2218 const tools::Rectangle aPreMergeRect
= aNewRect
;
2219 aNewRect
.Union(aOldRect
);
2220 SAL_INFO("lok.dialog", "Merging rects ["
2221 << aPreMergeRect
.toString() << "] & ["
2222 << aOldRect
.toString() << "] = ["
2223 << aNewRect
.toString()
2224 << "]. Replacing old.");
2234 // Do not enqueue if redundant.
2235 if (currentIsRedundant
)
2238 aTree
.put("rectangle", aNewRect
.toString().getStr());
2239 aCallbackData
.setJson(aTree
);
2240 assert(aCallbackData
.validate() && "Validation after setJson failed!");
2243 else if (aAction
== "created")
2245 // Remove all previous actions on same dialog, if we are creating it anew.
2246 removeAll(LOK_CALLBACK_WINDOW
,[&nLOKWindowId
](const CallbackData
& elemData
) {
2247 const boost::property_tree::ptree
& aOldTree
= elemData
.getJson();
2248 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
2253 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
2256 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
2261 auto xClip
= forceSetClipboardForCurrentView(m_pDocument
);
2263 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(xClip
);
2264 pWindow
->SetClipboard(xClipboard
);
2267 else if (aAction
== "size_changed")
2269 // A size change is practically re-creation of the window.
2270 // But at a minimum it's a full invalidation.
2271 removeAll(LOK_CALLBACK_WINDOW
, [&nLOKWindowId
](const CallbackData
& elemData
) {
2272 const boost::property_tree::ptree
& aOldTree
= elemData
.getJson();
2273 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
2275 const std::string aOldAction
= aOldTree
.get
<std::string
>("action", "");
2276 if (aOldAction
== "invalidate")
2287 void CallbackFlushHandler::enqueueUpdatedTypes()
2289 if( m_updatedTypes
.empty() && m_updatedTypesPerViewId
.empty())
2291 assert(m_viewId
>= 0);
2292 SfxViewShell
* viewShell
= SfxViewShell::GetFirst( false,
2293 [this](const SfxViewShell
* shell
) { return shell
->GetViewShellId().get() == m_viewId
; } );
2294 assert(viewShell
!= nullptr);
2296 // First move data to local structures, so that callbacks don't possibly modify it.
2297 std::vector
<bool> updatedTypes
;
2298 std::swap(updatedTypes
, m_updatedTypes
);
2299 boost::container::flat_map
<int, std::vector
<PerViewIdData
>> updatedTypesPerViewId
;
2300 std::swap(updatedTypesPerViewId
, m_updatedTypesPerViewId
);
2302 // Some types must always precede other types, for example
2303 // LOK_CALLBACK_TEXT_SELECTION_START and LOK_CALLBACK_TEXT_SELECTION_END
2304 // must always precede LOK_CALLBACK_TEXT_SELECTION if present.
2305 // Only these types should be present (see isUpdatedType()) and should be processed in this order.
2306 static const int orderedUpdatedTypes
[] = {
2307 LOK_CALLBACK_TEXT_SELECTION_START
, LOK_CALLBACK_TEXT_SELECTION_END
, LOK_CALLBACK_TEXT_SELECTION
};
2308 // Only these types should be present (see isUpdatedTypePerViewId()) and (as of now)
2309 // the order doesn't matter.
2310 static const int orderedUpdatedTypesPerViewId
[] = {
2311 LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
,
2312 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
,
2313 LOK_CALLBACK_TEXT_VIEW_SELECTION
};
2315 for( int type
: orderedUpdatedTypes
)
2317 if(o3tl::make_unsigned( type
) < updatedTypes
.size() && updatedTypes
[ type
])
2319 enqueueUpdatedType( type
, viewShell
, m_viewId
);
2322 for( const auto& it
: updatedTypesPerViewId
)
2324 int viewId
= it
.first
;
2325 const std::vector
<PerViewIdData
>& types
= it
.second
;
2326 for( int type
: orderedUpdatedTypesPerViewId
)
2328 if(o3tl::make_unsigned( type
) < types
.size() && types
[ type
].set
)
2330 SfxViewShell
* sourceViewShell
= viewShell
;
2331 const int sourceViewId
= types
[ type
].sourceViewId
;
2332 if( sourceViewId
!= m_viewId
)
2334 assert(sourceViewId
>= 0);
2335 sourceViewShell
= SfxViewShell::GetFirst( false,
2336 [sourceViewId
](const SfxViewShell
* shell
) { return shell
->GetViewShellId().get() == sourceViewId
; } );
2338 if(sourceViewShell
== nullptr)
2340 SAL_INFO("lok", "View #" << sourceViewId
<< " no longer found for updated event [" << type
<< "]");
2341 continue; // View removed, probably cleaning up.
2343 enqueueUpdatedType( type
, sourceViewShell
, viewId
);
2349 void CallbackFlushHandler::enqueueUpdatedType( int type
, const SfxViewShell
* viewShell
, int viewId
)
2351 if (type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
)
2353 if (const SfxViewShell
* viewShell2
= LokStarMathHelper(viewShell
).GetSmViewShell())
2354 viewShell
= viewShell2
;
2356 std::optional
<OString
> payload
= viewShell
->getLOKPayload( type
, viewId
);
2358 return; // No actual payload to send.
2359 CallbackData
callbackData(*payload
, viewId
);
2360 m_queue1
.emplace_back(type
);
2361 m_queue2
.emplace_back(callbackData
);
2362 SAL_INFO("lok", "Queued updated [" << type
<< "]: [" << callbackData
.getPayload()
2363 << "] to have " << m_queue1
.size() << " entries.");
2366 void CallbackFlushHandler::Invoke()
2368 comphelper::ProfileZone
aZone("CallbackFlushHandler::Invoke");
2373 // Get any pending invalidate tile events. This will call our callbacks,
2374 // so it must be done before taking the mutex.
2375 assert(m_viewId
>= 0);
2376 if(SfxViewShell
* viewShell
= SfxViewShell::GetFirst( false,
2377 [this](const SfxViewShell
* shell
) { return shell
->GetViewShellId().get() == m_viewId
; } ))
2379 viewShell
->flushPendingLOKInvalidateTiles();
2382 std::unique_lock
<std::recursive_mutex
> lock(m_mutex
);
2384 // Append messages for updated types, fetch them only now.
2385 enqueueUpdatedTypes();
2387 SAL_INFO("lok", "Flushing " << m_queue1
.size() << " elements.");
2388 auto it1
= m_queue1
.begin();
2389 auto it2
= m_queue2
.begin();
2390 for (; it1
!= m_queue1
.end(); ++it1
, ++it2
)
2392 const int type
= *it1
;
2393 const auto& payload
= it2
->getPayload();
2394 const int viewId
= lcl_isViewCallbackType(type
) ? it2
->getViewId() : -1;
2396 SAL_INFO("lok", "processing event: [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
2398 // common code-path for events on this view:
2403 if (type
== LOK_CALLBACK_STATE_CHANGED
&&
2404 (idx
= payload
.indexOf('=')) != -1)
2406 OString key
= payload
.copy(0, idx
);
2407 OString value
= payload
.copy(idx
+1);
2408 const auto stateIt
= m_lastStateChange
.find(key
);
2409 if (stateIt
!= m_lastStateChange
.end())
2411 // If the value didn't change, it's safe to ignore.
2412 if (stateIt
->second
== value
)
2414 SAL_INFO("lok", "Skipping new state duplicate: [" << type
<< "]: [" << payload
<< "].");
2417 SAL_INFO("lok", "Replacing a state element [" << type
<< "]: [" << payload
<< "].");
2418 stateIt
->second
= value
;
2422 SAL_INFO("lok", "Inserted a new state element: [" << type
<< "]: [" << payload
<< "]");
2423 m_lastStateChange
.emplace(key
, value
);
2428 const auto stateIt
= m_states
.find(type
);
2429 if (stateIt
!= m_states
.end())
2431 // If the state didn't change, it's safe to ignore.
2432 if (stateIt
->second
== payload
)
2434 SAL_INFO("lok", "Skipping duplicate [" << type
<< "]: [" << payload
<< "].");
2437 stateIt
->second
= payload
;
2441 else // less common path for events relating to other views
2443 const auto statesIt
= m_viewStates
.find(viewId
);
2444 if (statesIt
!= m_viewStates
.end())
2446 auto& states
= statesIt
->second
;
2447 const auto stateIt
= states
.find(type
);
2448 if (stateIt
!= states
.end())
2450 // If the state didn't change, it's safe to ignore.
2451 if (stateIt
->second
== payload
)
2453 SAL_INFO("lok", "Skipping view duplicate [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
2457 SAL_INFO("lok", "Replacing an element in view states [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
2458 stateIt
->second
= payload
;
2462 SAL_INFO("lok", "Inserted a new element in view states: [" << type
<< ',' << viewId
<< "]: [" << payload
<< "]");
2463 states
.emplace(type
, payload
);
2469 m_pCallback(type
, payload
.getStr(), m_pData
);
2475 m_TimeoutIdle
.Stop();
2478 void CallbackFlushHandler::startTimer()
2482 if (!m_TimeoutIdle
.IsActive())
2483 m_TimeoutIdle
.Start();
2486 bool CallbackFlushHandler::removeAll(int type
)
2488 bool bErased
= false;
2489 auto it1
= m_queue1
.begin();
2492 it1
= std::find(it1
, m_queue1
.end(), type
);
2493 if(it1
== m_queue1
.end())
2495 m_queue2
.erase(toQueue2(it1
));
2496 it1
= m_queue1
.erase(it1
);
2502 bool CallbackFlushHandler::removeAll(int type
, const std::function
<bool (const CallbackData
&)>& rTestFunc
)
2504 bool bErased
= false;
2505 auto it1
= m_queue1
.begin();
2508 it1
= std::find(it1
, m_queue1
.end(), type
);
2509 if(it1
== m_queue1
.end())
2511 auto it2
= toQueue2(it1
);
2512 if (rTestFunc(*it2
))
2514 m_queue2
.erase(it2
);
2515 it1
= m_queue1
.erase(it1
);
2524 void CallbackFlushHandler::addViewStates(int viewId
)
2526 const auto& result
= m_viewStates
.emplace(viewId
, decltype(m_viewStates
)::mapped_type());
2527 if (!result
.second
&& result
.first
!= m_viewStates
.end())
2529 result
.first
->second
.clear();
2533 void CallbackFlushHandler::removeViewStates(int viewId
)
2535 m_viewStates
.erase(viewId
);
2539 static void doc_destroy(LibreOfficeKitDocument
*pThis
)
2541 comphelper::ProfileZone
aZone("doc_destroy");
2543 SolarMutexGuard aGuard
;
2546 LOKClipboardFactory::releaseClipboardForView(-1);
2549 LibLODocument_Impl
*pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2553 static void lo_destroy (LibreOfficeKit
* pThis
);
2554 static int lo_initialize (LibreOfficeKit
* pThis
, const char* pInstallPath
, const char* pUserProfilePath
);
2555 static LibreOfficeKitDocument
* lo_documentLoad (LibreOfficeKit
* pThis
, const char* pURL
);
2556 static char * lo_getError (LibreOfficeKit
* pThis
);
2557 static void lo_freeError (char* pFree
);
2558 static LibreOfficeKitDocument
* lo_documentLoadWithOptions (LibreOfficeKit
* pThis
,
2560 const char* pOptions
);
2561 static void lo_registerCallback (LibreOfficeKit
* pThis
,
2562 LibreOfficeKitCallback pCallback
,
2564 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
);
2565 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long features
);
2566 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
2568 const char* pPassword
);
2569 static char* lo_getVersionInfo(LibreOfficeKit
* pThis
);
2570 static int lo_runMacro (LibreOfficeKit
* pThis
, const char* pURL
);
2572 static bool lo_signDocument(LibreOfficeKit
* pThis
,
2574 const unsigned char* pCertificateBinary
,
2575 const int nCertificateBinarySize
,
2576 const unsigned char* pPrivateKeyBinary
,
2577 const int nPrivateKeyBinarySize
);
2579 static char* lo_extractRequest(LibreOfficeKit
* pThis
,
2580 const char* pFilePath
);
2582 static void lo_trimMemory(LibreOfficeKit
* pThis
, int nTarget
);
2584 static void lo_runLoop(LibreOfficeKit
* pThis
,
2585 LibreOfficeKitPollCallback pPollCallback
,
2586 LibreOfficeKitWakeCallback pWakeCallback
,
2589 static void lo_sendDialogEvent(LibreOfficeKit
* pThis
,
2590 unsigned long long int nLOKWindowId
,
2591 const char* pArguments
);
2593 static void lo_setOption(LibreOfficeKit
* pThis
, const char* pOption
, const char* pValue
);
2595 static void lo_dumpState(LibreOfficeKit
* pThis
, const char* pOptions
, char** pState
);
2597 LibLibreOffice_Impl::LibLibreOffice_Impl()
2598 : m_pOfficeClass( gOfficeClass
.lock() )
2600 , mpCallback(nullptr)
2601 , mpCallbackData(nullptr)
2602 , mOptionalFeatures(0)
2604 if(!m_pOfficeClass
) {
2605 m_pOfficeClass
= std::make_shared
<LibreOfficeKitClass
>();
2606 m_pOfficeClass
->nSize
= sizeof(LibreOfficeKitClass
);
2608 m_pOfficeClass
->destroy
= lo_destroy
;
2609 m_pOfficeClass
->documentLoad
= lo_documentLoad
;
2610 m_pOfficeClass
->getError
= lo_getError
;
2611 m_pOfficeClass
->freeError
= lo_freeError
;
2612 m_pOfficeClass
->documentLoadWithOptions
= lo_documentLoadWithOptions
;
2613 m_pOfficeClass
->registerCallback
= lo_registerCallback
;
2614 m_pOfficeClass
->getFilterTypes
= lo_getFilterTypes
;
2615 m_pOfficeClass
->setOptionalFeatures
= lo_setOptionalFeatures
;
2616 m_pOfficeClass
->setDocumentPassword
= lo_setDocumentPassword
;
2617 m_pOfficeClass
->getVersionInfo
= lo_getVersionInfo
;
2618 m_pOfficeClass
->runMacro
= lo_runMacro
;
2619 m_pOfficeClass
->signDocument
= lo_signDocument
;
2620 m_pOfficeClass
->runLoop
= lo_runLoop
;
2621 m_pOfficeClass
->sendDialogEvent
= lo_sendDialogEvent
;
2622 m_pOfficeClass
->setOption
= lo_setOption
;
2623 m_pOfficeClass
->dumpState
= lo_dumpState
;
2624 m_pOfficeClass
->extractRequest
= lo_extractRequest
;
2625 m_pOfficeClass
->trimMemory
= lo_trimMemory
;
2627 gOfficeClass
= m_pOfficeClass
;
2630 pClass
= m_pOfficeClass
.get();
2633 LibLibreOffice_Impl::~LibLibreOffice_Impl()
2640 void setLanguageAndLocale(OUString
const & aLangISO
)
2642 SvtSysLocaleOptions aLocalOptions
;
2643 aLocalOptions
.SetLocaleConfigString(aLangISO
);
2644 aLocalOptions
.SetUILocaleConfigString(aLangISO
);
2645 aLocalOptions
.Commit();
2648 void setFormatSpecificFilterData(std::u16string_view sFormat
, comphelper::SequenceAsHashMap
& rFilterDataMap
)
2650 if (sFormat
== u
"pdf")
2652 // always export bookmarks, which is needed for annotations
2653 rFilterDataMap
["ExportBookmarks"] <<= true;
2657 } // anonymous namespace
2659 // Wonder global state ...
2660 static uno::Reference
<css::uno::XComponentContext
> xContext
;
2661 static uno::Reference
<css::lang::XMultiServiceFactory
> xSFactory
;
2662 static uno::Reference
<css::lang::XMultiComponentFactory
> xFactory
;
2664 static LibreOfficeKitDocument
* lo_documentLoad(LibreOfficeKit
* pThis
, const char* pURL
)
2666 return lo_documentLoadWithOptions(pThis
, pURL
, nullptr);
2669 static LibreOfficeKitDocument
* lo_documentLoadWithOptions(LibreOfficeKit
* pThis
, const char* pURL
, const char* pOptions
)
2671 comphelper::ProfileZone
aZone("lo_documentLoadWithOptions");
2673 SolarMutexGuard aGuard
;
2675 static int nDocumentIdCounter
= 0;
2677 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2678 pLib
->maLastExceptionMsg
.clear();
2680 const OUString
aURL(getAbsoluteURL(pURL
));
2683 pLib
->maLastExceptionMsg
= "Filename to load was not provided.";
2684 SAL_INFO("lok", "URL for load is empty");
2688 pLib
->maLastExceptionMsg
.clear();
2692 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
2693 SAL_INFO("lok", "ComponentContext is not available");
2697 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
2699 if (!xComponentLoader
.is())
2701 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
2702 SAL_INFO("lok", "ComponentLoader is not available");
2708 // 'Language=...' is an option that LOK consumes by itself, and does
2709 // not pass it as a parameter to the filter
2710 OUString aOptions
= getUString(pOptions
);
2711 const OUString aLanguage
= extractParameter(aOptions
, u
"Language");
2712 bool isValidLangTag
= LanguageTag::isValidBcp47(aLanguage
, nullptr);
2714 if (!aLanguage
.isEmpty() && isValidLangTag
)
2716 static bool isLoading
= true;
2719 // Capture the language used to load the document.
2720 SfxLokHelper::setLoadLanguage(aLanguage
);
2724 SfxLokHelper::setDefaultLanguage(aLanguage
);
2725 // Set the LOK language tag, used for dialog tunneling.
2726 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage
));
2727 comphelper::LibreOfficeKit::setLocale(LanguageTag(aLanguage
));
2729 SAL_INFO("lok", "Set document language to " << aLanguage
);
2730 // use with care - it sets it for the entire core, not just the
2732 setLanguageAndLocale(aLanguage
);
2733 // Need to reset the static initialized values
2734 SvNumberFormatter::resetTheCurrencyTable();
2737 // Set the timezone, if not empty.
2738 const OUString aTimezone
= extractParameter(aOptions
, u
"Timezone");
2739 if (!aTimezone
.isEmpty())
2741 SfxLokHelper::setDefaultTimezone(true, aTimezone
);
2745 // Default to the TZ envar, if set.
2746 const char* tz
= ::getenv("TZ");
2749 SfxLokHelper::setDefaultTimezone(true,
2750 OStringToOUString(tz
, RTL_TEXTENCODING_UTF8
));
2754 SfxLokHelper::setDefaultTimezone(false, OUString());
2758 const OUString aDeviceFormFactor
= extractParameter(aOptions
, u
"DeviceFormFactor");
2759 SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor
);
2761 const OUString aBatch
= extractParameter(aOptions
, u
"Batch");
2762 if (!aBatch
.isEmpty())
2764 Application::SetDialogCancelMode(DialogCancelMode::LOKSilent
);
2767 const OUString sFilterOptions
= aOptions
;
2769 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
2770 new LOKInteractionHandler("load", pLib
));
2771 auto const pair(pLib
->mInteractionMap
.insert(std::make_pair(aURL
.toUtf8(), pInteraction
)));
2772 comphelper::ScopeGuard
const g([&] () {
2775 pLib
->mInteractionMap
.erase(aURL
.toUtf8());
2778 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
);
2780 int nMacroSecurityLevel
= 1;
2781 const OUString aMacroSecurityLevel
= extractParameter(aOptions
, u
"MacroSecurityLevel");
2782 if (!aMacroSecurityLevel
.isEmpty())
2785 sal_uInt32 nFormat
= 1;
2786 SvNumberFormatter
aFormatter(::comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US
);
2787 if (aFormatter
.IsNumberFormat(aMacroSecurityLevel
, nFormat
, nNumber
))
2788 nMacroSecurityLevel
= static_cast<int>(nNumber
);
2790 SvtSecurityOptions::SetMacroSecurityLevel(nMacroSecurityLevel
);
2792 #if defined(ANDROID) && HAVE_FEATURE_ANDROID_LOK
2793 sal_Int16 nMacroExecMode
= document::MacroExecMode::USE_CONFIG
;
2795 const OUString aEnableMacrosExecution
= extractParameter(aOptions
, u
"EnableMacrosExecution");
2796 sal_Int16 nMacroExecMode
= aEnableMacrosExecution
== "true" ? document::MacroExecMode::USE_CONFIG
:
2797 document::MacroExecMode::NEVER_EXECUTE
;
2800 // set AsTemplate explicitly false to be able to load template files
2801 // as regular files, otherwise we cannot save them; it will try
2802 // to bring saveas dialog which cannot work with LOK case
2803 uno::Sequence
<css::beans::PropertyValue
> aFilterOptions
{
2804 comphelper::makePropertyValue("FilterOptions", sFilterOptions
),
2805 comphelper::makePropertyValue("InteractionHandler", xInteraction
),
2806 comphelper::makePropertyValue("MacroExecutionMode", nMacroExecMode
),
2807 comphelper::makePropertyValue("AsTemplate", false),
2808 comphelper::makePropertyValue("Silent", !aBatch
.isEmpty())
2812 sal_Int16 nUpdateDoc = document::UpdateDocMode::ACCORDING_TO_CONFIG;
2813 aFilterOptions[3].Name = "UpdateDocMode";
2814 aFilterOptions[3].Value <<= nUpdateDoc;
2817 OutputDevice::StartTrackingFontMappingUse();
2819 const int nThisDocumentId
= nDocumentIdCounter
++;
2820 SfxViewShell::SetCurrentDocId(ViewShellDocId(nThisDocumentId
));
2821 uno::Reference
<lang::XComponent
> xComponent
= xComponentLoader
->loadComponentFromURL(
2825 assert(!xComponent
.is() || pair
.second
); // concurrent loading of same URL ought to fail
2827 if (!xComponent
.is())
2829 pLib
->maLastExceptionMsg
= "loadComponentFromURL returned an empty reference";
2830 SAL_INFO("lok", "Document can't be loaded - " << pLib
->maLastExceptionMsg
);
2834 LibLODocument_Impl
* pDocument
= new LibLODocument_Impl(xComponent
, nThisDocumentId
);
2836 // After loading the document, its initial view is the "current" view.
2837 if (pLib
->mpCallback
)
2839 int nState
= doc_getSignatureState(pDocument
);
2840 pLib
->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS
, OString::number(nState
).getStr(), pLib
->mpCallbackData
);
2843 auto aFontMappingUseData
= OutputDevice::FinishTrackingFontMappingUse();
2845 if (aFontMappingUseData
.size() > 0)
2847 SAL_INFO("lok.fontsubst", "================ Original substitutions:");
2848 for (const auto &i
: aFontMappingUseData
)
2850 SAL_INFO("lok.fontsubst", i
.mOriginalFont
);
2851 for (const auto &j
: i
.mUsedFonts
)
2852 SAL_INFO("lok.fontsubst", " " << j
);
2856 // Filter out font substitutions that actually aren't any substitutions, like "Liberation
2857 // Serif" -> "Liberation Serif/Regular". If even one of the "substitutions" of a font is to
2858 // the same font, don't count that as a missing font.
2860 aFontMappingUseData
.erase
2861 (std::remove_if(aFontMappingUseData
.begin(), aFontMappingUseData
.end(),
2862 [](OutputDevice::FontMappingUseItem x
)
2864 // If the original font had an empty style and one of its
2865 // replacement fonts has the same family name, we assume the font is
2866 // present. The root problem here is that the code that collects
2867 // font substitutions tends to get just empty styles for the font
2868 // that is being substituted, as vcl::Font::GetStyleName() tends to
2869 // return an empty string. (Italicness is instead indicated by what
2870 // vcl::Font::GetItalic() returns and boldness by what
2871 // vcl::Font::GetWeight() returns.)
2873 if (x
.mOriginalFont
.indexOf('/') == -1)
2874 for (const auto &j
: x
.mUsedFonts
)
2875 if (j
== x
.mOriginalFont
||
2876 j
.startsWith(Concat2View(x
.mOriginalFont
+ "/")))
2881 aFontMappingUseData
.end());
2883 // Filter out substitutions where a proprietary font has been substituted by a
2884 // metric-compatible one. Obviously this is just a heuristic and implemented only for some
2885 // well-known cases.
2887 aFontMappingUseData
.erase
2888 (std::remove_if(aFontMappingUseData
.begin(), aFontMappingUseData
.end(),
2889 [](OutputDevice::FontMappingUseItem x
)
2891 // Again, handle only cases where the original font does not include
2892 // a style. Unclear whether there ever will be a style part included
2893 // in the mOriginalFont.
2895 if (x
.mOriginalFont
.indexOf('/') == -1)
2896 for (const auto &j
: x
.mUsedFonts
)
2897 if ((x
.mOriginalFont
== "Arial" &&
2898 j
.startsWith("Liberation Sans/")) ||
2899 (x
.mOriginalFont
== "Times New Roman" &&
2900 j
.startsWith("Liberation Serif/")) ||
2901 (x
.mOriginalFont
== "Courier New" &&
2902 j
.startsWith("Liberation Mono/")) ||
2903 (x
.mOriginalFont
== "Arial Narrow" &&
2904 j
.startsWith("Liberation Sans Narrow/")) ||
2905 (x
.mOriginalFont
== "Cambria" &&
2906 j
.startsWith("Caladea/")) ||
2907 (x
.mOriginalFont
== "Calibri" &&
2908 j
.startsWith("Carlito/")) ||
2909 (x
.mOriginalFont
== "Palatino Linotype" &&
2910 j
.startsWith("P052/")) ||
2911 // Perhaps a risky heuristic? If some glyphs from Symbol
2912 // have been mapped to ones in OpenSymbol, don't warn
2913 // that Symbol is missing.
2914 (x
.mOriginalFont
== "Symbol" &&
2915 j
.startsWith("OpenSymbol/")))
2922 aFontMappingUseData
.end());
2924 if (aFontMappingUseData
.size() > 0)
2926 SAL_INFO("lok.fontsubst", "================ Pruned substitutions:");
2927 for (const auto &i
: aFontMappingUseData
)
2929 SAL_INFO("lok.fontsubst", i
.mOriginalFont
);
2930 for (const auto &j
: i
.mUsedFonts
)
2931 SAL_INFO("lok.fontsubst", " " << j
);
2935 for (std::size_t i
= 0; i
< aFontMappingUseData
.size(); ++i
)
2937 pDocument
->maFontsMissing
.insert(aFontMappingUseData
[i
].mOriginalFont
);
2942 catch (const uno::Exception
& exception
)
2944 pLib
->maLastExceptionMsg
= exception
.Message
;
2945 TOOLS_INFO_EXCEPTION("lok", "Document can't be loaded");
2951 static int lo_runMacro(LibreOfficeKit
* pThis
, const char *pURL
)
2953 comphelper::ProfileZone
aZone("lo_runMacro");
2955 SolarMutexGuard aGuard
;
2957 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2958 pLib
->maLastExceptionMsg
.clear();
2960 OUString
sURL( pURL
, strlen(pURL
), RTL_TEXTENCODING_UTF8
);
2963 pLib
->maLastExceptionMsg
= "Macro to run was not provided.";
2964 SAL_INFO("lok", "Macro URL is empty");
2968 if (!sURL
.startsWith("macro://"))
2970 pLib
->maLastExceptionMsg
= "This doesn't look like macro URL";
2971 SAL_INFO("lok", "Macro URL is invalid");
2975 pLib
->maLastExceptionMsg
.clear();
2979 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
2980 SAL_INFO("lok", "ComponentContext is not available");
2985 aURL
.Complete
= sURL
;
2987 uno::Reference
< util::XURLTransformer
> xParser( util::URLTransformer::create( xContext
) );
2990 xParser
->parseStrict( aURL
);
2992 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
2994 if (!xComponentLoader
.is())
2996 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
2997 SAL_INFO("lok", "ComponentLoader is not available");
3001 xFactory
= xContext
->getServiceManager();
3006 uno::Reference
<frame::XDispatchProvider
> xDP
;
3007 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
3008 xDP
.set( xSFactory
->createInstance("com.sun.star.comp.sfx2.SfxMacroLoader"), uno::UNO_QUERY
);
3009 uno::Reference
<frame::XDispatch
> xD
= xDP
->queryDispatch( aURL
, OUString(), 0);
3013 pLib
->maLastExceptionMsg
= "Macro loader is not available";
3014 SAL_INFO("lok", "Macro loader is not available");
3018 uno::Reference
< frame::XSynchronousDispatch
> xSyncDisp( xD
, uno::UNO_QUERY_THROW
);
3019 uno::Sequence
<css::beans::PropertyValue
> aEmpty
;
3020 css::beans::PropertyValue aErr
;
3021 uno::Any aRet
= xSyncDisp
->dispatchWithReturnValue( aURL
, aEmpty
);
3024 if (aErr
.Name
== "ErrorCode")
3026 sal_uInt32 nErrCode
= 0; // ERRCODE_NONE
3027 aErr
.Value
>>= nErrCode
;
3029 pLib
->maLastExceptionMsg
= "An error occurred running macro (error code: " + OUString::number( nErrCode
) + ")";
3030 SAL_INFO("lok", "Macro execution terminated with error code " << nErrCode
);
3038 static bool lo_signDocument(LibreOfficeKit
* /*pThis*/,
3040 const unsigned char* pCertificateBinary
,
3041 const int nCertificateBinarySize
,
3042 const unsigned char* pPrivateKeyBinary
,
3043 const int nPrivateKeyBinarySize
)
3045 comphelper::ProfileZone
aZone("lo_signDocument");
3047 OUString
aURL(getAbsoluteURL(pURL
));
3054 uno::Sequence
<sal_Int8
> aCertificateSequence
;
3056 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
3057 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
3058 if (!aCertificateBase64String
.empty())
3060 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
);
3061 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
3065 aCertificateSequence
.realloc(nCertificateBinarySize
);
3066 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.getArray());
3069 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
3070 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeyBinarySize
);
3071 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
3072 if (!aPrivateKeyBase64String
.empty())
3074 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
);
3075 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
3079 aPrivateKeySequence
.realloc(nPrivateKeyBinarySize
);
3080 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeyBinarySize
, aPrivateKeySequence
.getArray());
3083 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
3084 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
3085 if (!xSecurityContext
.is())
3088 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
3089 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
3091 if (!xCertificateCreator
.is())
3094 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
3096 if (!xCertificate
.is())
3099 sfx2::DocumentSigner
aDocumentSigner(aURL
);
3100 if (!aDocumentSigner
.signDocument(xCertificate
))
3107 static char* lo_extractRequest(LibreOfficeKit
* /*pThis*/, const char* pFilePath
)
3109 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
3110 uno::Reference
< css::lang::XComponent
> xComp
;
3111 OUString
aURL(getAbsoluteURL(pFilePath
));
3113 if (!aURL
.isEmpty())
3115 if (xComponentLoader
.is())
3119 uno::Sequence
<css::beans::PropertyValue
> aFilterOptions(comphelper::InitPropertySequence(
3121 {"Hidden", css::uno::Any(true)},
3122 {"ReadOnly", css::uno::Any(true)}
3124 xComp
= xComponentLoader
->loadComponentFromURL( aURL
, "_blank", 0, aFilterOptions
);
3126 catch ( const lang::IllegalArgumentException
& ex
)
3128 SAL_WARN("lok", "lo_extractRequest: IllegalArgumentException: " << ex
.Message
);
3130 return convertOUString(result
);
3134 SAL_WARN("lok", "lo_extractRequest: Exception on loadComponentFromURL, url= " << aURL
);
3136 return convertOUString(result
);
3141 uno::Reference
< document::XLinkTargetSupplier
> xLTS( xComp
, uno::UNO_QUERY
);
3145 OUStringBuffer
jsonText("{ \"Targets\": { ");
3146 bool lastParentheses
= extractLinks(xLTS
->getLinks(), false, jsonText
);
3147 jsonText
.append("} }");
3148 if (!lastParentheses
)
3149 jsonText
.append(" }");
3151 OUString
res(jsonText
.makeStringAndClear());
3152 return convertOUString(res
);
3159 return convertOUString(result
);
3165 return convertOUString(result
);
3168 static void lo_trimMemory(LibreOfficeKit
* /* pThis */, int nTarget
)
3170 vcl::lok::trimMemory(nTarget
);
3173 #ifdef HAVE_MALLOC_TRIM
3179 static void lo_registerCallback (LibreOfficeKit
* pThis
,
3180 LibreOfficeKitCallback pCallback
,
3183 SolarMutexGuard aGuard
;
3185 Application
* pApp
= GetpApp();
3188 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
3189 pLib
->maLastExceptionMsg
.clear();
3191 pApp
->m_pCallback
= pLib
->mpCallback
= pCallback
;
3192 pApp
->m_pCallbackData
= pLib
->mpCallbackData
= pData
;
3195 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* sUrl
, const char* pFormat
, const char* pFilterOptions
)
3197 comphelper::ProfileZone
aZone("doc_saveAs");
3199 SolarMutexGuard aGuard
;
3200 SetLastExceptionMsg();
3202 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3204 OUString sFormat
= getUString(pFormat
);
3205 OUString
aURL(getAbsoluteURL(sUrl
));
3207 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
3211 SetLastExceptionMsg("Filename to save to was not provided.");
3212 SAL_INFO("lok", "URL for save is empty");
3218 const ExtensionMap
* pMap
;
3220 switch (doc_getDocumentType(pThis
))
3222 case LOK_DOCTYPE_SPREADSHEET
:
3223 pMap
= aCalcExtensionMap
;
3225 case LOK_DOCTYPE_PRESENTATION
:
3226 pMap
= aImpressExtensionMap
;
3228 case LOK_DOCTYPE_DRAWING
:
3229 pMap
= aDrawExtensionMap
;
3231 case LOK_DOCTYPE_TEXT
:
3232 pMap
= aWriterExtensionMap
;
3234 case LOK_DOCTYPE_OTHER
:
3236 SAL_INFO("lok", "Can't save document - unsupported document type.");
3240 if (pFormat
== nullptr)
3242 // sniff from the extension
3243 sal_Int32 idx
= aURL
.lastIndexOf(".");
3246 sFormat
= aURL
.copy( idx
+ 1 );
3250 SetLastExceptionMsg("input URL '" + aURL
+ "' lacks a suffix");
3255 OUString aFilterName
;
3256 for (sal_Int32 i
= 0; pMap
[i
].extn
; ++i
)
3258 if (sFormat
.equalsIgnoreAsciiCaseAscii(pMap
[i
].extn
))
3260 aFilterName
= getUString(pMap
[i
].filterName
);
3264 if (aFilterName
.isEmpty())
3266 SetLastExceptionMsg("no output filter found for provided suffix");
3270 OUString aFilterOptions
= getUString(pFilterOptions
);
3272 // Check if watermark for pdf is passed by filteroptions...
3273 // It is not a real filter option so it must be filtered out.
3274 OUString watermarkText
;
3275 std::u16string_view sFullSheetPreview
;
3277 if ((aIndex
= aFilterOptions
.indexOf(",Watermark=")) >= 0)
3279 int bIndex
= aFilterOptions
.indexOf("WATERMARKEND");
3280 watermarkText
= aFilterOptions
.subView(aIndex
+11, bIndex
-(aIndex
+11));
3281 aFilterOptions
= OUString::Concat(aFilterOptions
.subView(0, aIndex
)) + aFilterOptions
.subView(bIndex
+12);
3284 if ((aIndex
= aFilterOptions
.indexOf(",FullSheetPreview=")) >= 0)
3286 int bIndex
= aFilterOptions
.indexOf("FULLSHEETPREVEND");
3287 sFullSheetPreview
= aFilterOptions
.subView(aIndex
+18, bIndex
-(aIndex
+18));
3288 aFilterOptions
= OUString::Concat(aFilterOptions
.subView(0, aIndex
)) + aFilterOptions
.subView(bIndex
+16);
3291 bool bFullSheetPreview
= sFullSheetPreview
== u
"true";
3293 // Select a pdf version if specified a valid one. If not specified then ignore.
3294 // If invalid then fail.
3295 sal_Int32 pdfVer
= 0;
3296 if ((aIndex
= aFilterOptions
.indexOf(",PDFVer=")) >= 0)
3298 int bIndex
= aFilterOptions
.indexOf("PDFVEREND");
3299 std::u16string_view sPdfVer
= aFilterOptions
.subView(aIndex
+8, bIndex
-(aIndex
+8));
3300 aFilterOptions
= OUString::Concat(aFilterOptions
.subView(0, aIndex
)) + aFilterOptions
.subView(bIndex
+9);
3302 if (o3tl::equalsIgnoreAsciiCase(sPdfVer
, u
"PDF/A-1b"))
3304 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer
, u
"PDF/A-2b"))
3306 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer
, u
"PDF/A-3b"))
3308 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer
, u
"PDF-1.5"))
3310 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer
, u
"PDF-1.6"))
3314 SetLastExceptionMsg("wrong PDF version");
3319 // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
3320 // gets a new name). When this is not provided, the meaning of
3321 // saveAs() is more like save-a-copy, which allows saving to any
3322 // random format like PDF or PNG.
3323 // It is not a real filter option, so we have to filter it out.
3324 const uno::Sequence
<OUString
> aOptionSeq
= comphelper::string::convertCommaSeparated(aFilterOptions
);
3325 std::vector
<OUString
> aFilteredOptionVec
;
3326 bool bTakeOwnership
= false;
3327 MediaDescriptor aSaveMediaDescriptor
;
3328 for (const auto& rOption
: aOptionSeq
)
3330 if (rOption
== "TakeOwnership")
3331 bTakeOwnership
= true;
3332 else if (rOption
== "NoFileSync")
3333 aSaveMediaDescriptor
["NoFileSync"] <<= true;
3335 aFilteredOptionVec
.push_back(rOption
);
3338 aSaveMediaDescriptor
["Overwrite"] <<= true;
3339 aSaveMediaDescriptor
["FilterName"] <<= aFilterName
;
3341 auto aFilteredOptionSeq
= comphelper::containerToSequence
<OUString
>(aFilteredOptionVec
);
3342 aFilterOptions
= comphelper::string::convertCommaSeparated(aFilteredOptionSeq
);
3343 aSaveMediaDescriptor
[MediaDescriptor::PROP_FILTEROPTIONS
] <<= aFilterOptions
;
3345 comphelper::SequenceAsHashMap aFilterDataMap
;
3347 // If filter options is JSON string, then make sure aFilterDataMap stays empty, otherwise we
3348 // would ignore the filter options.
3349 if (!aFilterOptions
.startsWith("{"))
3351 setFormatSpecificFilterData(sFormat
, aFilterDataMap
);
3354 if (!watermarkText
.isEmpty())
3355 aFilterDataMap
["TiledWatermark"] <<= watermarkText
;
3357 if (bFullSheetPreview
)
3358 aFilterDataMap
["SinglePageSheets"] <<= true;
3361 aFilterDataMap
["SelectPdfVersion"] <<= pdfVer
;
3363 if (!aFilterDataMap
.empty())
3365 aSaveMediaDescriptor
["FilterData"] <<= aFilterDataMap
.getAsConstPropertyValueList();
3368 // add interaction handler too
3371 // gImpl does not have to exist when running from a unit test
3372 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
3373 new LOKInteractionHandler("saveas", gImpl
, pDocument
));
3374 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
);
3376 aSaveMediaDescriptor
[MediaDescriptor::PROP_INTERACTIONHANDLER
] <<= xInteraction
;
3381 xStorable
->storeAsURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
3383 xStorable
->storeToURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
3387 catch (const uno::Exception
& exception
)
3389 SetLastExceptionMsg("exception: " + exception
.Message
);
3395 * Initialize UNO commands, in the sense that from now on, the LOK client gets updates for status
3396 * changes of these commands. This is necessary, because (unlike in the desktop case) there are no
3397 * toolbars hosting widgets these UNO commands, so no such status updates would be sent to the
3398 * headless LOK clients out of the box.
3400 static void doc_iniUnoCommands ()
3402 SolarMutexGuard aGuard
;
3403 SetLastExceptionMsg();
3405 OUString sUnoCommands
[] =
3407 OUString(".uno:AlignLeft"),
3408 OUString(".uno:AlignHorizontalCenter"),
3409 OUString(".uno:AlignRight"),
3410 OUString(".uno:BackColor"),
3411 OUString(".uno:BackgroundColor"),
3412 OUString(".uno:TableCellBackgroundColor"),
3413 OUString(".uno:Bold"),
3414 OUString(".uno:CenterPara"),
3415 OUString(".uno:CharBackColor"),
3416 OUString(".uno:CharBackgroundExt"),
3417 OUString(".uno:CharFontName"),
3418 OUString(".uno:Color"),
3419 OUString(".uno:ControlCodes"),
3420 OUString(".uno:DecrementIndent"),
3421 OUString(".uno:DefaultBullet"),
3422 OUString(".uno:DefaultNumbering"),
3423 OUString(".uno:FontColor"),
3424 OUString(".uno:FontHeight"),
3425 OUString(".uno:IncrementIndent"),
3426 OUString(".uno:Italic"),
3427 OUString(".uno:JustifyPara"),
3428 OUString(".uno:JumpToMark"),
3429 OUString(".uno:OutlineFont"),
3430 OUString(".uno:LeftPara"),
3431 OUString(".uno:LanguageStatus"),
3432 OUString(".uno:RightPara"),
3433 OUString(".uno:Shadowed"),
3434 OUString(".uno:SubScript"),
3435 OUString(".uno:SuperScript"),
3436 OUString(".uno:Strikeout"),
3437 OUString(".uno:StyleApply"),
3438 OUString(".uno:Underline"),
3439 OUString(".uno:ModifiedStatus"),
3440 OUString(".uno:Undo"),
3441 OUString(".uno:Redo"),
3442 OUString(".uno:InsertPage"),
3443 OUString(".uno:DeletePage"),
3444 OUString(".uno:DuplicatePage"),
3445 OUString(".uno:InsertSlide"),
3446 OUString(".uno:DeleteSlide"),
3447 OUString(".uno:DuplicateSlide"),
3448 OUString(".uno:ChangeTheme"),
3449 OUString(".uno:Cut"),
3450 OUString(".uno:Copy"),
3451 OUString(".uno:Paste"),
3452 OUString(".uno:SelectAll"),
3453 OUString(".uno:ReplyComment"),
3454 OUString(".uno:ResolveComment"),
3455 OUString(".uno:ResolveCommentThread"),
3456 OUString(".uno:InsertRowsBefore"),
3457 OUString(".uno:InsertRowsAfter"),
3458 OUString(".uno:InsertColumnsBefore"),
3459 OUString(".uno:InsertColumnsAfter"),
3460 OUString(".uno:DeleteRows"),
3461 OUString(".uno:DeleteColumns"),
3462 OUString(".uno:DeleteTable"),
3463 OUString(".uno:SelectTable"),
3464 OUString(".uno:EntireRow"),
3465 OUString(".uno:EntireColumn"),
3466 OUString(".uno:EntireCell"),
3467 OUString(".uno:AssignLayout"),
3468 OUString(".uno:StatusDocPos"),
3469 OUString(".uno:RowColSelCount"),
3470 OUString(".uno:StatusPageStyle"),
3471 OUString(".uno:InsertMode"),
3472 OUString(".uno:SpellOnline"),
3473 OUString(".uno:StatusSelectionMode"),
3474 OUString(".uno:StateTableCell"),
3475 OUString(".uno:StatusBarFunc"),
3476 OUString(".uno:StatePageNumber"),
3477 OUString(".uno:StateWordCount"),
3478 OUString(".uno:SelectionMode"),
3479 OUString(".uno:PageStatus"),
3480 OUString(".uno:LayoutStatus"),
3481 OUString(".uno:Scale"),
3482 OUString(".uno:Context"),
3483 OUString(".uno:WrapText"),
3484 OUString(".uno:ToggleMergeCells"),
3485 OUString(".uno:NumberFormatCurrency"),
3486 OUString(".uno:NumberFormatPercent"),
3487 OUString(".uno:NumberFormatDecimal"),
3488 OUString(".uno:NumberFormatDate"),
3489 OUString(".uno:EditHeaderAndFooter"),
3490 OUString(".uno:FrameLineColor"),
3491 OUString(".uno:SortAscending"),
3492 OUString(".uno:SortDescending"),
3493 OUString(".uno:TrackChanges"),
3494 OUString(".uno:ShowTrackedChanges"),
3495 OUString(".uno:NextTrackedChange"),
3496 OUString(".uno:PreviousTrackedChange"),
3497 OUString(".uno:AcceptAllTrackedChanges"),
3498 OUString(".uno:RejectAllTrackedChanges"),
3499 OUString(".uno:TableDialog"),
3500 OUString(".uno:FormatCellDialog"),
3501 OUString(".uno:FontDialog"),
3502 OUString(".uno:ParagraphDialog"),
3503 OUString(".uno:OutlineBullet"),
3504 OUString(".uno:InsertIndexesEntry"),
3505 OUString(".uno:DocumentRepair"),
3506 OUString(".uno:TransformDialog"),
3507 OUString(".uno:InsertPageHeader"),
3508 OUString(".uno:InsertPageFooter"),
3509 OUString(".uno:OnlineAutoFormat"),
3510 OUString(".uno:InsertObjectChart"),
3511 OUString(".uno:InsertSection"),
3512 OUString(".uno:InsertAnnotation"),
3513 OUString(".uno:DeleteAnnotation"),
3514 OUString(".uno:InsertPagebreak"),
3515 OUString(".uno:InsertColumnBreak"),
3516 OUString(".uno:HyperlinkDialog"),
3517 OUString(".uno:InsertSymbol"),
3518 OUString(".uno:EditRegion"),
3519 OUString(".uno:ThesaurusDialog"),
3520 OUString(".uno:FormatArea"),
3521 OUString(".uno:FormatLine"),
3522 OUString(".uno:FormatColumns"),
3523 OUString(".uno:Watermark"),
3524 OUString(".uno:ResetAttributes"),
3525 OUString(".uno:Orientation"),
3526 OUString(".uno:ObjectAlignLeft"),
3527 OUString(".uno:ObjectAlignRight"),
3528 OUString(".uno:AlignCenter"),
3529 OUString(".uno:TransformPosX"),
3530 OUString(".uno:TransformPosY"),
3531 OUString(".uno:TransformWidth"),
3532 OUString(".uno:TransformHeight"),
3533 OUString(".uno:ObjectBackOne"),
3534 OUString(".uno:SendToBack"),
3535 OUString(".uno:ObjectForwardOne"),
3536 OUString(".uno:BringToFront"),
3537 OUString(".uno:WrapRight"),
3538 OUString(".uno:WrapThrough"),
3539 OUString(".uno:WrapLeft"),
3540 OUString(".uno:WrapIdeal"),
3541 OUString(".uno:WrapOn"),
3542 OUString(".uno:WrapOff"),
3543 OUString(".uno:UpdateCurIndex"),
3544 OUString(".uno:InsertCaptionDialog"),
3545 OUString(".uno:FormatGroup"),
3546 OUString(".uno:SplitTable"),
3547 OUString(".uno:SplitCell"),
3548 OUString(".uno:MergeCells"),
3549 OUString(".uno:DeleteNote"),
3550 OUString(".uno:AcceptChanges"),
3551 OUString(".uno:FormatPaintbrush"),
3552 OUString(".uno:SetDefault"),
3553 OUString(".uno:ParaLeftToRight"),
3554 OUString(".uno:ParaRightToLeft"),
3555 OUString(".uno:ParaspaceIncrease"),
3556 OUString(".uno:ParaspaceDecrease"),
3557 OUString(".uno:AcceptTrackedChange"),
3558 OUString(".uno:RejectTrackedChange"),
3559 OUString(".uno:ShowResolvedAnnotations"),
3560 OUString(".uno:InsertBreak"),
3561 OUString(".uno:InsertEndnote"),
3562 OUString(".uno:InsertFootnote"),
3563 OUString(".uno:InsertReferenceField"),
3564 OUString(".uno:InsertBookmark"),
3565 OUString(".uno:InsertAuthoritiesEntry"),
3566 OUString(".uno:InsertMultiIndex"),
3567 OUString(".uno:InsertField"),
3568 OUString(".uno:PageNumberWizard"),
3569 OUString(".uno:InsertPageNumberField"),
3570 OUString(".uno:InsertPageCountField"),
3571 OUString(".uno:InsertDateField"),
3572 OUString(".uno:InsertTitleField"),
3573 OUString(".uno:InsertFieldCtrl"),
3574 OUString(".uno:CharmapControl"),
3575 OUString(".uno:EnterGroup"),
3576 OUString(".uno:LeaveGroup"),
3577 OUString(".uno:AlignUp"),
3578 OUString(".uno:AlignMiddle"),
3579 OUString(".uno:AlignDown"),
3580 OUString(".uno:TraceChangeMode"),
3581 OUString(".uno:Combine"),
3582 OUString(".uno:Merge"),
3583 OUString(".uno:Dismantle"),
3584 OUString(".uno:Substract"),
3585 OUString(".uno:DistributeSelection"),
3586 OUString(".uno:Intersect"),
3587 OUString(".uno:BorderInner"),
3588 OUString(".uno:BorderOuter"),
3589 OUString(".uno:FreezePanes"),
3590 OUString(".uno:FreezePanesColumn"),
3591 OUString(".uno:FreezePanesRow"),
3592 OUString(".uno:Sidebar"),
3593 OUString(".uno:SheetRightToLeft"),
3594 OUString(".uno:RunMacro"),
3595 OUString(".uno:SpacePara1"),
3596 OUString(".uno:SpacePara15"),
3597 OUString(".uno:SpacePara2"),
3598 OUString(".uno:InsertSparkline"),
3599 OUString(".uno:DeleteSparkline"),
3600 OUString(".uno:DeleteSparklineGroup"),
3601 OUString(".uno:EditSparklineGroup"),
3602 OUString(".uno:EditSparkline"),
3603 OUString(".uno:GroupSparklines"),
3604 OUString(".uno:UngroupSparklines"),
3605 OUString(".uno:FormatSparklineMenu"),
3606 OUString(".uno:Protect"),
3607 OUString(".uno:UnsetCellsReadOnly"),
3608 OUString(".uno:ContentControlProperties"),
3609 OUString(".uno:InsertCheckboxContentControl"),
3610 OUString(".uno:InsertContentControl"),
3611 OUString(".uno:InsertDateContentControl"),
3612 OUString(".uno:InsertDropdownContentControl"),
3613 OUString(".uno:InsertPlainTextContentControl"),
3614 OUString(".uno:InsertPictureContentControl")
3617 util::URL aCommandURL
;
3618 SfxViewShell
* pViewShell
= SfxViewShell::Current();
3619 SfxViewFrame
* pViewFrame
= pViewShell
? &pViewShell
->GetViewFrame() : nullptr;
3621 // check if Frame-Controller were created.
3624 SAL_WARN("lok", "iniUnoCommands: No Frame-Controller created.");
3629 xContext
= comphelper::getProcessComponentContext();
3632 SAL_WARN("lok", "iniUnoCommands: Component context is not available");
3636 #if !defined IOS && !defined ANDROID && !defined __EMSCRIPTEN__
3637 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
3638 if (!xSEInitializer
.is())
3640 SAL_WARN("lok", "iniUnoCommands: XSEInitializer is not available");
3644 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
=
3645 xSEInitializer
->createSecurityContext(OUString());
3646 if (!xSecurityContext
.is())
3648 SAL_WARN("lok", "iniUnoCommands: failed to create security context");
3652 SfxSlotPool
& rSlotPool
= SfxSlotPool::GetSlotPool(pViewFrame
);
3653 uno::Reference
<util::XURLTransformer
> xParser(util::URLTransformer::create(xContext
));
3655 for (const auto & sUnoCommand
: sUnoCommands
)
3657 aCommandURL
.Complete
= sUnoCommand
;
3658 xParser
->parseStrict(aCommandURL
);
3660 // when null, this command is not supported by the given component
3661 // (like eg. Calc does not have ".uno:DefaultBullet" etc.)
3662 if (const SfxSlot
* pSlot
= rSlotPool
.GetUnoSlot(aCommandURL
.Path
))
3664 // Initialize slot to dispatch .uno: Command.
3665 pViewFrame
->GetBindings().GetDispatch(pSlot
, aCommandURL
, false);
3670 static int doc_getDocumentType (LibreOfficeKitDocument
* pThis
)
3672 comphelper::ProfileZone
aZone("doc_getDocumentType");
3674 SolarMutexGuard aGuard
;
3675 return getDocumentType(pThis
);
3678 static int doc_getParts (LibreOfficeKitDocument
* pThis
)
3680 comphelper::ProfileZone
aZone("doc_getParts");
3682 SolarMutexGuard aGuard
;
3684 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3687 SetLastExceptionMsg("Document doesn't support tiled rendering");
3691 return pDoc
->getParts();
3694 static int doc_getPart (LibreOfficeKitDocument
* pThis
)
3696 comphelper::ProfileZone
aZone("doc_getPart");
3698 SolarMutexGuard aGuard
;
3699 SetLastExceptionMsg();
3701 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3704 SetLastExceptionMsg("Document doesn't support tiled rendering");
3708 return pDoc
->getPart();
3711 static void doc_setPartImpl(LibreOfficeKitDocument
* pThis
, int nPart
, bool bAllowChangeFocus
= true)
3713 comphelper::ProfileZone
aZone("doc_setPart");
3715 SolarMutexGuard aGuard
;
3716 SetLastExceptionMsg();
3718 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3721 SetLastExceptionMsg("Document doesn't support tiled rendering");
3725 pDoc
->setPart( nPart
, bAllowChangeFocus
);
3728 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
)
3730 doc_setPartImpl(pThis
, nPart
, true);
3733 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
)
3735 comphelper::ProfileZone
aZone("doc_getPartInfo");
3737 SolarMutexGuard aGuard
;
3738 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3741 SetLastExceptionMsg("Document doesn't support tiled rendering");
3745 return convertOUString(pDoc
->getPartInfo(nPart
));
3748 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
)
3750 SolarMutexGuard aGuard
;
3752 gImpl
->maLastExceptionMsg
.clear();
3754 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3757 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3761 pDoc
->selectPart( nPart
, nSelect
);
3764 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
)
3766 SolarMutexGuard aGuard
;
3768 gImpl
->maLastExceptionMsg
.clear();
3770 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3773 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3777 pDoc
->moveSelectedParts(nPosition
, bDuplicate
);
3780 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
)
3782 comphelper::ProfileZone
aZone("doc_getPartPageRectangles");
3784 SolarMutexGuard aGuard
;
3785 SetLastExceptionMsg();
3787 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3790 SetLastExceptionMsg("Document doesn't support tiled rendering");
3794 return convertOUString(pDoc
->getPartPageRectangles());
3797 static char* doc_getA11yFocusedParagraph(LibreOfficeKitDocument
* pThis
)
3799 SolarMutexGuard aGuard
;
3800 SetLastExceptionMsg();
3802 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3805 SetLastExceptionMsg("Document doesn't support tiled rendering");
3809 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
3811 return convertOUString(pViewShell
->getA11yFocusedParagraph());
3817 static int doc_getA11yCaretPosition(LibreOfficeKitDocument
* pThis
)
3819 SolarMutexGuard aGuard
;
3820 SetLastExceptionMsg();
3822 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3825 SetLastExceptionMsg("Document doesn't support tiled rendering");
3828 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
3830 return pViewShell
->getA11yCaretPosition();
3837 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
)
3839 comphelper::ProfileZone
aZone("doc_getPartName");
3841 SolarMutexGuard aGuard
;
3842 SetLastExceptionMsg();
3844 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3847 SetLastExceptionMsg("Document doesn't support tiled rendering");
3851 return convertOUString(pDoc
->getPartName(nPart
));
3854 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
)
3856 comphelper::ProfileZone
aZone("doc_getPartHash");
3858 SolarMutexGuard aGuard
;
3859 SetLastExceptionMsg();
3861 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3864 SetLastExceptionMsg("Document doesn't support tiled rendering");
3868 return convertOUString(pDoc
->getPartHash(nPart
));
3871 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
,
3874 comphelper::ProfileZone
aZone("doc_setPartMode");
3876 SolarMutexGuard aGuard
;
3877 SetLastExceptionMsg();
3879 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3882 SetLastExceptionMsg("Document doesn't support tiled rendering");
3887 int nCurrentPart
= pDoc
->getPart();
3889 pDoc
->setPartMode(nPartMode
);
3891 // We need to make sure the internal state is updated, just changing the mode
3892 // might not update the relevant shells (i.e. impress will keep rendering the
3893 // previous mode unless we do this).
3894 // TODO: we might want to do this within the relevant components rather than
3895 // here, but that's also dependent on how we implement embedded object
3896 // rendering I guess?
3897 // TODO: we could be clever and e.g. set to 0 when we change to/from
3898 // embedded object mode, and not when changing between slide/notes/combined
3900 if ( nCurrentPart
< pDoc
->getParts() )
3902 pDoc
->setPart( nCurrentPart
);
3910 static int doc_getEditMode(LibreOfficeKitDocument
* pThis
)
3912 comphelper::ProfileZone
aZone("doc_getEditMode");
3914 SolarMutexGuard aGuard
;
3915 SetLastExceptionMsg();
3917 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3920 SetLastExceptionMsg("Document doesn't support tiled rendering");
3924 return pDoc
->getEditMode();
3927 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
3928 unsigned char* pBuffer
,
3929 const int nCanvasWidth
, const int nCanvasHeight
,
3930 const int nTilePosX
, const int nTilePosY
,
3931 const int nTileWidth
, const int nTileHeight
)
3933 comphelper::ProfileZone
aZone("doc_paintTile");
3935 SolarMutexGuard aGuard
;
3936 SetLastExceptionMsg();
3938 SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth
<< "x" << nTileHeight
<<
3939 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
3940 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
3942 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3945 SetLastExceptionMsg("Document doesn't support tiled rendering");
3949 #if defined(UNX) && !defined(MACOSX) || defined(_WIN32)
3951 // Painting of zoomed or HiDPI spreadsheets is special, we actually draw everything at 100%,
3952 // and only set cairo's (or CoreGraphic's, in the iOS case) scale factor accordingly, so that
3953 // everything is painted bigger or smaller. This is different to what Calc's internal scaling
3954 // would do - because that one is trying to fit the lines between cells to integer multiples of
3956 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
3959 double fDPIScale
= 1.0;
3961 CGContextRef pCGContext
= CGBitmapContextCreate(pBuffer
, nCanvasWidth
, nCanvasHeight
, 8,
3962 nCanvasWidth
* 4, CGColorSpaceCreateDeviceRGB(),
3963 kCGImageAlphaPremultipliedFirst
| kCGImageByteOrder32Little
);
3965 CGContextTranslateCTM(pCGContext
, 0, nCanvasHeight
);
3966 CGContextScaleCTM(pCGContext
, fDPIScale
, -fDPIScale
);
3968 SAL_INFO( "lok.tiledrendering", "doc_paintTile: painting [" << nTileWidth
<< "x" << nTileHeight
<<
3969 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
3970 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
3972 Size
aCanvasSize(nCanvasWidth
, nCanvasHeight
);
3974 SystemGraphicsData aData
;
3975 aData
.rCGContext
= reinterpret_cast<CGContextRef
>(pCGContext
);
3977 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::WITHOUT_ALPHA
);
3978 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
3979 pDevice
->SetOutputSizePixel(aCanvasSize
);
3980 pDoc
->paintTile(*pDevice
, aCanvasSize
.Width(), aCanvasSize
.Height(),
3981 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
3983 CGContextRelease(pCGContext
);
3985 ScopedVclPtrInstance
< VirtualDevice
> pDevice(DeviceFormat::WITHOUT_ALPHA
);
3987 // Set background to transparent by default.
3988 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
3990 pDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(
3991 Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(),
3994 pDoc
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
,
3995 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
3997 static bool bDebug
= getenv("LOK_DEBUG_TILES") != nullptr;
4000 // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
4001 tools::Rectangle
aRect(0, 0, 5, 5);
4002 aRect
= pDevice
->PixelToLogic(aRect
);
4003 pDevice
->Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
4004 pDevice
->SetFillColor(COL_LIGHTRED
);
4005 pDevice
->SetLineColor();
4006 pDevice
->DrawRect(aRect
);
4011 // pBuffer was not used there
4012 pDevice
->EnableMapMode(false);
4013 BitmapEx aBmpEx
= pDevice
->GetBitmapEx({ 0, 0 }, { nCanvasWidth
, nCanvasHeight
});
4014 Bitmap aBmp
= aBmpEx
.GetBitmap();
4015 Bitmap aAlpha
= aBmpEx
.GetAlphaMask();
4016 Bitmap::ScopedReadAccess
sraBmp(aBmp
);
4017 Bitmap::ScopedReadAccess
sraAlpha(aAlpha
);
4019 assert(sraBmp
->Height() == nCanvasHeight
);
4020 assert(sraBmp
->Width() == nCanvasWidth
);
4021 assert(!sraAlpha
|| sraBmp
->Height() == sraAlpha
->Height());
4022 assert(!sraAlpha
|| sraBmp
->Width() == sraAlpha
->Width());
4024 for (tools::Long y
= 0; y
< sraBmp
->Height(); ++y
)
4026 Scanline dataBmp
= sraBmp
->GetScanline(y
);
4027 Scanline dataAlpha
= sraAlpha
? sraAlpha
->GetScanline(y
) : nullptr;
4028 for (tools::Long x
= 0; x
< sraBmp
->Width(); ++x
)
4030 BitmapColor color
= sraBmp
->GetPixelFromData(dataBmp
, x
);
4031 sal_uInt8 alpha
= dataAlpha
? sraAlpha
->GetPixelFromData(dataAlpha
, x
).GetBlue() : 255;
4032 *p
++ = color
.GetBlue();
4033 *p
++ = color
.GetGreen();
4034 *p
++ = color
.GetRed();
4046 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
4047 unsigned char* pBuffer
,
4050 const int nCanvasWidth
, const int nCanvasHeight
,
4051 const int nTilePosX
, const int nTilePosY
,
4052 const int nTileWidth
, const int nTileHeight
)
4054 comphelper::ProfileZone
aZone("doc_paintPartTile");
4056 SolarMutexGuard aGuard
;
4057 SetLastExceptionMsg();
4059 SAL_INFO( "lok.tiledrendering", "paintPartTile: painting @ " << nPart
<< " : " << nMode
<< " ["
4060 << nTileWidth
<< "x" << nTileHeight
<< "]@("
4061 << nTilePosX
<< ", " << nTilePosY
<< ") to ["
4062 << nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
4064 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4065 int nOrigViewId
= doc_getView(pThis
);
4067 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4070 SetLastExceptionMsg("Document doesn't support tiled rendering");
4074 if (nOrigViewId
< 0)
4076 // tile painting always needs a SfxViewShell::Current(), but actually
4077 // it does not really matter which one - all of them should paint the
4078 // same thing. It's important to get a view for the correct document,
4080 // doc_getViewsCount() returns the count of views for the document in the current view.
4081 int viewCount
= doc_getViewsCount(pThis
);
4085 std::vector
<int> viewIds(viewCount
);
4086 doc_getViewIds(pThis
, viewIds
.data(), viewCount
);
4088 nOrigViewId
= viewIds
[0];
4089 doc_setView(pThis
, nOrigViewId
);
4092 // Disable callbacks while we are painting.
4093 if (nOrigViewId
>= 0)
4095 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
4096 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4097 handlerIt
->second
->disableCallbacks();
4102 // Text documents have a single coordinate system; don't change part.
4104 const int aType
= doc_getDocumentType(pThis
);
4105 const bool isText
= (aType
== LOK_DOCTYPE_TEXT
);
4106 const bool isCalc
= (aType
== LOK_DOCTYPE_SPREADSHEET
);
4107 int nOrigEditMode
= 0;
4108 bool bPaintTextEdit
= true;
4109 int nViewId
= nOrigViewId
;
4110 int nLastNonEditorView
= -1;
4111 int nViewMatchingMode
= -1;
4114 // Check if just switching to another view is enough, that has
4115 // less side-effects.
4116 if (nPart
!= doc_getPart(pThis
) || nMode
!= pDoc
->getEditMode())
4118 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
4121 bool bIsInEdit
= pViewShell
->GetDrawView() &&
4122 pViewShell
->GetDrawView()->GetTextEditOutliner();
4124 nLastNonEditorView
= pViewShell
->GetViewShellId().get();
4126 if (pViewShell
->getPart() == nPart
&&
4127 pViewShell
->getEditMode() == nMode
&&
4130 nViewId
= pViewShell
->GetViewShellId().get();
4131 nViewMatchingMode
= nViewId
;
4132 nLastNonEditorView
= nViewId
;
4133 doc_setView(pThis
, nViewId
);
4136 else if (pViewShell
->getEditMode() == nMode
&& !bIsInEdit
)
4138 nViewMatchingMode
= pViewShell
->GetViewShellId().get();
4141 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
4145 // if not found view with correct part
4146 // - at least avoid rendering active textbox, This is for Impress.
4147 // - prefer view with the same mode
4148 SfxViewShell
* pCurrentViewShell
= SfxViewShell::Current();
4149 if (nViewMatchingMode
>= 0 && nViewMatchingMode
!= nViewId
)
4151 nViewId
= nViewMatchingMode
;
4152 doc_setView(pThis
, nViewId
);
4154 else if (!isCalc
&& nLastNonEditorView
>= 0 && nLastNonEditorView
!= nViewId
&&
4155 pCurrentViewShell
&& pCurrentViewShell
->GetDrawView() &&
4156 pCurrentViewShell
->GetDrawView()->GetTextEditOutliner())
4158 nViewId
= nLastNonEditorView
;
4159 doc_setView(pThis
, nViewId
);
4162 // Disable callbacks while we are painting - after setting the view
4163 if (nViewId
!= nOrigViewId
&& nViewId
>= 0)
4165 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nViewId
);
4166 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4167 handlerIt
->second
->disableCallbacks();
4170 nOrigPart
= doc_getPart(pThis
);
4171 if (nPart
!= nOrigPart
)
4173 doc_setPartImpl(pThis
, nPart
, false);
4176 nOrigEditMode
= pDoc
->getEditMode();
4177 if (nOrigEditMode
!= nMode
)
4179 SfxLokHelper::setEditMode(nMode
, pDoc
);
4182 bPaintTextEdit
= (nPart
== nOrigPart
&& nMode
== nOrigEditMode
);
4183 pDoc
->setPaintTextEdit(bPaintTextEdit
);
4186 doc_paintTile(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
4190 pDoc
->setPaintTextEdit(true);
4192 if (nMode
!= nOrigEditMode
)
4194 SfxLokHelper::setEditMode(nOrigEditMode
, pDoc
);
4197 if (nPart
!= nOrigPart
)
4199 doc_setPartImpl(pThis
, nOrigPart
, false);
4202 if (nViewId
!= nOrigViewId
)
4206 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nViewId
);
4207 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4208 handlerIt
->second
->enableCallbacks();
4211 doc_setView(pThis
, nOrigViewId
);
4215 catch (const std::exception
&)
4217 // Nothing to do but restore the PartTilePainting flag.
4220 if (nOrigViewId
>= 0)
4222 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
4223 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
4224 handlerIt
->second
->enableCallbacks();
4228 static int doc_getTileMode(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
4230 SetLastExceptionMsg();
4231 return LOK_TILEMODE_BGRA
;
4234 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
4238 comphelper::ProfileZone
aZone("doc_getDocumentSize");
4240 SolarMutexGuard aGuard
;
4241 SetLastExceptionMsg();
4243 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4246 Size aDocumentSize
= pDoc
->getDocumentSize();
4247 *pWidth
= aDocumentSize
.Width();
4248 *pHeight
= aDocumentSize
.Height();
4252 SetLastExceptionMsg("Document doesn't support tiled rendering");
4256 static void doc_getDataArea(LibreOfficeKitDocument
* pThis
,
4261 comphelper::ProfileZone
aZone("doc_getDataArea");
4263 SolarMutexGuard aGuard
;
4264 SetLastExceptionMsg();
4266 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4269 Size aDocumentSize
= pDoc
->getDataArea(nTab
);
4270 *pCol
= aDocumentSize
.Width();
4271 *pRow
= aDocumentSize
.Height();
4275 SetLastExceptionMsg("Document doesn't support tiled rendering");
4279 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
4280 const char* pArguments
)
4282 comphelper::ProfileZone
aZone("doc_initializeForRendering");
4284 SolarMutexGuard aGuard
;
4285 SetLastExceptionMsg();
4287 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4290 doc_iniUnoCommands();
4291 pDoc
->initializeForTiledRendering(
4292 comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments
)));
4296 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
4297 LibreOfficeKitCallback pCallback
,
4300 SolarMutexGuard aGuard
;
4301 SetLastExceptionMsg();
4303 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4305 const int nView
= SfxLokHelper::getView();
4309 const size_t nId
= nView
;
4310 if (pCallback
!= nullptr)
4312 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
4314 if (pair
.first
== nId
)
4317 pair
.second
->addViewStates(nView
);
4322 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
4324 if (pair
.first
== nId
)
4327 pair
.second
->removeViewStates(nView
);
4331 pDocument
->mpCallbackFlushHandlers
[nView
] = std::make_shared
<CallbackFlushHandler
>(pThis
, pCallback
, pData
);
4333 if (pCallback
!= nullptr)
4335 for (const auto& pair
: pDocument
->mpCallbackFlushHandlers
)
4337 if (pair
.first
== nId
)
4340 pDocument
->mpCallbackFlushHandlers
[nView
]->addViewStates(pair
.first
);
4343 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
4345 pDocument
->mpCallbackFlushHandlers
[nView
]->setViewId(pViewShell
->GetViewShellId().get());
4346 pViewShell
->setLibreOfficeKitViewCallback(pDocument
->mpCallbackFlushHandlers
[nView
].get());
4349 if (pDocument
->maFontsMissing
.size() != 0)
4351 std::string sPayload
= "{ \"fontsmissing\": [ ";
4353 for (const auto &f
: pDocument
->maFontsMissing
)
4359 sPayload
+= "\"" + std::string(f
.toUtf8()) + "\"";
4362 pCallback(LOK_CALLBACK_FONTS_MISSING
, sPayload
.c_str(), pData
);
4363 pDocument
->maFontsMissing
.clear();
4368 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
4370 pViewShell
->setLibreOfficeKitViewCallback(nullptr);
4371 pDocument
->mpCallbackFlushHandlers
[nView
]->setViewId(-1);
4376 /// Returns the JSON representation of all the comments in the document
4377 static char* getPostIts(LibreOfficeKitDocument
* pThis
)
4379 SetLastExceptionMsg();
4380 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4383 SetLastExceptionMsg("Document doesn't support tiled rendering");
4386 tools::JsonWriter aJsonWriter
;
4387 pDoc
->getPostIts(aJsonWriter
);
4388 return strdup(aJsonWriter
.finishAndGetAsOString().getStr());
4391 /// Returns the JSON representation of the positions of all the comments in the document
4392 static char* getPostItsPos(LibreOfficeKitDocument
* pThis
)
4394 SetLastExceptionMsg();
4395 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4398 SetLastExceptionMsg("Document doesn't support tiled rendering");
4401 tools::JsonWriter aJsonWriter
;
4402 pDoc
->getPostItsPos(aJsonWriter
);
4403 return strdup(aJsonWriter
.finishAndGetAsOString().getStr());
4406 static char* getRulerState(LibreOfficeKitDocument
* pThis
)
4408 SetLastExceptionMsg();
4409 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4412 SetLastExceptionMsg("Document doesn't support tiled rendering");
4415 tools::JsonWriter aJsonWriter
;
4416 pDoc
->getRulerState(aJsonWriter
);
4417 return strdup(aJsonWriter
.finishAndGetAsOString().getStr());
4420 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nCharCode
, int nKeyCode
)
4422 comphelper::ProfileZone
aZone("doc_postKeyEvent");
4424 SolarMutexGuard aGuard
;
4425 SetLastExceptionMsg();
4427 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4430 SetLastExceptionMsg("Document doesn't support tiled rendering");
4436 pDoc
->postKeyEvent(nType
, nCharCode
, nKeyCode
);
4438 catch (const uno::Exception
& exception
)
4440 SetLastExceptionMsg(exception
.Message
);
4441 SAL_INFO("lok", "Failed to postKeyEvent " << exception
.Message
);
4445 static void doc_setBlockedCommandList(LibreOfficeKitDocument
* /*pThis*/, int nViewId
, const char* blockedCommandList
)
4447 SolarMutexGuard aGuard
;
4448 SfxLokHelper::setBlockedCommandList(nViewId
, blockedCommandList
);
4451 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
, unsigned nWindowId
, int nType
, const char* pText
)
4453 comphelper::ProfileZone
aZone("doc_postWindowExtTextInputEvent");
4455 SolarMutexGuard aGuard
;
4456 VclPtr
<vcl::Window
> pWindow
;
4459 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4462 SetLastExceptionMsg("Document doesn't support tiled rendering");
4465 pWindow
= pDoc
->getDocWindow();
4469 pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
4474 SetLastExceptionMsg("No window found for window id: " + OUString::number(nWindowId
));
4478 SfxLokHelper::postExtTextEventAsync(pWindow
, nType
, OUString::fromUtf8(std::string_view(pText
, strlen(pText
))));
4481 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, int nCharBefore
, int nCharAfter
)
4483 SolarMutexGuard aGuard
;
4484 VclPtr
<vcl::Window
> pWindow
;
4485 if (nLOKWindowId
== 0)
4487 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4490 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
4493 pWindow
= pDoc
->getDocWindow();
4497 pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4502 gImpl
->maLastExceptionMsg
= "No window found for window id: " + OUString::number(nLOKWindowId
);
4506 // Annoyingly - backspace and delete are handled in the apps via an accelerator
4507 // which are PostMessage'd by SfxViewShell::ExecKey_Impl so to stay in the same
4508 // order we do this synchronously here, unless we're in a dialog.
4509 if (nCharBefore
> 0)
4512 if (nLOKWindowId
== 0)
4514 KeyEvent
aEvt(8, 1283);
4515 for (int i
= 0; i
< nCharBefore
; ++i
)
4516 pWindow
->KeyInput(aEvt
);
4519 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 8, 1283, nCharBefore
- 1);
4525 if (nLOKWindowId
== 0)
4527 KeyEvent
aEvt(46, 1286);
4528 for (int i
= 0; i
< nCharAfter
; ++i
)
4529 pWindow
->KeyInput(aEvt
);
4532 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 46, 1286, nCharAfter
- 1);
4536 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nCharCode
, int nKeyCode
)
4538 comphelper::ProfileZone
aZone("doc_postWindowKeyEvent");
4540 SolarMutexGuard aGuard
;
4541 SetLastExceptionMsg();
4543 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4546 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4550 KeyEvent
aEvent(nCharCode
, nKeyCode
, 0);
4554 case LOK_KEYEVENT_KEYINPUT
:
4555 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
4557 case LOK_KEYEVENT_KEYUP
:
4558 Application::PostKeyEvent(VclEventId::WindowKeyUp
, pWindow
, &aEvent
);
4566 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
)
4568 comphelper::ProfileZone
aZone("doc_renderShapeSelection");
4570 SolarMutexGuard aGuard
;
4571 SetLastExceptionMsg();
4573 LokChartHelper
aChartHelper(SfxViewShell::Current());
4575 if (aChartHelper
.GetWindow())
4580 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4582 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
4584 SvMemoryStream aOutStream
;
4585 uno::Reference
<io::XOutputStream
> xOut
= new utl::OOutputStreamWrapper(aOutStream
);
4587 utl::MediaDescriptor aMediaDescriptor
;
4588 switch (doc_getDocumentType(pThis
))
4590 case LOK_DOCTYPE_PRESENTATION
:
4591 aMediaDescriptor
["FilterName"] <<= OUString("impress_svg_Export");
4593 case LOK_DOCTYPE_DRAWING
:
4594 aMediaDescriptor
["FilterName"] <<= OUString("draw_svg_Export");
4596 case LOK_DOCTYPE_TEXT
:
4597 aMediaDescriptor
["FilterName"] <<= OUString("writer_svg_Export");
4599 case LOK_DOCTYPE_SPREADSHEET
:
4600 aMediaDescriptor
["FilterName"] <<= OUString("calc_svg_Export");
4603 SAL_WARN("lok", "Failed to render shape selection: Document type is not supported");
4605 aMediaDescriptor
["SelectionOnly"] <<= true;
4606 aMediaDescriptor
["OutputStream"] <<= xOut
;
4607 aMediaDescriptor
["IsPreview"] <<= true; // will down-scale graphics
4609 xStorable
->storeToURL("private:stream", aMediaDescriptor
.getAsConstPropertyValueList());
4613 const size_t nOutputSize
= aOutStream
.GetEndOfData();
4614 *pOutput
= static_cast<char*>(malloc(nOutputSize
));
4617 std::memcpy(*pOutput
, aOutStream
.GetData(), nOutputSize
);
4622 catch (const uno::Exception
& exception
)
4624 css::uno::Any
exAny( cppu::getCaughtException() );
4625 SetLastExceptionMsg(exception
.Message
);
4626 SAL_WARN("lok", "Failed to render shape selection: " << exceptionToString(exAny
));
4634 /** Class to react on finishing of a dispatched command.
4636 This will call a LOK_COMMAND_FINISHED callback when postUnoCommand was
4637 called with the parameter requesting the notification.
4639 @see LibreOfficeKitCallbackType::LOK_CALLBACK_UNO_COMMAND_RESULT.
4641 class DispatchResultListener
: public cppu::WeakImplHelper
<css::frame::XDispatchResultListener
>
4643 const OString maCommand
; ///< Command for which this is the result.
4644 const std::shared_ptr
<CallbackFlushHandler
> mpCallback
; ///< Callback to call.
4645 const std::chrono::steady_clock::time_point mSaveTime
; //< The time we started saving.
4646 const bool mbWasModified
; //< Whether or not the document was modified before saving.
4649 DispatchResultListener(const char* pCommand
, std::shared_ptr
<CallbackFlushHandler
> pCallback
)
4650 : maCommand(pCommand
)
4651 , mpCallback(std::move(pCallback
))
4652 , mSaveTime(std::chrono::steady_clock::now())
4653 , mbWasModified(SfxObjectShell::Current()->IsModified())
4658 virtual void SAL_CALL
dispatchFinished(const css::frame::DispatchResultEvent
& rEvent
) override
4660 tools::JsonWriter aJson
;
4661 aJson
.put("commandName", maCommand
);
4663 if (rEvent
.State
!= frame::DispatchResultState::DONTKNOW
)
4665 bool bSuccess
= (rEvent
.State
== frame::DispatchResultState::SUCCESS
);
4666 aJson
.put("success", bSuccess
);
4669 unoAnyToJson(aJson
, "result", rEvent
.Result
);
4670 aJson
.put("wasModified", mbWasModified
);
4671 aJson
.put("startUnixTimeMics",
4672 std::chrono::time_point_cast
<std::chrono::microseconds
>(mSaveTime
)
4675 aJson
.put("saveDurationMics", std::chrono::duration_cast
<std::chrono::microseconds
>(
4676 std::chrono::steady_clock::now() - mSaveTime
)
4678 mpCallback
->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aJson
.finishAndGetAsOString());
4681 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
{}
4684 } // anonymous namespace
4687 static void lcl_sendDialogEvent(unsigned long long int nWindowId
, const char* pArguments
)
4689 SolarMutexGuard aGuard
;
4691 StringMap
aMap(jsdialog::jsonToStringMap(pArguments
));
4693 if (aMap
.find("id") == aMap
.end())
4696 sal_uInt64 nCurrentShellId
= reinterpret_cast<sal_uInt64
>(SfxViewShell::Current());
4700 OUString sControlId
= aMap
["id"];
4702 // dialogs send own id but notebookbar and sidebar controls are remembered by SfxViewShell id
4703 if (jsdialog::ExecuteAction(OUString::number(nWindowId
), sControlId
, aMap
))
4705 auto sCurrentShellId
= OUString::number(nCurrentShellId
);
4706 if (jsdialog::ExecuteAction(sCurrentShellId
+ "sidebar", sControlId
, aMap
))
4708 if (jsdialog::ExecuteAction(sCurrentShellId
+ "notebookbar", sControlId
, aMap
))
4710 if (jsdialog::ExecuteAction(sCurrentShellId
+ "formulabar", sControlId
, aMap
))
4712 // this is needed for dialogs shown before document is loaded: MacroWarning dialog, etc...
4713 // these dialogs are created with WindowId "0"
4714 if (!SfxViewShell::Current() && jsdialog::ExecuteAction("0", sControlId
, aMap
))
4717 // force resend - used in mobile-wizard
4718 jsdialog::SendFullUpdate(sCurrentShellId
+ "sidebar", "Panel");
4724 static void doc_sendDialogEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned long long int nWindowId
, const char* pArguments
)
4726 lcl_sendDialogEvent(nWindowId
, pArguments
);
4729 static void lo_sendDialogEvent(LibreOfficeKit
* /*pThis*/, unsigned long long int nWindowId
, const char* pArguments
)
4731 lcl_sendDialogEvent(nWindowId
, pArguments
);
4734 static void lo_setOption(LibreOfficeKit
* /*pThis*/, const char *pOption
, const char* pValue
)
4736 static char* pCurrentSalLogOverride
= nullptr;
4738 if (strcmp(pOption
, "traceeventrecording") == 0)
4740 if (strcmp(pValue
, "start") == 0)
4742 comphelper::TraceEvent::setBufferSizeAndCallback(100, TraceEventDumper::flushRecordings
);
4743 comphelper::TraceEvent::startRecording();
4744 if (traceEventDumper
== nullptr)
4745 traceEventDumper
= new TraceEventDumper();
4747 else if (strcmp(pValue
, "stop") == 0)
4748 comphelper::TraceEvent::stopRecording();
4750 else if (strcmp(pOption
, "sallogoverride") == 0)
4752 if (pCurrentSalLogOverride
!= nullptr)
4753 free(pCurrentSalLogOverride
);
4754 if (pValue
== nullptr)
4755 pCurrentSalLogOverride
= nullptr;
4757 pCurrentSalLogOverride
= strdup(pValue
);
4759 if (pCurrentSalLogOverride
== nullptr || pCurrentSalLogOverride
[0] == '\0')
4760 sal_detail_set_log_selector(nullptr);
4762 sal_detail_set_log_selector(pCurrentSalLogOverride
);
4765 else if (strcmp(pOption
, "addfont") == 0)
4767 if (memcmp(pValue
, "file://", 7) == 0)
4770 int fd
= open(pValue
, O_RDONLY
);
4773 std::cerr
<< "Could not open font file '" << pValue
<< "': " << strerror(errno
) << std::endl
;
4777 OUString sMagicFileName
= "file:///:FD:/" + OUString::number(fd
);
4779 OutputDevice
*pDevice
= Application::GetDefaultDevice();
4780 OutputDevice::ImplClearAllFontData(false);
4781 pDevice
->AddTempDevFont(sMagicFileName
, "");
4782 OutputDevice::ImplRefreshAllFontData(false);
4787 static void lo_dumpState (LibreOfficeKit
* pThis
, const char* /* pOptions */, char** pState
)
4792 // NB. no SolarMutexGuard since this may be caused in some extremis / deadlock
4793 SetLastExceptionMsg();
4796 OStringBuffer
aState(4096*256);
4798 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
4800 pLib
->dumpState(aState
);
4802 OString aStr
= aState
.makeStringAndClear();
4803 *pState
= strdup(aStr
.getStr());
4806 void LibLibreOffice_Impl::dumpState(rtl::OStringBuffer
&rState
)
4808 rState
.append("LibreOfficeKit state:");
4809 rState
.append("\n\tLastExceptionMsg:\t");
4810 rState
.append(rtl::OUStringToOString(maLastExceptionMsg
, RTL_TEXTENCODING_UTF8
));
4811 rState
.append("\n\tUnipoll:\t");
4812 rState
.append(vcl::lok::isUnipoll() ? "yes" : "no: events on thread");
4813 rState
.append("\n\tOptionalFeatures:\t0x");
4814 rState
.append(static_cast<sal_Int64
>(mOptionalFeatures
), 16);
4815 rState
.append("\n\tCallbackData:\t0x");
4816 rState
.append(reinterpret_cast<sal_Int64
>(mpCallback
), 16);
4817 // TODO: dump mInteractionMap
4818 SfxLokHelper::dumpState(rState
);
4819 vcl::lok::dumpState(rState
);
4822 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
, const char* pCommand
, const char* pArguments
, bool bNotifyWhenFinished
)
4824 comphelper::ProfileZone
aZone("doc_postUnoCommand");
4826 SolarMutexGuard aGuard
;
4827 SetLastExceptionMsg();
4829 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4830 OUString
aCommand(pCommand
, strlen(pCommand
), RTL_TEXTENCODING_UTF8
);
4831 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4833 std::vector
<beans::PropertyValue
> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments
));
4835 if (!vcl::lok::isUnipoll())
4837 beans::PropertyValue aSynchronMode
;
4838 aSynchronMode
.Name
= "SynchronMode";
4839 aSynchronMode
.Value
<<= false;
4840 aPropertyValuesVector
.push_back(aSynchronMode
);
4843 int nView
= SfxLokHelper::getView();
4847 if (gImpl
&& aCommand
== ".uno:ToggleOrientation")
4849 ExecuteOrientationChange();
4853 // handle potential interaction
4854 if (gImpl
&& aCommand
== ".uno:Save")
4856 // Check if saving a PDF file
4857 OUString aMimeType
= lcl_getCurrentDocumentMimeType(pDocument
);
4858 if (pDocSh
&& pDocSh
->IsModified() && aMimeType
== "application/pdf")
4860 // If we have a PDF file (for saving annotations for example), we need
4861 // to run save-as to the same file as the opened document. Plain save
4862 // doesn't work as the PDF is not a "native" format.
4863 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
4864 OUString aURL
= xStorable
->getLocation();
4865 OString aURLUtf8
= OUStringToOString(aURL
, RTL_TEXTENCODING_UTF8
);
4866 bool bResult
= doc_saveAs(pThis
, aURLUtf8
.getStr(), "pdf", nullptr);
4868 // Send the result of save
4869 tools::JsonWriter aJson
;
4870 aJson
.put("commandName", pCommand
);
4871 aJson
.put("success", bResult
);
4872 pDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aJson
.finishAndGetAsOString());
4877 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
4878 new LOKInteractionHandler("save", gImpl
, pDocument
));
4879 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
);
4881 beans::PropertyValue aValue
;
4882 aValue
.Name
= "InteractionHandler";
4883 aValue
.Value
<<= xInteraction
;
4884 aPropertyValuesVector
.push_back(aValue
);
4886 bool bDontSaveIfUnmodified
= false;
4887 aPropertyValuesVector
.erase(std::remove_if(aPropertyValuesVector
.begin(),
4888 aPropertyValuesVector
.end(),
4889 [&bDontSaveIfUnmodified
](const beans::PropertyValue
& aItem
){
4890 if (aItem
.Name
== "DontSaveIfUnmodified")
4892 bDontSaveIfUnmodified
= aItem
.Value
.get
<bool>();
4896 }), aPropertyValuesVector
.end());
4898 // skip saving and tell the result via UNO_COMMAND_RESULT
4899 if (bDontSaveIfUnmodified
&& (!pDocSh
|| !pDocSh
->IsModified()))
4901 tools::JsonWriter aJson
;
4902 aJson
.put("commandName", pCommand
);
4903 aJson
.put("success", false);
4904 // Add the reason for not saving
4906 auto resultNode
= aJson
.startNode("result");
4907 aJson
.put("type", "string");
4908 aJson
.put("value", "unmodified");
4910 pDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aJson
.finishAndGetAsOString());
4914 else if (gImpl
&& aCommand
== ".uno:TransformDialog")
4916 bool bNeedConversion
= false;
4917 SfxViewShell
* pViewShell
= SfxViewShell::Current();
4918 LokChartHelper
aChartHelper(pViewShell
);
4920 if (aChartHelper
.GetWindow() )
4922 bNeedConversion
= true;
4924 else if (const SdrView
* pView
= pViewShell
->GetDrawView())
4926 if (OutputDevice
* pOutputDevice
= pView
->GetFirstOutputDevice())
4928 bNeedConversion
= (pOutputDevice
->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
);
4932 if (bNeedConversion
)
4935 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
4937 if (rPropValue
.Name
== "TransformPosX"
4938 || rPropValue
.Name
== "TransformPosY"
4939 || rPropValue
.Name
== "TransformWidth"
4940 || rPropValue
.Name
== "TransformHeight"
4941 || rPropValue
.Name
== "TransformRotationX"
4942 || rPropValue
.Name
== "TransformRotationY")
4944 rPropValue
.Value
>>= value
;
4945 value
= o3tl::convert(value
, o3tl::Length::twip
, o3tl::Length::mm100
);
4946 rPropValue
.Value
<<= value
;
4951 if (aChartHelper
.GetWindow() && aPropertyValuesVector
.size() > 0)
4953 if (aPropertyValuesVector
[0].Name
!= "Action")
4955 tools::Rectangle aChartBB
= aChartHelper
.GetChartBoundingBox();
4957 int nLeft
= o3tl::convert(aChartBB
.Left(), o3tl::Length::twip
, o3tl::Length::mm100
);
4958 int nTop
= o3tl::convert(aChartBB
.Top(), o3tl::Length::twip
, o3tl::Length::mm100
);
4960 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
4962 if (rPropValue
.Name
== "TransformPosX" || rPropValue
.Name
== "TransformRotationX")
4964 auto const value
= *o3tl::doAccess
<sal_Int32
>(rPropValue
.Value
);
4965 rPropValue
.Value
<<= value
- nLeft
;
4967 else if (rPropValue
.Name
== "TransformPosY" || rPropValue
.Name
== "TransformRotationY")
4969 auto const value
= *o3tl::doAccess
<sal_Int32
>(rPropValue
.Value
);
4970 rPropValue
.Value
<<= value
- nTop
;
4974 util::URL aCommandURL
;
4975 aCommandURL
.Path
= "LOKTransform";
4976 css::uno::Reference
<css::frame::XDispatch
>& aChartDispatcher
= aChartHelper
.GetXDispatcher();
4977 aChartDispatcher
->dispatch(aCommandURL
, comphelper::containerToSequence(aPropertyValuesVector
));
4981 else if (gImpl
&& aCommand
== ".uno:LOKSidebarWriterPage")
4983 setupSidebar(u
"WriterPageDeck");
4986 else if (gImpl
&& aCommand
== ".uno:SidebarShow")
4991 else if (gImpl
&& aCommand
== ".uno:SidebarHide")
4997 bool bResult
= false;
4998 LokChartHelper
aChartHelper(SfxViewShell::Current());
5000 if (aChartHelper
.GetWindow() && aCommand
!= ".uno:Save" )
5002 util::URL aCommandURL
;
5003 aCommandURL
.Path
= aCommand
.copy(5);
5004 css::uno::Reference
<css::frame::XDispatch
>& aChartDispatcher
= aChartHelper
.GetXDispatcher();
5005 aChartDispatcher
->dispatch(aCommandURL
, comphelper::containerToSequence(aPropertyValuesVector
));
5008 if (LokStarMathHelper
aMathHelper(SfxViewShell::Current());
5009 aMathHelper
.GetGraphicWindow() && aCommand
!= ".uno:Save")
5011 aMathHelper
.Dispatch(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
));
5014 if (bNotifyWhenFinished
&& pDocument
->mpCallbackFlushHandlers
.count(nView
))
5016 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
),
5017 new DispatchResultListener(pCommand
, pDocument
->mpCallbackFlushHandlers
[nView
]));
5020 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
));
5024 SetLastExceptionMsg("Failed to dispatch " + aCommand
);
5028 static void doc_postMouseEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
5030 comphelper::ProfileZone
aZone("doc_postMouseEvent");
5032 SolarMutexGuard aGuard
;
5033 SetLastExceptionMsg();
5035 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5038 SetLastExceptionMsg("Document doesn't support tiled rendering");
5043 pDoc
->postMouseEvent(nType
, nX
, nY
, nCount
, nButtons
, nModifier
);
5045 catch (const uno::Exception
& exception
)
5047 SetLastExceptionMsg(exception
.Message
);
5048 SAL_INFO("lok", "Failed to postMouseEvent " << exception
.Message
);
5052 static void doc_postWindowMouseEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
5054 comphelper::ProfileZone
aZone("doc_postWindowMouseEvent");
5056 SolarMutexGuard aGuard
;
5057 SetLastExceptionMsg();
5059 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5062 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5066 const Point
aPos(nX
, nY
);
5068 MouseEvent
aEvent(aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
, nButtons
, nModifier
);
5070 vcl::EnableDialogInput(pWindow
);
5074 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN
:
5075 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown
, pWindow
, &aEvent
);
5077 case LOK_MOUSEEVENT_MOUSEBUTTONUP
:
5078 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp
, pWindow
, &aEvent
);
5080 case LOK_MOUSEEVENT_MOUSEMOVE
:
5081 Application::PostMouseEvent(VclEventId::WindowMouseMove
, pWindow
, &aEvent
);
5089 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, const char* pType
, int nX
, int nY
, int nOffset
)
5091 comphelper::ProfileZone
aZone("doc_postWindowGestureEvent");
5093 SolarMutexGuard aGuard
;
5094 SetLastExceptionMsg();
5096 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5099 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5103 OString
aType(pType
);
5104 GestureEventPanType eEventType
= GestureEventPanType::Update
;
5106 if (aType
== "panBegin")
5107 eEventType
= GestureEventPanType::Begin
;
5108 else if (aType
== "panEnd")
5109 eEventType
= GestureEventPanType::End
;
5111 GestureEventPan aEvent
{
5116 PanningOrientation::Vertical
,
5119 vcl::EnableDialogInput(pWindow
);
5121 Application::PostGestureEvent(VclEventId::WindowGestureEvent
, pWindow
, &aEvent
);
5124 static void doc_setTextSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
5126 comphelper::ProfileZone
aZone("doc_setTextSelection");
5128 SolarMutexGuard aGuard
;
5129 SetLastExceptionMsg();
5131 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5134 SetLastExceptionMsg("Document doesn't support tiled rendering");
5138 pDoc
->setTextSelection(nType
, nX
, nY
);
5141 static void doc_setWindowTextSelection(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, bool swap
, int nX
, int nY
)
5143 comphelper::ProfileZone
aZone("doc_setWindowTextSelection");
5145 SolarMutexGuard aGuard
;
5146 SetLastExceptionMsg();
5148 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5151 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5156 Size
aOffset(pWindow
->GetOutOffXPixel(), pWindow
->GetOutOffYPixel());
5157 Point
aCursorPos(nX
, nY
);
5158 aCursorPos
.Move(aOffset
);
5159 sal_uInt16 nModifier
= swap
? KEY_MOD1
+ KEY_MOD2
: KEY_SHIFT
;
5161 MouseEvent
aCursorEvent(aCursorPos
, 1, MouseEventModifiers::SIMPLECLICK
, 0, nModifier
);
5162 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown
, pWindow
, &aCursorEvent
);
5163 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp
, pWindow
, &aCursorEvent
);
5166 static bool getFromTransferable(
5167 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
5168 const OString
&aInMimeType
, OString
&aRet
);
5170 static bool encodeImageAsHTML(
5171 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
5172 const OString
&aMimeType
, OString
&aRet
)
5174 if (!getFromTransferable(xTransferable
, aMimeType
, aRet
))
5177 // Encode in base64.
5178 auto aSeq
= Sequence
<sal_Int8
>(reinterpret_cast<const sal_Int8
*>(aRet
.getStr()),
5180 OStringBuffer aBase64Data
;
5181 comphelper::Base64::encode(aBase64Data
, aSeq
);
5184 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
5186 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
5187 "name=\"generator\" content=\""
5188 + getGenerator().toUtf8()
5190 "</head><body><img src=\"data:" + aMimeType
+ ";base64,"
5191 + aBase64Data
+ "\"/></body></html>";
5196 static bool encodeTextAsHTML(
5197 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
5198 const OString
&aMimeType
, OString
&aRet
)
5200 if (!getFromTransferable(xTransferable
, aMimeType
, aRet
))
5203 // Embed in HTML - FIXME: needs some escaping.
5204 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
5206 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
5207 "name=\"generator\" content=\""
5208 + getGenerator().toUtf8()
5209 + "\"/></head><body><pre>" + aRet
+ "</pre></body></html>";
5214 static bool getFromTransferable(
5215 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
5216 const OString
&aInMimeType
, OString
&aRet
)
5218 OString
aMimeType(aInMimeType
);
5220 // Take care of UTF-8 text here.
5221 bool bConvert
= false;
5222 sal_Int32 nIndex
= 0;
5223 if (o3tl::getToken(aMimeType
, 0, ';', nIndex
) == "text/plain")
5225 if (o3tl::getToken(aMimeType
, 0, ';', nIndex
) == "charset=utf-8")
5227 aMimeType
= "text/plain;charset=utf-16";
5232 datatransfer::DataFlavor aFlavor
;
5233 aFlavor
.MimeType
= OUString::fromUtf8(aMimeType
);
5234 if (aMimeType
== "text/plain;charset=utf-16")
5235 aFlavor
.DataType
= cppu::UnoType
<OUString
>::get();
5237 aFlavor
.DataType
= cppu::UnoType
< uno::Sequence
<sal_Int8
> >::get();
5239 if (!xTransferable
->isDataFlavorSupported(aFlavor
))
5241 // Try harder for HTML it is our copy/paste meta-file format
5242 if (aInMimeType
== "text/html")
5244 // Desperate measures - convert text to HTML instead.
5245 if (encodeTextAsHTML(xTransferable
, "text/plain;charset=utf-8", aRet
))
5247 // If html is not supported, might be a graphic-selection,
5248 if (encodeImageAsHTML(xTransferable
, "image/png", aRet
))
5252 SetLastExceptionMsg("Flavor " + aFlavor
.MimeType
+ " is not supported");
5259 aAny
= xTransferable
->getTransferData(aFlavor
);
5261 catch (const css::datatransfer::UnsupportedFlavorException
& e
)
5263 SetLastExceptionMsg("Unsupported flavor " + aFlavor
.MimeType
+ " exception " + e
.Message
);
5266 catch (const css::uno::Exception
& e
)
5268 SetLastExceptionMsg("Exception getting " + aFlavor
.MimeType
+ " exception " + e
.Message
);
5272 if (aFlavor
.DataType
== cppu::UnoType
<OUString
>::get())
5277 aRet
= OUStringToOString(aString
, RTL_TEXTENCODING_UTF8
);
5279 aRet
= OString(reinterpret_cast<const char *>(aString
.getStr()), aString
.getLength() * sizeof(sal_Unicode
));
5283 uno::Sequence
<sal_Int8
> aSequence
;
5285 aRet
= OString(reinterpret_cast<const char*>(aSequence
.getConstArray()), aSequence
.getLength());
5291 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, char** pUsedMimeType
)
5293 comphelper::ProfileZone
aZone("doc_getTextSelection");
5295 SolarMutexGuard aGuard
;
5296 SetLastExceptionMsg();
5298 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5301 SetLastExceptionMsg("Document doesn't support tiled rendering");
5305 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= pDoc
->getSelection();
5308 SetLastExceptionMsg("No selection available");
5312 const char *pType
= pMimeType
;
5313 if (!pType
|| pType
[0] == '\0')
5314 pType
= "text/plain;charset=utf-8";
5317 bool bSuccess
= getFromTransferable(xTransferable
, OString(pType
), aRet
);
5321 if (pUsedMimeType
) // legacy
5324 *pUsedMimeType
= strdup(pMimeType
);
5326 *pUsedMimeType
= nullptr;
5329 return convertOString(aRet
);
5332 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
)
5334 comphelper::ProfileZone
aZone("doc_getSelectionType");
5336 SolarMutexGuard aGuard
;
5337 SetLastExceptionMsg();
5339 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5342 SetLastExceptionMsg("Document doesn't support tiled rendering");
5343 return LOK_SELTYPE_NONE
;
5346 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= pDoc
->getSelection();
5349 SetLastExceptionMsg("No selection available");
5350 return LOK_SELTYPE_NONE
;
5353 css::uno::Reference
<css::datatransfer::XTransferable2
> xTransferable2(xTransferable
, css::uno::UNO_QUERY
);
5354 if (xTransferable2
.is() && xTransferable2
->isComplex())
5355 return LOK_SELTYPE_COMPLEX
;
5358 bool bSuccess
= getFromTransferable(xTransferable
, "text/plain;charset=utf-8", aRet
);
5360 return LOK_SELTYPE_NONE
;
5362 if (aRet
.getLength() > 10000)
5363 return LOK_SELTYPE_COMPLEX
;
5365 return !aRet
.isEmpty() ? LOK_SELTYPE_TEXT
: LOK_SELTYPE_NONE
;
5368 static int doc_getSelectionTypeAndText(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, char** pText
, char** pUsedMimeType
)
5370 // The purpose of this function is to avoid double call to pDoc->getSelection(),
5371 // which may be expensive.
5372 comphelper::ProfileZone
aZone("doc_getSelectionTypeAndText");
5374 SolarMutexGuard aGuard
;
5375 SetLastExceptionMsg();
5377 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5380 SetLastExceptionMsg("Document doesn't support tiled rendering");
5381 return LOK_SELTYPE_NONE
;
5384 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= pDoc
->getSelection();
5387 SetLastExceptionMsg("No selection available");
5388 return LOK_SELTYPE_NONE
;
5391 css::uno::Reference
<css::datatransfer::XTransferable2
> xTransferable2(xTransferable
, css::uno::UNO_QUERY
);
5392 if (xTransferable2
.is() && xTransferable2
->isComplex())
5393 return LOK_SELTYPE_COMPLEX
;
5395 const char *pType
= pMimeType
;
5396 if (!pType
|| pType
[0] == '\0')
5397 pType
= "text/plain;charset=utf-8";
5400 bool bSuccess
= getFromTransferable(xTransferable
, OString(pType
), aRet
);
5402 return LOK_SELTYPE_NONE
;
5404 if (aRet
.getLength() > 10000)
5405 return LOK_SELTYPE_COMPLEX
;
5408 return LOK_SELTYPE_NONE
;
5411 *pText
= convertOString(aRet
);
5413 if (pUsedMimeType
) // legacy
5416 *pUsedMimeType
= strdup(pMimeType
);
5418 *pUsedMimeType
= nullptr;
5421 return LOK_SELTYPE_TEXT
;
5424 static int doc_getClipboard(LibreOfficeKitDocument
* pThis
,
5425 const char **pMimeTypes
,
5427 char ***pOutMimeTypes
,
5429 char ***pOutStreams
)
5435 (void) pOutMimeTypes
;
5439 assert(!"doc_getClipboard should not be called on iOS");
5443 comphelper::ProfileZone
aZone("doc_getClipboard");
5445 SolarMutexGuard aGuard
;
5446 SetLastExceptionMsg();
5449 assert (pOutMimeTypes
);
5451 assert (pOutStreams
);
5454 *pOutMimeTypes
= nullptr;
5455 *pOutSizes
= nullptr;
5456 *pOutStreams
= nullptr;
5458 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5461 SetLastExceptionMsg("Document doesn't support tiled rendering");
5465 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
5467 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= xClip
->getContents();
5468 SAL_INFO("lok", "Got from clip: " << xClip
.get() << " transferable: " << xTransferable
);
5471 SetLastExceptionMsg("No clipboard content available");
5475 std::vector
<OString
> aMimeTypes
;
5476 if (!pMimeTypes
) // everything
5478 const uno::Sequence
< css::datatransfer::DataFlavor
> flavors
= xTransferable
->getTransferDataFlavors();
5479 if (!flavors
.getLength())
5481 SetLastExceptionMsg("Flavourless selection");
5484 for (const auto &it
: flavors
)
5485 aMimeTypes
.push_back(OUStringToOString(it
.MimeType
, RTL_TEXTENCODING_UTF8
));
5489 for (size_t i
= 0; pMimeTypes
[i
]; ++i
)
5490 aMimeTypes
.push_back(OString(pMimeTypes
[i
]));
5493 *pOutCount
= aMimeTypes
.size();
5494 *pOutSizes
= static_cast<size_t *>(malloc(*pOutCount
* sizeof(size_t)));
5495 *pOutMimeTypes
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
5496 *pOutStreams
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
5497 for (size_t i
= 0; i
< aMimeTypes
.size(); ++i
)
5499 if (aMimeTypes
[i
] == "text/plain;charset=utf-16")
5500 (*pOutMimeTypes
)[i
] = strdup("text/plain;charset=utf-8");
5502 (*pOutMimeTypes
)[i
] = strdup(aMimeTypes
[i
].getStr());
5505 bool bSuccess
= getFromTransferable(xTransferable
, (*pOutMimeTypes
)[i
], aRet
);
5506 if (!bSuccess
|| aRet
.getLength() < 1)
5508 (*pOutSizes
)[i
] = 0;
5509 (*pOutStreams
)[i
] = nullptr;
5513 (*pOutSizes
)[i
] = aRet
.getLength();
5514 (*pOutStreams
)[i
] = convertOString(aRet
);
5522 static int doc_setClipboard(LibreOfficeKitDocument
* pThis
,
5523 const size_t nInCount
,
5524 const char **pInMimeTypes
,
5525 const size_t *pInSizes
,
5526 const char **pInStreams
)
5531 (void) pInMimeTypes
;
5535 comphelper::ProfileZone
aZone("doc_setClipboard");
5537 SolarMutexGuard aGuard
;
5538 SetLastExceptionMsg();
5540 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5543 SetLastExceptionMsg("Document doesn't support tiled rendering");
5547 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(nInCount
, pInMimeTypes
, pInSizes
, pInStreams
));
5549 auto xClip
= forceSetClipboardForCurrentView(pThis
);
5550 xClip
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
5552 SAL_INFO("lok", "Set clip: " << xClip
.get() << " to: " << xTransferable
);
5554 if (!pDoc
->isMimeTypeSupported())
5556 SetLastExceptionMsg("Document doesn't support this mime type");
5563 static bool doc_paste(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, const char* pData
, size_t nSize
)
5565 comphelper::ProfileZone
aZone("doc_paste");
5567 SolarMutexGuard aGuard
;
5569 const char *pInMimeTypes
[1];
5570 const char *pInStreams
[1];
5572 pInMimeTypes
[0] = pMimeType
;
5573 pInSizes
[0] = nSize
;
5574 pInStreams
[0] = pData
;
5576 if (!doc_setClipboard(pThis
, 1, pInMimeTypes
, pInSizes
, pInStreams
))
5579 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
5581 {"AnchorType", uno::Any(static_cast<sal_uInt16
>(css::text::TextContentAnchorType_AS_CHARACTER
))},
5582 {"IgnoreComments", uno::Any(true)},
5584 if (!comphelper::dispatchCommand(".uno:Paste", aPropertyValues
))
5586 SetLastExceptionMsg("Failed to dispatch the .uno: command");
5593 static void doc_setGraphicSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
5595 comphelper::ProfileZone
aZone("doc_setGraphicSelection");
5597 SolarMutexGuard aGuard
;
5598 SetLastExceptionMsg();
5600 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5603 SetLastExceptionMsg("Document doesn't support tiled rendering");
5607 pDoc
->setGraphicSelection(nType
, nX
, nY
);
5610 static void getDocLanguages(LibreOfficeKitDocument
* pThis
, uno::Sequence
<lang::Locale
>& rSeq
)
5612 SfxViewFrame
* pViewFrame
= SfxViewFrame::Current();
5616 SfxDispatcher
* pDispatcher
= pViewFrame
->GetBindings().GetDispatcher();
5620 css::uno::Any aLangStatus
;
5621 pDispatcher
->QueryState(SID_LANGUAGE_STATUS
, aLangStatus
);
5625 OUString sGuessText
;
5626 SvtScriptType eScriptType
= SvtScriptType::LATIN
| SvtScriptType::ASIAN
5627 | SvtScriptType::COMPLEX
;
5629 Sequence
<OUString
> aSeqLang
;
5630 if (aLangStatus
>>= aSeqLang
)
5632 if (aSeqLang
.getLength() == 4)
5634 sCurrent
= aSeqLang
[0];
5635 eScriptType
= static_cast<SvtScriptType
>(aSeqLang
[1].toInt32());
5636 sKeyboard
= aSeqLang
[1];
5637 sGuessText
= aSeqLang
[2];
5642 aLangStatus
>>= sCurrent
;
5645 LanguageType nLangType
;
5646 std::set
<LanguageType
> aLangItems
;
5648 if (!sCurrent
.isEmpty())
5650 nLangType
= SvtLanguageTable::GetLanguageType(sCurrent
);
5651 if (nLangType
!= LANGUAGE_DONTKNOW
)
5653 aLangItems
.insert(nLangType
);
5657 const AllSettings
& rAllSettings
= Application::GetSettings();
5658 nLangType
= rAllSettings
.GetLanguageTag().getLanguageType();
5659 if (nLangType
!= LANGUAGE_DONTKNOW
&&
5660 (eScriptType
& SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
)))
5662 aLangItems
.insert(nLangType
);
5665 nLangType
= rAllSettings
.GetUILanguageTag().getLanguageType();
5666 if (nLangType
!= LANGUAGE_DONTKNOW
&&
5667 (eScriptType
& SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
)))
5669 aLangItems
.insert(nLangType
);
5672 if (!sKeyboard
.isEmpty())
5674 nLangType
= SvtLanguageTable::GetLanguageType(sKeyboard
);
5675 if (nLangType
!= LANGUAGE_DONTKNOW
&&
5676 (eScriptType
& SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
)))
5678 aLangItems
.insert(nLangType
);
5682 if (!sGuessText
.isEmpty())
5684 Reference
<linguistic2::XLanguageGuessing
> xLangGuesser
;
5687 xLangGuesser
= linguistic2::LanguageGuessing::create(xContext
);
5693 if (xLangGuesser
.is())
5695 lang::Locale aLocale
= xLangGuesser
->guessPrimaryLanguage(sGuessText
, 0,
5696 sGuessText
.getLength());
5697 LanguageTag
aLanguageTag(aLocale
);
5698 nLangType
= aLanguageTag
.getLanguageType(false);
5699 if (nLangType
!= LANGUAGE_DONTKNOW
&&
5700 (eScriptType
& SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
)))
5702 aLangItems
.insert(nLangType
);
5707 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5708 Reference
<document::XDocumentLanguages
> xDocumentLanguages(pDocument
->mxComponent
, UNO_QUERY
);
5709 if (xDocumentLanguages
.is())
5711 const Sequence
<lang::Locale
> aLocales(xDocumentLanguages
->getDocumentLanguages(
5712 static_cast<sal_Int16
>(eScriptType
), 64));
5714 for (const lang::Locale
& aLocale
: aLocales
)
5716 nLangType
= SvtLanguageTable::GetLanguageType(aLocale
.Language
);
5717 if (nLangType
!= LANGUAGE_DONTKNOW
&&
5718 (eScriptType
& SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
)))
5720 aLangItems
.insert(nLangType
);
5726 Sequence
<lang::Locale
> aLocales(aLangItems
.size());
5727 auto pLocales
= aLocales
.getArray();
5728 for (const LanguageType
& itLang
: aLangItems
)
5730 pLocales
[nLocale
++] = LanguageTag::convertToLocale(itLang
);
5736 static void doc_resetSelection(LibreOfficeKitDocument
* pThis
)
5738 comphelper::ProfileZone
aZone("doc_resetSelection");
5740 SolarMutexGuard aGuard
;
5741 SetLastExceptionMsg();
5743 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5746 SetLastExceptionMsg("Document doesn't support tiled rendering");
5750 pDoc
->resetSelection();
5753 static char* getLanguages(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
5755 css::uno::Sequence
< css::lang::Locale
> aLocales
;
5759 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
5762 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
5764 aLocales
= xSpell
->getLocales();
5767 /* FIXME: To obtain the document languages the spell checker can be disabled,
5768 so a future re-work of the getLanguages function is needed in favor to use
5770 if (!aLocales
.hasElements())
5772 uno::Sequence
< css::lang::Locale
> aSeq
;
5773 getDocLanguages(pThis
, aSeq
);
5778 boost::property_tree::ptree aTree
;
5779 aTree
.put("commandName", pCommand
);
5780 boost::property_tree::ptree aValues
;
5781 boost::property_tree::ptree aChild
;
5783 for ( css::lang::Locale
const & locale
: std::as_const(aLocales
) )
5785 const LanguageTag
aLanguageTag( locale
);
5786 sLanguage
= SvtLanguageTable::GetLanguageString(aLanguageTag
.getLanguageType());
5787 if (sLanguage
.startsWith("{") && sLanguage
.endsWith("}"))
5790 sLanguage
+= ";" + aLanguageTag
.getBcp47(false);
5791 aChild
.put("", sLanguage
.toUtf8());
5792 aValues
.push_back(std::make_pair("", aChild
));
5794 aTree
.add_child("commandValues", aValues
);
5795 std::stringstream aStream
;
5796 boost::property_tree::write_json(aStream
, aTree
);
5797 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
5798 assert(pJson
); // Don't handle OOM conditions
5799 strcpy(pJson
, aStream
.str().c_str());
5800 pJson
[aStream
.str().size()] = '\0';
5804 static char* getFonts (const char* pCommand
)
5806 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
5809 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
5810 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
5811 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
5813 boost::property_tree::ptree aTree
;
5814 aTree
.put("commandName", pCommand
);
5815 boost::property_tree::ptree aValues
;
5818 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
5819 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
5821 boost::property_tree::ptree aChildren
;
5822 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
5823 const int* pAry
= FontList::GetStdSizeAry();
5824 sal_uInt16 nSizeCount
= 0;
5825 while (pAry
[nSizeCount
])
5827 boost::property_tree::ptree aChild
;
5828 aChild
.put("", static_cast<float>(pAry
[nSizeCount
]) / 10);
5829 aChildren
.push_back(std::make_pair("", aChild
));
5832 aValues
.add_child(rFontMetric
.GetFamilyName().toUtf8().getStr(), aChildren
);
5835 aTree
.add_child("commandValues", aValues
);
5836 std::stringstream aStream
;
5837 boost::property_tree::write_json(aStream
, aTree
);
5838 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
5839 assert(pJson
); // Don't handle OOM conditions
5840 strcpy(pJson
, aStream
.str().c_str());
5841 pJson
[aStream
.str().size()] = '\0';
5845 static char* getFontSubset (std::string_view aFontName
)
5847 OUString
aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName
, RTL_TEXTENCODING_UTF8
), rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
));
5849 boost::property_tree::ptree aTree
;
5850 aTree
.put("commandName", ".uno:FontSubset");
5851 boost::property_tree::ptree aValues
;
5853 if (const vcl::Font
* pFont
= FindFont(aFoundFont
))
5855 FontCharMapRef
xFontCharMap (new FontCharMap());
5856 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
));
5858 aDevice
->SetFont(*pFont
);
5859 aDevice
->GetFontCharMap(xFontCharMap
);
5860 SubsetMap
aSubMap(xFontCharMap
);
5862 for (auto const& subset
: aSubMap
.GetSubsetMap())
5864 boost::property_tree::ptree aChild
;
5865 aChild
.put("", static_cast<int>(ublock_getCode(subset
.GetRangeMin())));
5866 aValues
.push_back(std::make_pair("", aChild
));
5870 aTree
.add_child("commandValues", aValues
);
5871 std::stringstream aStream
;
5872 boost::property_tree::write_json(aStream
, aTree
);
5873 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
5874 assert(pJson
); // Don't handle OOM conditions
5875 strcpy(pJson
, aStream
.str().c_str());
5876 pJson
[aStream
.str().size()] = '\0';
5880 static char* getStyles(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
5882 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5884 boost::property_tree::ptree aTree
;
5885 aTree
.put("commandName", pCommand
);
5886 uno::Reference
<css::style::XStyleFamiliesSupplier
> xStyleFamiliesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
5887 const uno::Reference
<container::XNameAccess
> xStyleFamilies
= xStyleFamiliesSupplier
->getStyleFamilies();
5888 const uno::Sequence
<OUString
> aStyleFamilies
= xStyleFamilies
->getElementNames();
5890 static const std::vector
<OUString
> aWriterStyles
=
5901 // We need to keep a list of the default style names
5902 // in order to filter these out later when processing
5903 // the full list of styles.
5904 std::set
<OUString
> aDefaultStyleNames
;
5906 boost::property_tree::ptree aValues
;
5907 for (OUString
const & sStyleFam
: aStyleFamilies
)
5909 boost::property_tree::ptree aChildren
;
5910 uno::Reference
<container::XNameAccess
> xStyleFamily(xStyleFamilies
->getByName(sStyleFam
), uno::UNO_QUERY
);
5912 // Writer provides a huge number of styles, we have a list of 7 "default" styles which
5913 // should be shown in the normal dropdown, which we should add to the start of the list
5914 // to simplify their selection.
5915 if (sStyleFam
== "ParagraphStyles"
5916 && doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
)
5918 for (const OUString
& rStyle
: aWriterStyles
)
5920 aDefaultStyleNames
.insert( rStyle
);
5922 boost::property_tree::ptree aChild
;
5923 aChild
.put("", rStyle
.toUtf8());
5924 aChildren
.push_back(std::make_pair("", aChild
));
5928 const uno::Sequence
<OUString
> aStyles
= xStyleFamily
->getElementNames();
5929 for (const OUString
& rStyle
: aStyles
)
5931 // Filter out the default styles - they are already at the top
5933 if (aDefaultStyleNames
.find(rStyle
) == aDefaultStyleNames
.end() ||
5934 (sStyleFam
!= "ParagraphStyles" || doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
) )
5936 boost::property_tree::ptree aChild
;
5937 aChild
.put("", rStyle
.toUtf8());
5938 aChildren
.push_back(std::make_pair("", aChild
));
5941 aValues
.add_child(sStyleFam
.toUtf8().getStr(), aChildren
);
5944 // Header & Footer Styles
5946 boost::property_tree::ptree aChild
;
5947 boost::property_tree::ptree aChildren
;
5948 static const OUStringLiteral
sPageStyles(u
"PageStyles");
5949 uno::Reference
<beans::XPropertySet
> xProperty
;
5950 uno::Reference
<container::XNameContainer
> xContainer
;
5952 if (xStyleFamilies
->hasByName(sPageStyles
) && (xStyleFamilies
->getByName(sPageStyles
) >>= xContainer
))
5954 const uno::Sequence
<OUString
> aSeqNames
= xContainer
->getElementNames();
5955 for (OUString
const & sName
: aSeqNames
)
5958 xProperty
.set(xContainer
->getByName(sName
), uno::UNO_QUERY
);
5959 if (xProperty
.is() && (xProperty
->getPropertyValue("IsPhysical") >>= bIsPhysical
) && bIsPhysical
)
5961 OUString displayName
;
5962 xProperty
->getPropertyValue("DisplayName") >>= displayName
;
5963 aChild
.put("", displayName
.toUtf8());
5964 aChildren
.push_back(std::make_pair("", aChild
));
5967 aValues
.add_child("HeaderFooter", aChildren
);
5972 boost::property_tree::ptree aCommandList
;
5975 boost::property_tree::ptree aChild
;
5977 OUString sClearFormat
= SvxResId(RID_SVXSTR_CLEARFORM
);
5979 boost::property_tree::ptree aName
;
5980 aName
.put("", sClearFormat
.toUtf8());
5981 aChild
.push_back(std::make_pair("text", aName
));
5983 boost::property_tree::ptree aCommand
;
5984 aCommand
.put("", ".uno:ResetAttributes");
5985 aChild
.push_back(std::make_pair("id", aCommand
));
5987 aCommandList
.push_back(std::make_pair("", aChild
));
5990 aValues
.add_child("Commands", aCommandList
);
5993 aTree
.add_child("commandValues", aValues
);
5994 std::stringstream aStream
;
5995 boost::property_tree::write_json(aStream
, aTree
);
5996 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
5997 assert(pJson
); // Don't handle OOM conditions
5998 strcpy(pJson
, aStream
.str().c_str());
5999 pJson
[aStream
.str().size()] = '\0';
6005 enum class UndoOrRedo
6013 /// Returns the JSON representation of either an undo or a redo stack.
6014 static char* getUndoOrRedo(LibreOfficeKitDocument
* pThis
, UndoOrRedo eCommand
)
6016 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6018 auto pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
6022 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
6026 SfxUndoManager
* pUndoManager
= pObjectShell
->GetUndoManager();
6031 if (eCommand
== UndoOrRedo::UNDO
)
6032 aString
= pUndoManager
->GetUndoActionsInfo();
6034 aString
= pUndoManager
->GetRedoActionsInfo();
6035 char* pJson
= strdup(aString
.toUtf8().getStr());
6039 /// Returns the JSON representation of the redline stack.
6040 static char* getTrackedChanges(LibreOfficeKitDocument
* pThis
)
6042 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6044 uno::Reference
<document::XRedlinesSupplier
> xRedlinesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
6045 tools::JsonWriter aJson
;
6046 // We want positions of the track changes also which is not possible from
6047 // UNO. Enable positioning information for text documents only for now, so
6048 // construct the tracked changes JSON from inside the sw/, not here using UNO
6049 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
&& xRedlinesSupplier
.is())
6051 auto redlinesNode
= aJson
.startArray("redlines");
6052 uno::Reference
<container::XEnumeration
> xRedlines
= xRedlinesSupplier
->getRedlines()->createEnumeration();
6053 for (size_t nIndex
= 0; xRedlines
->hasMoreElements(); ++nIndex
)
6055 uno::Reference
<beans::XPropertySet
> xRedline(xRedlines
->nextElement(), uno::UNO_QUERY
);
6056 auto redlineNode
= aJson
.startStruct();
6057 aJson
.put("index", static_cast<sal_Int32
>(nIndex
));
6060 xRedline
->getPropertyValue("RedlineAuthor") >>= sAuthor
;
6061 aJson
.put("author", sAuthor
);
6064 xRedline
->getPropertyValue("RedlineType") >>= sType
;
6065 aJson
.put("type", sType
);
6068 xRedline
->getPropertyValue("RedlineComment") >>= sComment
;
6069 aJson
.put("comment", sComment
);
6071 OUString sDescription
;
6072 xRedline
->getPropertyValue("RedlineDescription") >>= sDescription
;
6073 aJson
.put("description", sDescription
);
6075 util::DateTime aDateTime
;
6076 xRedline
->getPropertyValue("RedlineDateTime") >>= aDateTime
;
6077 OUString sDateTime
= utl::toISO8601(aDateTime
);
6078 aJson
.put("dateTime", sDateTime
);
6083 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6086 SetLastExceptionMsg("Document doesn't support tiled rendering");
6089 pDoc
->getTrackedChanges(aJson
);
6092 return strdup(aJson
.finishAndGetAsOString().getStr());
6096 /// Returns the JSON representation of the redline author table.
6097 static char* getTrackedChangeAuthors(LibreOfficeKitDocument
* pThis
)
6099 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6102 SetLastExceptionMsg("Document doesn't support tiled rendering");
6105 tools::JsonWriter aJsonWriter
;
6106 pDoc
->getTrackedChangeAuthors(aJsonWriter
);
6107 return strdup(aJsonWriter
.finishAndGetAsOString().getStr());
6110 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
6112 comphelper::ProfileZone
aZone("doc_getCommandValues");
6114 SolarMutexGuard aGuard
;
6115 SetLastExceptionMsg();
6117 const std::string_view
aCommand(pCommand
);
6118 static constexpr OStringLiteral
aViewRowColumnHeaders(".uno:ViewRowColumnHeaders");
6119 static constexpr OStringLiteral
aSheetGeometryData(".uno:SheetGeometryData");
6120 static constexpr OStringLiteral
aCellCursor(".uno:CellCursor");
6121 static constexpr OStringLiteral
aFontSubset(".uno:FontSubset&name=");
6123 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6126 SetLastExceptionMsg("Document doesn't support tiled rendering");
6130 if (!strcmp(pCommand
, ".uno:LanguageStatus"))
6132 return getLanguages(pThis
, pCommand
);
6134 else if (!strcmp(pCommand
, ".uno:CharFontName"))
6136 return getFonts(pCommand
);
6138 else if (!strcmp(pCommand
, ".uno:StyleApply"))
6140 return getStyles(pThis
, pCommand
);
6142 else if (aCommand
== ".uno:Undo")
6144 return getUndoOrRedo(pThis
, UndoOrRedo::UNDO
);
6146 else if (aCommand
== ".uno:Redo")
6148 return getUndoOrRedo(pThis
, UndoOrRedo::REDO
);
6150 else if (aCommand
== ".uno:AcceptTrackedChanges")
6152 return getTrackedChanges(pThis
);
6154 else if (aCommand
== ".uno:TrackedChangeAuthors")
6156 return getTrackedChangeAuthors(pThis
);
6158 else if (aCommand
== ".uno:ViewAnnotations")
6160 return getPostIts(pThis
);
6162 else if (aCommand
== ".uno:ViewAnnotationsPosition")
6164 return getPostItsPos(pThis
);
6166 else if (aCommand
== ".uno:RulerState")
6168 return getRulerState(pThis
);
6170 else if (o3tl::starts_with(aCommand
, aViewRowColumnHeaders
))
6172 tools::Rectangle aRectangle
;
6173 if (aCommand
.size() > o3tl::make_unsigned(aViewRowColumnHeaders
.getLength()))
6175 // Command has parameters.
6180 std::string_view aArguments
= aCommand
.substr(aViewRowColumnHeaders
.getLength() + 1);
6181 sal_Int32 nParamIndex
= 0;
6184 std::string_view aParamToken
= o3tl::getToken(aArguments
, 0, '&', nParamIndex
);
6185 sal_Int32 nIndex
= 0;
6186 std::string_view aKey
;
6187 std::string_view aValue
;
6190 std::string_view aToken
= o3tl::getToken(aParamToken
, 0, '=', nIndex
);
6196 while (nIndex
>= 0);
6198 nX
= o3tl::toInt32(aValue
);
6199 else if (aKey
== "y")
6200 nY
= o3tl::toInt32(aValue
);
6201 else if (aKey
== "width")
6202 nWidth
= o3tl::toInt32(aValue
);
6203 else if (aKey
== "height")
6204 nHeight
= o3tl::toInt32(aValue
);
6206 while (nParamIndex
>= 0);
6208 aRectangle
= tools::Rectangle(nX
, nY
, nX
+ nWidth
, nY
+ nHeight
);
6211 tools::JsonWriter aJsonWriter
;
6212 pDoc
->getRowColumnHeaders(aRectangle
, aJsonWriter
);
6213 return strdup(aJsonWriter
.finishAndGetAsOString().getStr());
6215 else if (o3tl::starts_with(aCommand
, aSheetGeometryData
))
6217 bool bColumns
= true;
6220 bool bHidden
= true;
6221 bool bFiltered
= true;
6222 bool bGroups
= true;
6223 if (aCommand
.size() > o3tl::make_unsigned(aSheetGeometryData
.getLength()))
6225 bColumns
= bRows
= bSizes
= bHidden
= bFiltered
= bGroups
= false;
6227 std::string_view aArguments
= aCommand
.substr(aSheetGeometryData
.getLength() + 1);
6228 sal_Int32 nParamIndex
= 0;
6231 std::string_view aParamToken
= o3tl::getToken(aArguments
, 0, '&', nParamIndex
);
6232 sal_Int32 nIndex
= 0;
6233 std::string_view aKey
;
6234 std::string_view aValue
;
6237 std::string_view aToken
= o3tl::getToken(aParamToken
, 0, '=', nIndex
);
6243 } while (nIndex
>= 0);
6245 bool bEnableFlag
= aValue
.empty() ||
6246 o3tl::equalsIgnoreAsciiCase(aValue
, "true") || o3tl::toInt32(aValue
) > 0;
6250 if (aKey
== "columns")
6252 else if (aKey
== "rows")
6254 else if (aKey
== "sizes")
6256 else if (aKey
== "hidden")
6258 else if (aKey
== "filtered")
6260 else if (aKey
== "groups")
6263 } while (nParamIndex
>= 0);
6266 OString aGeomDataStr
6267 = pDoc
->getSheetGeometryData(bColumns
, bRows
, bSizes
, bHidden
, bFiltered
, bGroups
);
6269 if (aGeomDataStr
.isEmpty())
6272 return convertOString(aGeomDataStr
);
6274 else if (o3tl::starts_with(aCommand
, aCellCursor
))
6276 // Ignore command's deprecated parameters.
6277 tools::JsonWriter aJsonWriter
;
6278 pDoc
->getCellCursor(aJsonWriter
);
6279 return strdup(aJsonWriter
.finishAndGetAsOString().getStr());
6281 else if (o3tl::starts_with(aCommand
, aFontSubset
))
6283 return getFontSubset(aCommand
.substr(aFontSubset
.getLength()));
6285 else if (pDoc
->supportsCommand(INetURLObject(OUString::fromUtf8(aCommand
)).GetURLPath()))
6287 tools::JsonWriter aJsonWriter
;
6288 pDoc
->getCommandValues(aJsonWriter
, aCommand
);
6289 return strdup(aJsonWriter
.finishAndGetAsOString().getStr());
6293 SetLastExceptionMsg("Unknown command, no values returned");
6298 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
, int nTilePixelWidth
, int nTilePixelHeight
,
6299 int nTileTwipWidth
, int nTileTwipHeight
)
6301 comphelper::ProfileZone
aZone("doc_setClientZoom");
6303 SolarMutexGuard aGuard
;
6304 SetLastExceptionMsg();
6306 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6309 SetLastExceptionMsg("Document doesn't support tiled rendering");
6313 pDoc
->setClientZoom(nTilePixelWidth
, nTilePixelHeight
, nTileTwipWidth
, nTileTwipHeight
);
6316 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
)
6318 comphelper::ProfileZone
aZone("doc_setClientVisibleArea");
6320 SolarMutexGuard aGuard
;
6321 SetLastExceptionMsg();
6323 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6326 SetLastExceptionMsg("Document doesn't support tiled rendering");
6330 tools::Rectangle
aRectangle(Point(nX
, nY
), Size(nWidth
, nHeight
));
6331 pDoc
->setClientVisibleArea(aRectangle
);
6334 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
)
6336 comphelper::ProfileZone
aZone("doc_setOutlineState");
6338 SolarMutexGuard aGuard
;
6339 SetLastExceptionMsg();
6341 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6344 SetLastExceptionMsg("Document doesn't support tiled rendering");
6348 pDoc
->setOutlineState(bColumn
, nLevel
, nIndex
, bHidden
);
6351 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
,
6352 const char* pOptions
)
6354 comphelper::ProfileZone
aZone("doc_createView");
6356 SolarMutexGuard aGuard
;
6357 SetLastExceptionMsg();
6359 OUString aOptions
= getUString(pOptions
);
6360 const OUString aLanguage
= extractParameter(aOptions
, u
"Language");
6362 if (!aLanguage
.isEmpty())
6364 // Set the LOK language tag, used for dialog tunneling.
6365 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage
));
6366 comphelper::LibreOfficeKit::setLocale(LanguageTag(aLanguage
));
6369 const OUString aDeviceFormFactor
= extractParameter(aOptions
, u
"DeviceFormFactor");
6370 SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor
);
6372 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6373 const int nId
= SfxLokHelper::createView(pDocument
->mnDocumentId
);
6375 vcl::lok::numberOfViewsChanged(SfxLokHelper::getViewsCount(pDocument
->mnDocumentId
));
6380 forceSetClipboardForCurrentView(pThis
);
6386 static int doc_createView(LibreOfficeKitDocument
* pThis
)
6388 return doc_createViewWithOptions(pThis
, nullptr); // No options.
6391 static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* pThis
, int nId
)
6393 comphelper::ProfileZone
aZone("doc_destroyView");
6395 SolarMutexGuard aGuard
;
6396 SetLastExceptionMsg();
6399 LOKClipboardFactory::releaseClipboardForView(nId
);
6402 SfxLokHelper::destroyView(nId
);
6404 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6405 vcl::lok::numberOfViewsChanged(SfxLokHelper::getViewsCount(pDocument
->mnDocumentId
));
6408 static void doc_setView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
)
6410 comphelper::ProfileZone
aZone("doc_setView");
6412 SolarMutexGuard aGuard
;
6413 SetLastExceptionMsg();
6415 SfxLokHelper::setView(nId
);
6418 static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
6420 comphelper::ProfileZone
aZone("doc_getView");
6422 SolarMutexGuard aGuard
;
6423 SetLastExceptionMsg();
6425 return SfxLokHelper::getView();
6428 static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* pThis
)
6430 comphelper::ProfileZone
aZone("doc_getViewsCount");
6432 SolarMutexGuard aGuard
;
6433 SetLastExceptionMsg();
6435 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6436 return SfxLokHelper::getViewsCount(pDocument
->mnDocumentId
);
6439 static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* pThis
, int* pArray
, size_t nSize
)
6441 comphelper::ProfileZone
aZone("doc_getViewsIds");
6443 SolarMutexGuard aGuard
;
6444 SetLastExceptionMsg();
6446 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6447 return SfxLokHelper::getViewIds(pDocument
->mnDocumentId
, pArray
, nSize
);
6450 static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
, const char* language
)
6452 comphelper::ProfileZone
aZone("doc_setViewLanguage");
6454 SolarMutexGuard aGuard
;
6455 SetLastExceptionMsg();
6457 OUString sLanguage
= OStringToOUString(language
, RTL_TEXTENCODING_UTF8
);
6458 SfxLokHelper::setViewLanguage(nId
, sLanguage
);
6459 SfxLokHelper::setViewLocale(nId
, sLanguage
);
6462 unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
6463 const char* pFontName
,
6468 return doc_renderFontOrientation(pThis
, pFontName
, pChar
, pFontWidth
, pFontHeight
, 0);
6471 unsigned char* doc_renderFontOrientation(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/,
6472 const char* pFontName
,
6478 comphelper::ProfileZone
aZone("doc_renderFont");
6480 SolarMutexGuard aGuard
;
6481 SetLastExceptionMsg();
6483 const int nDefaultFontSize
= 25;
6485 auto aFont
= FindFont_FallbackToDefault(OStringToOUString(pFontName
, RTL_TEXTENCODING_UTF8
));
6487 OUString
aText(OStringToOUString(pChar
, RTL_TEXTENCODING_UTF8
));
6488 if (aText
.isEmpty())
6489 aText
= aFont
.GetFamilyName();
6491 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
));
6492 ::tools::Rectangle aRect
;
6493 aFont
.SetFontSize(Size(0, nDefaultFontSize
));
6494 aFont
.SetOrientation(Degree10(pOrientation
));
6495 aDevice
->SetFont(aFont
);
6496 aDevice
->GetTextBoundRect(aRect
, aText
);
6497 if (aRect
.IsEmpty())
6500 int nFontWidth
= aRect
.Right() + 1;
6501 int nFontHeight
= aRect
.Bottom() + 1;
6503 if (nFontWidth
<= 0 || nFontHeight
<= 0)
6506 if (*pFontWidth
> 0 && *pFontHeight
> 0)
6508 double fScaleX
= *pFontWidth
/ static_cast<double>(nFontWidth
) / 1.5;
6509 double fScaleY
= *pFontHeight
/ static_cast<double>(nFontHeight
) / 1.5;
6511 double fScale
= std::min(fScaleX
, fScaleY
);
6515 int nFontSize
= fScale
* nDefaultFontSize
;
6516 aFont
.SetFontSize(Size(0, nFontSize
));
6517 aDevice
->SetFont(aFont
);
6520 aRect
= tools::Rectangle(0, 0, *pFontWidth
, *pFontHeight
);
6522 nFontWidth
= *pFontWidth
;
6523 nFontHeight
= *pFontHeight
;
6527 unsigned char* pBuffer
= static_cast<unsigned char*>(malloc(4 * nFontWidth
* nFontHeight
));
6531 memset(pBuffer
, 0, nFontWidth
* nFontHeight
* 4);
6532 aDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
6533 aDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(
6534 Size(nFontWidth
, nFontHeight
), Fraction(1.0), Point(),
6537 if (*pFontWidth
> 0 && *pFontHeight
> 0)
6539 DrawTextFlags
const nStyle
=
6540 DrawTextFlags::Center
6541 | DrawTextFlags::VCenter
6542 | DrawTextFlags::MultiLine
6543 | DrawTextFlags::WordBreak
;// | DrawTextFlags::WordBreakHyphenation ;
6545 aDevice
->DrawText(aRect
, aText
, nStyle
);
6549 *pFontWidth
= nFontWidth
;
6550 *pFontHeight
= nFontHeight
;
6552 aDevice
->DrawText(Point(0,0), aText
);
6560 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
6561 unsigned char* pBuffer
,
6562 const int nX
, const int nY
,
6563 const int nWidth
, const int nHeight
)
6565 doc_paintWindowDPI(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, 1.0);
6568 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
6569 unsigned char* pBuffer
,
6570 const int nX
, const int nY
,
6571 const int nWidth
, const int nHeight
,
6572 const double fDPIScale
)
6574 doc_paintWindowForView(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, fDPIScale
, -1);
6577 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
6578 unsigned char* pBuffer
, const int nX
, const int nY
,
6579 const int nWidth
, const int nHeight
,
6580 const double fDPIScale
, int viewId
)
6582 comphelper::ProfileZone
aZone("doc_paintWindowDPI");
6584 SolarMutexGuard aGuard
;
6585 SetLastExceptionMsg();
6587 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
6590 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
6594 // Used to avoid work in setView if set.
6595 comphelper::LibreOfficeKit::setDialogPainting(true);
6598 doc_setView(pThis
, viewId
);
6600 // Setup cairo (or CoreGraphics, in the iOS case) to draw with the changed DPI scale (and return
6601 // back to 1.0 when the painting finishes)
6602 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
6603 comphelper::LibreOfficeKit::setDPIScale(fDPIScale
);
6607 CGContextRef cgc
= CGBitmapContextCreate(pBuffer
, nWidth
, nHeight
, 8, nWidth
*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst
| kCGImageByteOrder32Little
);
6609 CGContextTranslateCTM(cgc
, 0, nHeight
);
6610 CGContextScaleCTM(cgc
, fDPIScale
, -fDPIScale
);
6612 SystemGraphicsData aData
;
6613 aData
.rCGContext
= cgc
;
6615 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::WITHOUT_ALPHA
);
6616 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
6618 pDevice
->SetOutputSizePixel(Size(nWidth
, nHeight
));
6620 MapMode
aMapMode(pDevice
->GetMapMode());
6621 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
6622 pDevice
->SetMapMode(aMapMode
);
6624 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0));
6626 CGContextRelease(cgc
);
6630 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::WITHOUT_ALPHA
);
6631 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
6633 pDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nWidth
, nHeight
), Fraction(1.0), Point(), pBuffer
);
6635 MapMode
aMapMode(pDevice
->GetMapMode());
6636 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
6637 pDevice
->SetMapMode(aMapMode
);
6639 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0));
6642 comphelper::LibreOfficeKit::setDialogPainting(false);
6645 static void doc_postWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nAction
, const char* pData
)
6647 comphelper::ProfileZone
aZone("doc_postWindow");
6649 SolarMutexGuard aGuard
;
6650 SetLastExceptionMsg();
6652 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
6655 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
6659 if (nAction
== LOK_WINDOW_CLOSE
)
6661 vcl::CloseTopLevel(pWindow
);
6663 else if (nAction
== LOK_WINDOW_PASTE
)
6667 css::uno::Sequence
<sal_Int8
> aData
;
6668 std::vector
<beans::PropertyValue
> aArgs(jsonToPropertyValuesVector(pData
));
6670 aArgs
.size() == 2 &&
6671 aArgs
[0].Name
== "MimeType" && (aArgs
[0].Value
>>= aMimeType
) &&
6672 aArgs
[1].Name
== "Data" && (aArgs
[1].Value
>>= aData
);
6675 if (!aMimeType
.isEmpty() && aData
.hasElements())
6677 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(aMimeType
, aData
));
6678 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(new LOKClipboard
);
6679 xClipboard
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
6680 pWindow
->SetClipboard(xClipboard
);
6682 KeyEvent
aEvent(0, KEY_PASTE
, 0);
6683 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
6686 SetLastExceptionMsg("Window command 'paste': wrong parameters.");
6689 assert(!"doc_postWindow() with LOK_WINDOW_PASTE should not be called on iOS");
6694 // CERTIFICATE AND DOCUMENT SIGNING
6695 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
6696 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
,
6697 const unsigned char* pPrivateKeyBinary
, const int nPrivateKeySize
)
6699 comphelper::ProfileZone
aZone("doc_insertCertificate");
6704 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6706 if (!pDocument
->mxComponent
.is())
6709 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
6713 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
6718 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
6719 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
6720 if (!xSecurityContext
.is())
6723 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
6724 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
6726 if (!xCertificateCreator
.is())
6729 uno::Sequence
<sal_Int8
> aCertificateSequence
;
6731 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
6732 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
6733 if (!aCertificateBase64String
.empty())
6735 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
);
6736 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
6740 aCertificateSequence
.realloc(nCertificateBinarySize
);
6741 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.getArray());
6744 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
6745 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeySize
);
6746 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
6747 if (!aPrivateKeyBase64String
.empty())
6749 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
);
6750 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
6754 aPrivateKeySequence
.realloc(nPrivateKeySize
);
6755 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeySize
, aPrivateKeySequence
.getArray());
6758 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
6760 if (!xCertificate
.is())
6763 SolarMutexGuard aGuard
;
6765 return pObjectShell
->SignDocumentContentUsingCertificate(xCertificate
);
6768 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
6769 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
)
6771 comphelper::ProfileZone
aZone("doc_addCertificate");
6776 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6778 if (!pDocument
->mxComponent
.is())
6781 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
6785 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
6790 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
6791 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
6792 if (!xSecurityContext
.is())
6795 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
6796 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
6798 if (!xCertificateCreator
.is())
6801 uno::Sequence
<sal_Int8
> aCertificateSequence
;
6803 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
6804 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
6805 if (!aCertificateBase64String
.empty())
6807 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
);
6808 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
6812 aCertificateSequence
.realloc(nCertificateBinarySize
);
6813 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.getArray());
6816 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->addDERCertificateToTheDatabase(aCertificateSequence
, "TCu,Cu,Tu");
6818 if (!xCertificate
.is())
6821 SAL_INFO("lok", "Certificate Added = IssuerName: " << xCertificate
->getIssuerName() << " SubjectName: " << xCertificate
->getSubjectName());
6826 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
)
6828 comphelper::ProfileZone
aZone("doc_getSignatureState");
6830 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6832 if (!pDocument
->mxComponent
.is())
6833 return int(SignatureState::UNKNOWN
);
6835 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
6837 return int(SignatureState::UNKNOWN
);
6839 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
6841 return int(SignatureState::UNKNOWN
);
6843 SolarMutexGuard aGuard
;
6845 pObjectShell
->RecheckSignature(false);
6847 return int(pObjectShell
->GetDocumentSignatureState());
6850 static void doc_resizeWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
,
6851 const int nWidth
, const int nHeight
)
6853 SolarMutexGuard aGuard
;
6855 gImpl
->maLastExceptionMsg
.clear();
6857 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
6860 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog resizing, or window not found.";
6864 pWindow
->SetSizePixel(Size(nWidth
, nHeight
));
6867 static void doc_completeFunction(LibreOfficeKitDocument
* pThis
, const char* pFunctionName
)
6869 SolarMutexGuard aGuard
;
6870 SetLastExceptionMsg();
6872 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6875 SetLastExceptionMsg("Document doesn't support tiled rendering");
6879 pDoc
->completeFunction(OUString::fromUtf8(pFunctionName
));
6883 static void doc_sendFormFieldEvent(LibreOfficeKitDocument
* pThis
, const char* pArguments
)
6885 SolarMutexGuard aGuard
;
6887 // Supported in Writer only
6888 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
)
6891 StringMap
aMap(jsdialog::jsonToStringMap(pArguments
));
6892 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6895 SetLastExceptionMsg("Document doesn't support tiled rendering!");
6900 if (aMap
.find("type") == aMap
.end() || aMap
.find("cmd") == aMap
.end())
6902 SetLastExceptionMsg("Wrong arguments for sendFormFieldEvent!");
6906 pDoc
->executeFromFieldEvent(aMap
);
6909 static bool doc_renderSearchResult(LibreOfficeKitDocument
* pThis
,
6910 const char* pSearchResult
, unsigned char** pBitmapBuffer
,
6911 int* pWidth
, int* pHeight
, size_t* pByteSize
)
6913 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
)
6916 if (pBitmapBuffer
== nullptr)
6919 if (!pSearchResult
|| pSearchResult
[0] == '\0')
6922 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6925 SetLastExceptionMsg("Document doesn't support tiled rendering");
6929 auto aRectangleVector
= pDoc
->getSearchResultRectangles(pSearchResult
);
6931 // combine into a rectangle union
6932 basegfx::B2DRange aRangeUnion
;
6933 for (basegfx::B2DRange
const & rRange
: aRectangleVector
)
6935 aRangeUnion
.expand(rRange
);
6938 int aPixelWidth
= o3tl::convert(aRangeUnion
.getWidth(), o3tl::Length::twip
, o3tl::Length::px
);
6939 int aPixelHeight
= o3tl::convert(aRangeUnion
.getHeight(), o3tl::Length::twip
, o3tl::Length::px
);
6941 size_t nByteSize
= aPixelWidth
* aPixelHeight
* 4;
6943 *pWidth
= aPixelWidth
;
6944 *pHeight
= aPixelHeight
;
6945 *pByteSize
= nByteSize
;
6947 auto* pBuffer
= static_cast<unsigned char*>(std::malloc(nByteSize
));
6949 doc_paintTile(pThis
, pBuffer
,
6950 aPixelWidth
, aPixelHeight
,
6951 aRangeUnion
.getMinX(), aRangeUnion
.getMinY(),
6952 aRangeUnion
.getWidth(), aRangeUnion
.getHeight());
6954 *pBitmapBuffer
= pBuffer
;
6959 static void doc_sendContentControlEvent(LibreOfficeKitDocument
* pThis
, const char* pArguments
)
6961 SolarMutexGuard aGuard
;
6963 // Supported in Writer only
6964 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
)
6969 StringMap
aMap(jsdialog::jsonToStringMap(pArguments
));
6970 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
6973 SetLastExceptionMsg("Document doesn't support tiled rendering");
6978 if (aMap
.find("type") == aMap
.end())
6980 SetLastExceptionMsg("Missing 'type' argument for sendContentControlEvent");
6984 pDoc
->executeContentControlEvent(aMap
);
6987 static void doc_setViewTimezone(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
,
6988 const char* pTimezone
)
6990 comphelper::ProfileZone
aZone("doc_setViewTimezone");
6992 SolarMutexGuard aGuard
;
6993 SetLastExceptionMsg();
6995 // Leave the default if we get a null timezone.
6998 OUString sTimezone
= OStringToOUString(pTimezone
, RTL_TEXTENCODING_UTF8
);
6999 SfxLokHelper::setViewTimezone(nId
, true, sTimezone
);
7003 static void doc_setAccessibilityState(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* pThis
, int nId
, bool nEnabled
)
7005 SolarMutexGuard aGuard
;
7006 SetLastExceptionMsg();
7008 int nDocType
= getDocumentType(pThis
);
7009 if (nDocType
!= LOK_DOCTYPE_TEXT
)
7012 SfxLokHelper::setAccessibilityState(nId
, nEnabled
);
7015 static char* lo_getError (LibreOfficeKit
*pThis
)
7017 comphelper::ProfileZone
aZone("lo_getError");
7019 SolarMutexGuard aGuard
;
7021 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
7022 return convertOUString(pLib
->maLastExceptionMsg
);
7025 static void lo_freeError(char* pFree
)
7030 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
)
7032 SolarMutexGuard aGuard
;
7033 SetLastExceptionMsg();
7035 LibLibreOffice_Impl
* pImpl
= static_cast<LibLibreOffice_Impl
*>(pThis
);
7037 if (!xSFactory
.is())
7038 xSFactory
= comphelper::getProcessServiceFactory();
7040 if (!xSFactory
.is())
7042 pImpl
->maLastExceptionMsg
= "Service factory is not available";
7046 uno::Reference
<container::XNameAccess
> xTypeDetection(xSFactory
->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY
);
7047 const uno::Sequence
<OUString
> aTypes
= xTypeDetection
->getElementNames();
7048 tools::JsonWriter aJson
;
7049 for (const OUString
& rType
: aTypes
)
7051 uno::Sequence
<beans::PropertyValue
> aValues
;
7052 if (xTypeDetection
->getByName(rType
) >>= aValues
)
7054 auto it
= std::find_if(std::cbegin(aValues
), std::cend(aValues
), [](const beans::PropertyValue
& rValue
) { return rValue
.Name
== "MediaType"; });
7056 if (it
!= std::cend(aValues
) && (it
->Value
>>= aValue
) && !aValue
.isEmpty())
7058 auto typeNode
= aJson
.startNode(rType
.toUtf8());
7059 aJson
.put("MediaType", aValue
.toUtf8());
7064 return strdup(aJson
.finishAndGetAsOString().getStr());
7067 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long const features
)
7069 comphelper::ProfileZone
aZone("lo_setOptionalFeatures");
7071 SolarMutexGuard aGuard
;
7072 SetLastExceptionMsg();
7074 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
7075 pLib
->mOptionalFeatures
= features
;
7076 if (features
& LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK
)
7077 comphelper::LibreOfficeKit::setPartInInvalidation(true);
7078 if (features
& LOK_FEATURE_NO_TILED_ANNOTATIONS
)
7079 comphelper::LibreOfficeKit::setTiledAnnotations(false);
7080 if (features
& LOK_FEATURE_RANGE_HEADERS
)
7081 comphelper::LibreOfficeKit::setRangeHeaders(true);
7082 if (features
& LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK
)
7083 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
7086 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
7087 const char* pURL
, const char* pPassword
)
7089 comphelper::ProfileZone
aZone("lo_setDocumentPassword");
7091 SolarMutexGuard aGuard
;
7092 SetLastExceptionMsg();
7096 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
7097 assert(pLib
->mInteractionMap
.find(OString(pURL
)) != pLib
->mInteractionMap
.end());
7098 pLib
->mInteractionMap
.find(OString(pURL
))->second
->SetPassword(pPassword
);
7101 static char* lo_getVersionInfo(SAL_UNUSED_PARAMETER LibreOfficeKit
* /*pThis*/)
7103 SetLastExceptionMsg();
7104 return convertOUString(ReplaceStringHookProc(
7106 "\"ProductName\": \"%PRODUCTNAME\", "
7107 "\"ProductVersion\": \"%PRODUCTVERSION\", "
7108 "\"ProductExtension\": \"%PRODUCTEXTENSION\", "
7109 "\"BuildId\": \"%BUILDID\", "
7110 "\"BuildConfig\": \"" BUILDCONFIG
"\" "
7114 static void aBasicErrorFunc(const OUString
& rError
, const OUString
& rAction
)
7116 OString aBuffer
= "Unexpected dialog: " +
7117 OUStringToOString(rAction
, RTL_TEXTENCODING_ASCII_US
) +
7119 OUStringToOString(rError
, RTL_TEXTENCODING_ASCII_US
);
7121 fprintf(stderr
, "Unexpected basic error dialog '%s'\n", aBuffer
.getStr());
7124 static bool initialize_uno(const OUString
& aAppProgramURL
)
7127 // For iOS we already hardcode the inifile as "rc" in the .app directory.
7128 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("fundamental"));
7129 xContext
= cppu::defaultBootstrap_InitialComponentContext(aAppProgramURL
+ "/rc");
7130 #elif defined MACOSX
7131 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/../Resources/" SAL_CONFIGFILE("soffice"));
7132 xContext
= cppu::defaultBootstrap_InitialComponentContext();
7134 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("soffice"));
7135 xContext
= cppu::defaultBootstrap_InitialComponentContext();
7140 SetLastExceptionMsg("XComponentContext could not be created");
7141 SAL_INFO("lok", "XComponentContext could not be created");
7145 xFactory
= xContext
->getServiceManager();
7148 SetLastExceptionMsg("XMultiComponentFactory could not be created");
7149 SAL_INFO("lok", "XMultiComponentFactory could not be created");
7153 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
7154 comphelper::setProcessServiceFactory(xSFactory
);
7156 SAL_INFO("lok", "Uno initialized - " << xContext
.is());
7158 // set UserInstallation to user profile dir in test/user-template
7159 // rtl::Bootstrap aDefaultVars;
7160 // aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
7161 // configmgr setup ?
7166 // pre-unipoll version.
7167 static void lo_startmain(void*)
7169 osl_setThreadName("lo_startmain");
7171 if (comphelper::SolarMutex::get())
7172 Application::GetSolarMutex().tryToAcquire();
7174 Application::UpdateMainThread();
7178 Application::ReleaseSolarMutex();
7182 static void lo_runLoop(LibreOfficeKit
* /*pThis*/,
7183 LibreOfficeKitPollCallback pPollCallback
,
7184 LibreOfficeKitWakeCallback pWakeCallback
,
7187 #if defined(IOS) || defined(ANDROID) || defined(__EMSCRIPTEN__)
7188 Application::GetSolarMutex().acquire();
7192 SolarMutexGuard aGuard
;
7194 vcl::lok::registerPollCallbacks(pPollCallback
, pWakeCallback
, pData
);
7195 Application::UpdateMainThread();
7198 #if defined(IOS) || defined(ANDROID) || defined(__EMSCRIPTEN__)
7199 vcl::lok::unregisterPollCallbacks();
7200 Application::ReleaseSolarMutex();
7204 static bool bInitialized
= false;
7206 static void lo_status_indicator_callback(void *data
, comphelper::LibreOfficeKit::statusIndicatorCallbackType type
, int percent
, const char* pText
)
7208 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(data
);
7210 if (!pLib
->mpCallback
)
7215 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start
:
7216 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START
, pText
, pLib
->mpCallbackData
);
7218 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue
:
7219 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
,
7220 OUString(OUString::number(percent
)).toUtf8().getStr(), pLib
->mpCallbackData
);
7222 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Finish
:
7223 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH
, nullptr, pLib
->mpCallbackData
);
7228 /// Used by preloadData (LibreOfficeKit) for providing different shortcuts for different languages.
7229 static void preLoadShortCutAccelerators()
7231 std::unordered_map
<OUString
, css::uno::Reference
<com::sun::star::ui::XAcceleratorConfiguration
>>& acceleratorConfs
= SfxLokHelper::getAcceleratorConfs();
7232 css::uno::Sequence
<OUString
> installedLocales(officecfg::Setup::Office::InstalledLocales::get()->getElementNames());
7233 OUString actualLang
= officecfg::Setup::L10N::ooLocale::get();
7235 for (sal_Int32 i
= 0; i
< installedLocales
.getLength(); i
++)
7237 OUString language
= LanguageTag(installedLocales
[i
]).getLocale().Language
;
7239 if (!comphelper::LibreOfficeKit::isAllowlistedLanguage(language
))
7241 // Language is listed by COOL and also installed in core. We can create the short cut accelerator.
7243 // Set the UI language to current one, before creating the accelerator.
7244 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
7245 officecfg::Setup::L10N::ooLocale::set(installedLocales
[i
], batch
);
7248 // Supported module names: Writer, Calc, Draw, Impress
7249 std::vector
<OUString
> supportedModuleNames
= { "com.sun.star.text.TextDocument", "com.sun.star.sheet.SpreadsheetDocument", "com.sun.star.drawing.DrawingDocument", "com.sun.star.presentation.PresentationDocument" };
7250 // Create the accelerators.
7251 for (std::size_t j
= 0; j
< supportedModuleNames
.size(); j
++)
7253 OUString key
= supportedModuleNames
[j
] + installedLocales
[i
];
7254 acceleratorConfs
[key
] = svt::AcceleratorExecute::lok_createNewAcceleratorConfiguration(::comphelper::getProcessComponentContext(), supportedModuleNames
[j
]);
7259 std::cerr
<< "Language is installed in core but not in the list of COOL languages: " << language
<< "\n";
7263 // Set the UI language back to default one.
7264 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
7265 officecfg::Setup::L10N::ooLocale::set(actualLang
, batch
);
7269 /// Used only by LibreOfficeKit when used by Online to pre-initialize
7270 static void preloadData()
7272 comphelper::ProfileZone
aZone("preload data");
7274 // Create user profile in the temp directory for loading the dictionaries
7276 rtl::Bootstrap::get("UserInstallation", sUserPath
);
7277 utl::TempFileNamed
aTempDir(nullptr, true);
7278 aTempDir
.EnableKillingFile();
7279 rtl::Bootstrap::set("UserInstallation", aTempDir
.GetURL());
7281 // Register the bundled extensions
7282 desktop::Desktop::SynchronizeExtensionRepositories(true);
7283 bool bAbort
= desktop::Desktop::CheckExtensionDependencies();
7285 std::cerr
<< "CheckExtensionDependencies failed" << std::endl
;
7287 // preload all available dictionaries
7288 css::uno::Reference
<css::linguistic2::XLinguServiceManager
> xLngSvcMgr
=
7289 css::linguistic2::LinguServiceManager::create(comphelper::getProcessComponentContext());
7290 css::uno::Reference
<linguistic2::XSpellChecker
> xSpellChecker(xLngSvcMgr
->getSpellChecker());
7292 std::cerr
<< "Preloading dictionaries: ";
7293 css::uno::Reference
<linguistic2::XSupportedLocales
> xSpellLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
7294 uno::Sequence
< css::lang::Locale
> aLocales
= xSpellLocales
->getLocales();
7295 for (auto &it
: std::as_const(aLocales
))
7297 std::cerr
<< LanguageTag::convertToBcp47(it
) << " ";
7298 css::beans::PropertyValues aNone
;
7299 xSpellChecker
->isValid("forcefed", it
, aNone
);
7303 // Hack to load and cache the module liblocaledata_others.so which is not loaded normally
7304 // (when loading dictionaries of just non-Asian locales). Creating a XCalendar4 of one Asian locale
7305 // will cheaply load this missing "others" locale library. Appending an Asian locale in
7306 // LOK_ALLOWLIST_LANGUAGES env-var also works but at the cost of loading that dictionary.
7307 css::uno::Reference
< css::i18n::XCalendar4
> xCal
= css::i18n::LocaleCalendar2::create(comphelper::getProcessComponentContext());
7308 css::lang::Locale aAsianLocale
= {"hi", "IN", ""};
7309 xCal
->loadDefaultCalendar(aAsianLocale
);
7311 // preload all available thesauri
7312 css::uno::Reference
<linguistic2::XThesaurus
> xThesaurus(xLngSvcMgr
->getThesaurus());
7313 css::uno::Reference
<linguistic2::XSupportedLocales
> xThesLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
7314 aLocales
= xThesLocales
->getLocales();
7315 std::cerr
<< "Preloading thesauri: ";
7316 for (auto &it
: std::as_const(aLocales
))
7318 std::cerr
<< LanguageTag::convertToBcp47(it
) << " ";
7319 css::beans::PropertyValues aNone
;
7320 xThesaurus
->queryMeanings("forcefed", it
, aNone
);
7324 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
= css::ui::GlobalAcceleratorConfiguration::create(
7325 comphelper::getProcessComponentContext());
7326 xGlobalCfg
->getAllKeyEvents();
7328 std::cerr
<< "Preload icons\n";
7329 ImageTree
&images
= ImageTree::get();
7330 images
.getImageUrl("forcefed.png", "style", "FO_oo");
7332 std::cerr
<< "Preload short cut accelerators\n";
7333 preLoadShortCutAccelerators();
7335 std::cerr
<< "Preload languages\n";
7337 // force load language singleton
7338 SvtLanguageTable::HasLanguageType(LANGUAGE_SYSTEM
);
7339 (void)LanguageTag::isValidBcp47("foo", nullptr);
7341 std::cerr
<< "Preload fonts\n";
7343 // Initialize fonts.
7344 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
7347 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
7349 aLocales
= xSpell
->getLocales();
7352 for (const auto& aLocale
: std::as_const(aLocales
))
7354 //TODO: Add more types and cache more aggressively. For now this initializes the fontcache.
7355 using namespace ::com::sun::star::i18n::ScriptType
;
7357 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), LATIN
);
7358 OutputDevice::GetDefaultFont(DefaultFontType::LATIN_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
7359 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), ASIAN
);
7360 OutputDevice::GetDefaultFont(DefaultFontType::CJK_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
7361 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), COMPLEX
);
7362 OutputDevice::GetDefaultFont(DefaultFontType::CTL_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
7365 std::cerr
<< "Preload config\n";
7366 #if defined __GNUC__ || defined __clang__
7367 #pragma GCC diagnostic push
7368 #pragma GCC diagnostic ignored "-Wunused-variable"
7370 static SvtOptionsDialogOptions aDialogOptions
;
7371 static SvtCTLOptions aSvtCTLOptions
;
7372 static SvtAccessibilityOptions aSvtAccessibilityOptions
;
7373 static svtools::ColorConfig aColorConfig
;
7374 static SvtMiscOptions aSvtMiscOptions
;
7375 static SvtSlideSorterBarOptions aSvtSlideSorterBarOptions
;
7376 static SvtCommandOptions aSvtCommandOptions
;
7377 static SvtCompatibilityOptions aSvtCompatibilityOptions
;
7378 static SvtFilterOptions aSvtFilterOptions
;
7379 static SvtLinguConfig aSvtLinguConfig
;
7380 static SvtModuleOptions aSvtModuleOptions
;
7381 static SvtPathOptions aSvtPathOptions
;
7382 static SvtSearchOptions aSvtSearchOptions
;
7383 static SvtSysLocaleOptions aSvtSysLocaleOptions
;
7384 static SvtUserOptions aSvtUserOptions
;
7385 //static SvtViewOptions aSvtViewOptions;
7386 static MouseSettings aMouseSettings
;
7387 static StyleSettings aStyleSettings
;
7388 static MiscSettings aMiscSettings
;
7389 static HelpSettings aHelpSettings
;
7390 static AllSettings aAllSettings
;
7391 #if defined __GNUC__ || defined __clang__
7392 #pragma GCC diagnostic pop
7395 // Set user profile's path back to the original one
7396 rtl::Bootstrap::set("UserInstallation", sUserPath
);
7401 static void activateNotebookbar(std::u16string_view rApp
)
7403 OUString aPath
= OUString::Concat("org.openoffice.Office.UI.ToolbarMode/Applications/") + rApp
;
7405 const utl::OConfigurationTreeRoot
aAppNode(xContext
, aPath
, true);
7407 if (aAppNode
.isValid())
7409 aAppNode
.setNodeValue("Active", Any(OUString("notebookbar_online.ui")));
7414 void setCertificateDir()
7416 const char* pEnvVarString
= ::getenv("LO_CERTIFICATE_DATABASE_PATH");
7419 OUString aCertificateDatabasePath
= OStringToOUString(pEnvVarString
, RTL_TEXTENCODING_UTF8
);
7422 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(comphelper::ConfigurationChanges::create());
7423 officecfg::Office::Common::Security::Scripting::CertDir::set(aCertificateDatabasePath
, pBatch
);
7424 officecfg::Office::Common::Security::Scripting::ManualCertDir::set(aCertificateDatabasePath
, pBatch
);
7427 catch (uno::Exception
const& rException
)
7429 SAL_WARN("lok", "Failed to set the NSS certificate database directory: " << rException
.Message
);
7434 void setDeeplConfig()
7436 const char* pAPIUrlString
= ::getenv("DEEPL_API_URL");
7437 const char* pAuthKeyString
= ::getenv("DEEPL_AUTH_KEY");
7438 if (pAPIUrlString
&& pAuthKeyString
)
7440 OUString aAPIUrl
= OStringToOUString(pAPIUrlString
, RTL_TEXTENCODING_UTF8
);
7441 OUString aAuthKey
= OStringToOUString(pAuthKeyString
, RTL_TEXTENCODING_UTF8
);
7444 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
7445 officecfg::Office::Linguistic::Translation::Deepl::ApiURL::set(aAPIUrl
, batch
);
7446 officecfg::Office::Linguistic::Translation::Deepl::AuthKey::set(aAuthKey
, batch
);
7449 catch(uno::Exception
const& rException
)
7451 SAL_WARN("lok", "Failed to set Deepl API settings: " << rException
.Message
);
7456 void setLanguageToolConfig()
7458 const char* pEnabled
= ::getenv("LANGUAGETOOL_ENABLED");
7459 const char* pBaseUrlString
= ::getenv("LANGUAGETOOL_BASEURL");
7461 if (pEnabled
&& pBaseUrlString
)
7463 const char* pUsername
= ::getenv("LANGUAGETOOL_USERNAME");
7464 const char* pApikey
= ::getenv("LANGUAGETOOL_APIKEY");
7465 const char* pSSLVerification
= ::getenv("LANGUAGETOOL_SSL_VERIFICATION");
7466 const char* pRestProtocol
= ::getenv("LANGUAGETOOL_RESTPROTOCOL");
7468 OUString aEnabled
= OStringToOUString(pEnabled
, RTL_TEXTENCODING_UTF8
);
7469 if (aEnabled
!= "true")
7471 OUString aBaseUrl
= OStringToOUString(pBaseUrlString
, RTL_TEXTENCODING_UTF8
);
7474 using LanguageToolCfg
= officecfg::Office::Linguistic::GrammarChecking::LanguageTool
;
7475 auto batch(comphelper::ConfigurationChanges::create());
7477 LanguageToolCfg::BaseURL::set(aBaseUrl
, batch
);
7478 LanguageToolCfg::IsEnabled::set(true, batch
);
7479 if (pSSLVerification
)
7481 OUString aSSLVerification
= OStringToOUString(pSSLVerification
, RTL_TEXTENCODING_UTF8
);
7482 LanguageToolCfg::SSLCertVerify::set(aSSLVerification
== "true", batch
);
7486 OUString aRestProtocol
= OStringToOUString(pRestProtocol
, RTL_TEXTENCODING_UTF8
);
7487 LanguageToolCfg::RestProtocol::set(aRestProtocol
, batch
);
7489 if (pUsername
&& pApikey
)
7491 OUString aUsername
= OStringToOUString(pUsername
, RTL_TEXTENCODING_UTF8
);
7492 OUString aApiKey
= OStringToOUString(pApikey
, RTL_TEXTENCODING_UTF8
);
7493 LanguageToolCfg::Username::set(aUsername
, batch
);
7494 LanguageToolCfg::ApiKey::set(aApiKey
, batch
);
7498 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
=
7499 css::linguistic2::LinguServiceManager::create(xContext
);
7502 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
7505 Sequence
<OUString
> aEmpty
;
7506 Sequence
<css::lang::Locale
> aLocales
= xSpell
->getLocales();
7508 for (int itLocale
= 0; itLocale
< aLocales
.getLength(); itLocale
++)
7510 xLangSrv
->setConfiguredServices(SN_SPELLCHECKER
, aLocales
[itLocale
], aEmpty
);
7515 catch(uno::Exception
const& rException
)
7517 SAL_WARN("lok", "Failed to set LanguageTool API settings: " << rException
.Message
);
7524 static int lo_initialize(LibreOfficeKit
* pThis
, const char* pAppPath
, const char* pUserProfileUrl
)
7527 PRE_INIT
, // setup shared data in master process
7528 SECOND_INIT
, // complete init. after fork
7529 FULL_INIT
// do a standard complete init.
7532 // Did we do a pre-initialize
7533 static bool bPreInited
= false;
7534 static bool bUnipoll
= false;
7535 static bool bProfileZones
= false;
7536 static bool bNotebookbar
= false;
7538 { // cf. string lifetime for preinit
7539 std::vector
<OUString
> aOpts
;
7541 // ':' delimited options - avoiding ABI change for new parameters
7542 const char *pOptions
= getenv("SAL_LOK_OPTIONS");
7544 aOpts
= comphelper::string::split(OUString(pOptions
, strlen(pOptions
), RTL_TEXTENCODING_UTF8
), ':');
7545 for (const auto &it
: aOpts
)
7547 if (it
== "unipoll")
7549 else if (it
== "profile_events")
7550 bProfileZones
= true;
7551 else if (it
== "sc_no_grid_bg")
7552 comphelper::LibreOfficeKit::setCompatFlag(
7553 comphelper::LibreOfficeKit::Compat::scNoGridBackground
);
7554 else if (it
== "sc_print_twips_msgs")
7555 comphelper::LibreOfficeKit::setCompatFlag(
7556 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
7557 else if (it
== "notebookbar")
7558 bNotebookbar
= true;
7562 // What stage are we at ?
7563 if (pThis
== nullptr)
7566 if (lok_preinit_2_called
)
7568 SAL_INFO("lok", "Create libreoffice object");
7569 gImpl
= new LibLibreOffice_Impl();
7572 else if (bPreInited
)
7573 eStage
= SECOND_INIT
;
7577 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
7582 // Turn profile zones on early
7583 if (bProfileZones
&& eStage
== SECOND_INIT
)
7585 comphelper::TraceEvent::startRecording();
7586 traceEventDumper
= new TraceEventDumper();
7589 comphelper::ProfileZone
aZone("lok-init");
7591 if (eStage
== PRE_INIT
)
7593 rtl_alloc_preInit(true);
7595 // Set the default timezone to the TZ envar, if set.
7596 const char* tz
= ::getenv("TZ");
7597 SfxLokHelper::setDefaultTimezone(!!tz
, tz
? OStringToOUString(tz
, RTL_TEXTENCODING_UTF8
)
7601 if (eStage
!= SECOND_INIT
)
7602 comphelper::LibreOfficeKit::setActive();
7604 if (eStage
!= PRE_INIT
)
7605 comphelper::LibreOfficeKit::setStatusIndicatorCallback(lo_status_indicator_callback
, pLib
);
7607 if (pUserProfileUrl
&& eStage
!= PRE_INIT
)
7610 pUserProfileUrl
, strlen(pUserProfileUrl
), RTL_TEXTENCODING_UTF8
);
7612 if (url
.startsWithIgnoreAsciiCase("vnd.sun.star.pathname:", &path
))
7615 osl::FileBase::RC e
= osl::FileBase::getFileURLFromSystemPath(
7617 if (e
== osl::FileBase::E_None
)
7620 SAL_WARN("lok", "resolving <" << url
<< "> failed with " << +e
);
7622 rtl::Bootstrap::set("UserInstallation", url
);
7623 if (eStage
== SECOND_INIT
)
7624 utl::Bootstrap::reloadData();
7630 aAppPath
= OUString(pAppPath
, strlen(pAppPath
), RTL_TEXTENCODING_UTF8
);
7634 #if defined ANDROID || defined EMSCRIPTEN
7635 aAppPath
= OUString::fromUtf8(lo_get_app_data_dir()) + "/program";
7637 // Fun conversion dance back and forth between URLs and system paths...
7639 ::osl::Module::getUrlFromAddress( reinterpret_cast< oslGenericFunction
>(lo_initialize
),
7641 osl::FileBase::getSystemPathFromFileURL( aAppURL
, aAppPath
);
7645 // The above gives something like
7646 // "/private/var/containers/Bundle/Application/953AA851-CC15-4C60-A2CB-C2C6F24E6F71/Foo.app/Foo",
7647 // and we want to drop the final component (the binary name).
7648 sal_Int32 lastSlash
= aAppPath
.lastIndexOf('/');
7649 assert(lastSlash
> 0);
7650 aAppPath
= aAppPath
.copy(0, lastSlash
);
7655 if (osl::FileBase::getFileURLFromSystemPath(aAppPath
, aAppURL
) != osl::FileBase::E_None
)
7659 // A LibreOffice-using iOS app should have the ICU data file in the app bundle. Initialize ICU
7661 NSString
*bundlePath
= [[NSBundle mainBundle
] bundlePath
];
7663 int fd
= open([[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
], O_RDONLY
);
7665 NSLog(@
"Could not open ICU data file %s", [[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
]);
7669 if (fstat(fd
, &st
) == -1)
7670 NSLog(@
"fstat on ICU data file failed: %s", strerror(errno
));
7673 void *icudata
= mmap(0, (size_t) st
.st_size
, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
7674 if (icudata
== MAP_FAILED
)
7675 NSLog(@
"mmap failed: %s", strerror(errno
));
7678 UErrorCode icuStatus
= U_ZERO_ERROR
;
7679 udata_setCommonData(icudata
, &icuStatus
);
7680 if (U_FAILURE(icuStatus
))
7681 NSLog(@
"udata_setCommonData failed");
7684 // Quick test that ICU works...
7685 UConverter
*cnv
= ucnv_open("iso-8859-3", &icuStatus
);
7686 if (U_SUCCESS(icuStatus
))
7689 NSLog(@
"ucnv_open() failed: %s", u_errorName(icuStatus
));
7699 if (eStage
!= SECOND_INIT
)
7701 SAL_INFO("lok", "Attempting to initialize UNO");
7703 if (!initialize_uno(aAppURL
))
7706 // Force headless -- this is only for bitmap rendering.
7707 rtl::Bootstrap::set("SAL_USE_VCLPLUGIN", "svp");
7709 // We specifically need to make sure we have the "headless"
7710 // command arg set (various code specifically checks via
7711 // CommandLineArgs):
7712 desktop::Desktop::GetCommandLineArgs().setHeadless();
7715 if (InitVCL() && [NSThread isMainThread
])
7717 static bool bFirstTime
= true;
7720 Application::GetSolarMutex().release();
7724 SfxApplication::GetOrCreate();
7727 #if HAVE_FEATURE_ANDROID_LOK
7728 // Register the bundled extensions - so that the dictionaries work
7729 desktop::Desktop::SynchronizeExtensionRepositories(false);
7730 bool bFailed
= desktop::Desktop::CheckExtensionDependencies();
7732 SAL_INFO("lok", "CheckExtensionDependencies failed");
7735 if (eStage
== PRE_INIT
)
7738 comphelper::ProfileZone
aInit("Init vcl");
7739 std::cerr
<< "Init vcl\n";
7743 // pre-load all component libraries.
7745 throw css::uno::DeploymentException("preInit: XComponentContext is not created");
7747 css::uno::Reference
< css::uno::XInterface
> xService
;
7748 xContext
->getValueByName("/singletons/com.sun.star.lang.theServiceManager") >>= xService
;
7750 throw css::uno::DeploymentException("preInit: XMultiComponentFactory is not created");
7752 css::uno::Reference
<css::lang::XInitialization
> aService(
7753 xService
, css::uno::UNO_QUERY_THROW
);
7756 // In order to load implementations and invoke
7757 // component factory it is required:
7758 // 1) defaultBootstrap_InitialComponentContext()
7759 // 2) comphelper::setProcessServiceFactory(xSFactory);
7762 comphelper::ProfileZone
aInit("preload");
7763 aService
->initialize({css::uno::Any(OUString("preload"))});
7765 { // Force load some modules
7766 comphelper::ProfileZone
aInit("preload modules");
7767 VclBuilderPreload();
7768 VclAbstractDialogFactory::Create();
7773 // Release Solar Mutex, lo_startmain thread should acquire it.
7774 Application::ReleaseSolarMutex();
7777 setLanguageAndLocale("en-US");
7780 if (eStage
!= PRE_INIT
)
7782 SAL_INFO("lok", "Re-initialize temp paths");
7783 SvtPathOptions aOptions
;
7785 osl::FileBase::getTempDirURL(aNewTemp
);
7786 aOptions
.SetTempPath(aNewTemp
);
7787 desktop::Desktop::CreateTemporaryDirectory();
7789 // The RequestHandler is specifically set to be ready when all the other
7790 // init in Desktop::Main (run from soffice_main) is done. We can enable
7791 // the RequestHandler here (without starting any IPC thread;
7792 // shortcutting the invocation in Desktop::Main that would start the IPC
7793 // thread), and can then use it to wait until we're definitely ready to
7796 SAL_INFO("lok", "Enabling RequestHandler");
7797 RequestHandler::Enable(false);
7798 SAL_INFO("lok", "Starting soffice_main");
7799 RequestHandler::SetReady(false);
7802 // Start the main thread only in non-unipoll mode (i.e. multithreaded).
7803 pLib
->maThread
= osl_createThread(lo_startmain
, nullptr);
7804 SAL_INFO("lok", "Waiting for RequestHandler");
7805 RequestHandler::WaitForReady();
7806 SAL_INFO("lok", "RequestHandler ready -- continuing");
7812 if (eStage
!= SECOND_INIT
)
7813 ErrorRegistry::RegisterDisplay(aBasicErrorFunc
);
7815 SAL_INFO("lok", "LOK Initialized");
7816 if (eStage
== PRE_INIT
)
7819 bInitialized
= true;
7821 catch (css::uno::Exception
& exception
)
7823 fprintf(stderr
, "Bootstrapping exception '%s'\n",
7824 OUStringToOString(exception
.Message
, RTL_TEXTENCODING_UTF8
).getStr());
7827 if (eStage
== PRE_INIT
)
7829 comphelper::ThreadPool::getSharedOptimalPool().shutdown();
7832 // Turn off quick editing on iOS, Android and Emscripten
7833 #if defined IOS || defined ANDROID || defined __EMSCRIPTEN__
7834 if (officecfg::Office::Impress::Misc::TextObject::QuickEditing::get())
7836 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
7837 officecfg::Office::Impress::Misc::TextObject::QuickEditing::set(false, batch
);
7842 setCertificateDir();
7844 setLanguageToolConfig();
7848 activateNotebookbar(u
"Writer");
7849 activateNotebookbar(u
"Calc");
7850 activateNotebookbar(u
"Impress");
7851 activateNotebookbar(u
"Draw");
7854 // staticize all strings.
7855 if (eStage
== PRE_INIT
)
7856 rtl_alloc_preInit(false);
7858 return bInitialized
;
7862 LibreOfficeKit
*libreofficekit_hook_2(const char* install_path
, const char* user_profile_url
)
7864 static bool alreadyCalled
= false;
7866 if ((!lok_preinit_2_called
&& !gImpl
) || (lok_preinit_2_called
&& !alreadyCalled
))
7868 alreadyCalled
= true;
7870 if (!lok_preinit_2_called
)
7872 SAL_INFO("lok", "Create libreoffice object");
7873 gImpl
= new LibLibreOffice_Impl();
7876 if (!lo_initialize(gImpl
, install_path
, user_profile_url
))
7881 return static_cast<LibreOfficeKit
*>(gImpl
);
7885 LibreOfficeKit
*libreofficekit_hook(const char* install_path
)
7887 return libreofficekit_hook_2(install_path
, nullptr);
7891 int lok_preinit(const char* install_path
, const char* user_profile_url
)
7893 return lo_initialize(nullptr, install_path
, user_profile_url
);
7897 int lok_preinit_2(const char* install_path
, const char* user_profile_url
, LibreOfficeKit
** kit
)
7899 lok_preinit_2_called
= true;
7900 int result
= lo_initialize(nullptr, install_path
, user_profile_url
);
7906 static void lo_destroy(LibreOfficeKit
* pThis
)
7908 SolarMutexClearableGuard aGuard
;
7910 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
7913 SAL_INFO("lok", "LO Destroy");
7915 comphelper::LibreOfficeKit::setStatusIndicatorCallback(nullptr, nullptr);
7916 uno::Reference
<frame::XDesktop2
> xDesktop
= frame::Desktop::create ( ::comphelper::getProcessComponentContext() );
7917 // FIXME: the terminate() call here is a no-op because it detects
7918 // that LibreOfficeKit::isActive() and then returns early!
7919 bool bSuccess
= xDesktop
.is() && xDesktop
->terminate();
7923 bSuccess
= GetpApp() && GetpApp()->QueryExit();
7928 Application::Quit();
7933 osl_joinWithThread(pLib
->maThread
);
7934 osl_destroyThread(pLib
->maThread
);
7937 bInitialized
= false;
7938 SAL_INFO("lok", "LO Destroy Done");
7943 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */