LibreOffice Module desktop (master) 1
init.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 */
9
10#include <sfx2/lokhelper.hxx>
11#include <config_buildconfig.h>
12#include <config_cairo_rgba.h>
13#include <config_features.h>
14
15#include <stdio.h>
16#include <string.h>
17#include <stdlib.h>
18
19#ifdef IOS
20#include <sys/mman.h>
21#include <sys/stat.h>
22#include <unicode/udata.h>
23#include <unicode/ucnv.h>
24#include <premac.h>
25#import <Foundation/Foundation.h>
26#import <CoreGraphics/CoreGraphics.h>
27#include <postmac.h>
28#endif
29
30#undef HAVE_MALLOC_TRIM
31
32#ifdef LINUX
33#include <fcntl.h>
34#if defined __GLIBC__
35# include <malloc.h>
36# define HAVE_MALLOC_TRIM
37#endif
38#endif
39
40#ifdef ANDROID
41#include <osl/detail/android-bootstrap.h>
42#endif
43
44#ifdef EMSCRIPTEN
45#include <osl/detail/emscripten-bootstrap.h>
46#endif
47
48#include <algorithm>
49#include <memory>
50#include <iostream>
51#include <string_view>
52
53#include <boost/property_tree/json_parser.hpp>
54#include <boost/algorithm/string.hpp>
55
56#include <LibreOfficeKit/LibreOfficeKit.h>
57#include <LibreOfficeKit/LibreOfficeKitEnums.h>
58
59#include <sal/log.hxx>
60#include <utility>
61#include <vcl/errinf.hxx>
62#include <vcl/lok.hxx>
63#include <o3tl/any.hxx>
65#include <o3tl/string_view.hxx>
66#include <osl/file.hxx>
67#include <osl/process.h>
68#include <osl/thread.h>
69#include <rtl/bootstrap.hxx>
70#include <rtl/strbuf.hxx>
71#include <rtl/uri.hxx>
72#include <svl/zforlist.hxx>
73#include <linguistic/misc.hxx>
75#include <comphelper/base64.hxx>
77#include <comphelper/lok.hxx>
79#include <comphelper/string.hxx>
87
88#include <com/sun/star/document/MacroExecMode.hpp>
89#include <com/sun/star/beans/XPropertySet.hpp>
90#include <com/sun/star/container/XNameAccess.hpp>
91#include <com/sun/star/document/XDocumentLanguages.hpp>
92#include <com/sun/star/frame/Desktop.hpp>
93#include <com/sun/star/frame/DispatchResultEvent.hpp>
94#include <com/sun/star/frame/DispatchResultState.hpp>
95#include <com/sun/star/frame/XDispatchProvider.hpp>
96#include <com/sun/star/frame/XDispatchResultListener.hpp>
97#include <com/sun/star/frame/XSynchronousDispatch.hpp>
98#include <com/sun/star/frame/XStorable.hpp>
99#include <com/sun/star/lang/Locale.hpp>
100#include <com/sun/star/lang/XComponent.hpp>
101#include <com/sun/star/lang/XMultiServiceFactory.hpp>
102#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
103#include <com/sun/star/util/URLTransformer.hpp>
104#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
105#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
106#include <com/sun/star/datatransfer/XTransferable2.hpp>
107#include <com/sun/star/text/TextContentAnchorType.hpp>
108#include <com/sun/star/document/XRedlinesSupplier.hpp>
109#include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
110
111#include <com/sun/star/xml/crypto/SEInitializer.hpp>
112#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
113#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
114#include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
115#include <com/sun/star/security/XCertificate.hpp>
116
117#include <com/sun/star/linguistic2/LanguageGuessing.hpp>
118#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
119#include <com/sun/star/linguistic2/XSpellChecker.hpp>
120#include <com/sun/star/i18n/LocaleCalendar2.hpp>
121#include <com/sun/star/i18n/ScriptType.hpp>
122#include <com/sun/star/lang/DisposedException.hpp>
123
124#include <editeng/flstitem.hxx>
125#ifdef IOS
126#include <sfx2/app.hxx>
127#endif
128#include <sfx2/objsh.hxx>
129#include <sfx2/docfilt.hxx>
130#include <sfx2/docfile.hxx>
131#include <sfx2/viewsh.hxx>
132#include <sfx2/viewfrm.hxx>
133#include <sfx2/msgpool.hxx>
134#include <sfx2/dispatch.hxx>
139#include <svl/numformat.hxx>
140#include <svx/dialmgr.hxx>
141#include <svx/strings.hrc>
142#include <svx/svdview.hxx>
143#include <svx/svxids.hrc>
144#include <svx/ucsubset.hxx>
145#include <vcl/vclevent.hxx>
147#include <vcl/svapp.hxx>
148#include <unotools/resmgr.hxx>
149#include <tools/fract.hxx>
150#include <tools/json_writer.hxx>
151#include <svtools/ctrltool.hxx>
152#include <svtools/langtab.hxx>
153#include <vcl/fontcharmap.hxx>
154#ifdef IOS
155#include <vcl/sysdata.hxx>
156#endif
157#include <vcl/virdev.hxx>
158#include <vcl/ImageTree.hxx>
160#include <vcl/dialoghelper.hxx>
161#ifdef _WIN32
163#endif
164#include <unicode/uchar.h>
170#include <unotools/tempfile.hxx>
172#include <osl/module.hxx>
174#include <sfx2/sfxbasemodel.hxx>
175#include <svl/undo.hxx>
176#include <unotools/datetime.hxx>
179#include <vcl/abstdlg.hxx>
183
184// Needed for getUndoManager()
185#include <com/sun/star/document/XUndoManager.hpp>
186#include <com/sun/star/document/XUndoManagerSupplier.hpp>
187#include <com/sun/star/document/XLinkTargetSupplier.hpp>
188#include <editeng/sizeitem.hxx>
189#include <svx/rulritem.hxx>
190#include <svx/pageitem.hxx>
191
192#include <app.hxx>
193
194#include "../app/cmdlineargs.hxx"
195// We also need to hackily be able to start the main libreoffice thread:
196#include "../app/sofficemain.h"
197#include "../app/officeipcthread.hxx"
198#include <lib/init.hxx>
199
201#include "lokclipboard.hxx"
202#include <officecfg/Office/Common.hxx>
203#include <officecfg/Office/Impress.hxx>
204#include <officecfg/Office/Linguistic.hxx>
206#include <svl/ctloptions.hxx>
208#include <svtools/colorcfg.hxx>
209#include <svtools/miscopt.hxx>
213#include <unotools/fltrcfg.hxx>
214#include <unotools/lingucfg.hxx>
216#include <unotools/searchopt.hxx>
219#include <vcl/settings.hxx>
220
221#include <officecfg/Setup.hxx>
222#include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
224
225using namespace css;
226using namespace vcl;
227using namespace desktop;
228using namespace utl;
229
230static LibLibreOffice_Impl *gImpl = nullptr;
231static bool lok_preinit_2_called = false;
232static std::weak_ptr< LibreOfficeKitClass > gOfficeClass;
233static std::weak_ptr< LibreOfficeKitDocumentClass > gDocumentClass;
234
235static void SetLastExceptionMsg(const OUString& s = OUString())
236{
237 SAL_WARN_IF(!s.isEmpty(), "lok", "lok exception '" + s + "'");
238 if (gImpl)
240}
241
242namespace {
243
244struct ExtensionMap
245{
246 const char *extn;
247 const char *filterName;
248};
249
250class TraceEventDumper : public AutoTimer
251{
252 static const int dumpTimeoutMS = 5000;
253
254public:
255 TraceEventDumper() : AutoTimer( "Trace Event dumper" )
256 {
257 SetTimeout(dumpTimeoutMS);
258 Start();
259 }
260
261 virtual void Invoke() override
262 {
263 flushRecordings();
264 }
265
266 static void flushRecordings()
267 {
268 const css::uno::Sequence<OUString> aEvents =
270 OStringBuffer aOutput;
271 for (const auto &s : aEvents)
272 {
273 aOutput.append(OUStringToOString(s, RTL_TEXTENCODING_UTF8)
274 + "\n");
275 }
276 if (aOutput.getLength() > 0)
277 {
278 OString aChunk = aOutput.makeStringAndClear();
279 if (gImpl && gImpl->mpCallback)
280 gImpl->mpCallback(LOK_CALLBACK_PROFILE_FRAME, aChunk.getStr(), gImpl->mpCallbackData);
281 }
282 }
283};
284
285} // unnamed namespace
286
287static TraceEventDumper *traceEventDumper = nullptr;
288
289const ExtensionMap aWriterExtensionMap[] =
290{
291 { "doc", "MS Word 97" },
292 { "docm", "MS Word 2007 XML VBA" },
293 { "docx", "MS Word 2007 XML" },
294 { "fodt", "OpenDocument Text Flat XML" },
295 { "html", "HTML (StarWriter)" },
296 { "odt", "writer8" },
297 { "ott", "writer8_template" },
298 { "pdf", "writer_pdf_Export" },
299 { "epub", "EPUB" },
300 { "rtf", "Rich Text Format" },
301 { "txt", "Text" },
302 { "xhtml", "XHTML Writer File" },
303 { "png", "writer_png_Export" },
304 { "xml", "writer_indexing_export" },
305 { nullptr, nullptr }
306};
307
308const ExtensionMap aCalcExtensionMap[] =
309{
310 { "csv", "Text - txt - csv (StarCalc)" },
311 { "fods", "OpenDocument Spreadsheet Flat XML" },
312 { "html", "HTML (StarCalc)" },
313 { "ods", "calc8" },
314 { "ots", "calc8_template" },
315 { "pdf", "calc_pdf_Export" },
316 { "xhtml", "XHTML Calc File" },
317 { "xls", "MS Excel 97" },
318 { "xlsm", "Calc MS Excel 2007 VBA XML" },
319 { "xlsx", "Calc MS Excel 2007 XML" },
320 { "png", "calc_png_Export" },
321 { nullptr, nullptr }
322};
323
324const ExtensionMap aImpressExtensionMap[] =
325{
326 { "fodp", "OpenDocument Presentation Flat XML" },
327 { "html", "impress_html_Export" },
328 { "odg", "impress8_draw" },
329 { "odp", "impress8" },
330 { "otp", "impress8_template" },
331 { "pdf", "impress_pdf_Export" },
332 { "potm", "Impress MS PowerPoint 2007 XML Template" },
333 { "pot", "MS PowerPoint 97 Vorlage" },
334 { "pptm", "Impress MS PowerPoint 2007 XML VBA" },
335 { "pptx", "Impress MS PowerPoint 2007 XML" },
336 { "pps", "MS PowerPoint 97 Autoplay" },
337 { "ppt", "MS PowerPoint 97" },
338 { "svg", "impress_svg_Export" },
339 { "xhtml", "XHTML Impress File" },
340 { "png", "impress_png_Export"},
341 { nullptr, nullptr }
342};
343
344const ExtensionMap aDrawExtensionMap[] =
345{
346 { "fodg", "draw_ODG_FlatXML" },
347 { "html", "draw_html_Export" },
348 { "odg", "draw8" },
349 { "pdf", "draw_pdf_Export" },
350 { "svg", "draw_svg_Export" },
351 { "xhtml", "XHTML Draw File" },
352 { "png", "draw_png_Export"},
353 { nullptr, nullptr }
354};
355
356static OUString getUString(const char* pString)
357{
358 if (pString == nullptr)
359 return OUString();
360
361 std::string_view sString(pString, strlen(pString));
362 return OStringToOUString(sString, RTL_TEXTENCODING_UTF8);
363}
364
365// Tolerate embedded \0s etc.
366static char *convertOString(const OString &rStr)
367{
368 char* pMemory = static_cast<char*>(malloc(rStr.getLength() + 1));
369 assert(pMemory); // don't tolerate failed allocations.
370 memcpy(pMemory, rStr.getStr(), rStr.getLength() + 1);
371 return pMemory;
372}
373
374static char *convertOUString(std::u16string_view aStr)
375{
376 return convertOString(OUStringToOString(aStr, RTL_TEXTENCODING_UTF8));
377}
378
380static OUString getAbsoluteURL(const char* pURL)
381{
382 OUString aURL(getUString(pURL));
383 if (aURL.isEmpty())
384 return aURL;
385
386 // convert relative paths to absolute ones
387 OUString aWorkingDir;
388 osl_getProcessWorkingDir(&aWorkingDir.pData);
389 if (!aWorkingDir.endsWith("/"))
390 aWorkingDir += "/";
391
392 try
393 {
394 return rtl::Uri::convertRelToAbs(aWorkingDir, aURL);
395 }
396 catch (const rtl::MalformedUriException &)
397 {
398 }
399
400 return OUString();
401}
402
403std::vector<beans::PropertyValue> desktop::jsonToPropertyValuesVector(const char* pJSON)
404{
405 std::vector<beans::PropertyValue> aArguments;
406 if (pJSON && pJSON[0] != '\0')
407 {
409 }
410 return aArguments;
411}
412
413static void extractLinks(const uno::Reference< container::XNameAccess >& xLinks, bool subcontent, tools::JsonWriter& aJson)
414{
415 const uno::Sequence< OUString > aNames( xLinks->getElementNames() );
416
417 const sal_uLong nLinks = aNames.getLength();
418 const OUString* pNames = aNames.getConstArray();
419 static constexpr OUStringLiteral aProp_LinkDisplayName( u"LinkDisplayName" );
420 static constexpr OUStringLiteral aProp_LinkTarget( u"com.sun.star.document.LinkTarget" );
421 bool bIsTarget = false;
422 for( sal_uLong i = 0; i < nLinks; i++ )
423 {
424 uno::Any aAny;
425 OUString aLink( *pNames++ );
426
427 bool bError = false;
428 try
429 {
430 aAny = xLinks->getByName( aLink );
431 }
432 catch(const uno::Exception&)
433 {
434 // if the name of the target was invalid (like empty headings)
435 // no object can be provided
436 bError = true;
437 }
438 if(bError)
439 continue;
440
442 if( aAny >>= xTarget )
443 {
444 try
445 {
446 // get name to display
447 aAny = xTarget->getPropertyValue( aProp_LinkDisplayName );
448 OUString aDisplayName;
449 aAny >>= aDisplayName;
450 OUString aStrDisplayname ( aDisplayName );
451
452 if (subcontent)
453 {
454 aJson.put(aStrDisplayname, aLink);
455 }
456 else
457 {
458 uno::Reference< lang::XServiceInfo > xSI( xTarget, uno::UNO_QUERY );
459 bIsTarget = xSI->supportsService( aProp_LinkTarget );
460
461 if (bIsTarget)
462 {
463 aJson.put(aStrDisplayname, aLink);
464 continue;
465 }
466 else
467 {
468 std::unique_ptr<char[], o3tl::free_delete> pName(convertOUString(aStrDisplayname));
469 auto aNode = aJson.startNode(pName.get());
470
472 if( xLTS.is() )
473 extractLinks(xLTS->getLinks(), true, aJson);
474 }
475 }
476 }
477 catch(...)
478 {
479 SAL_WARN("lok", "extractLinks: Exception");
480 }
481 }
482 }
483}
484
485static void unoAnyToJson(tools::JsonWriter& rJson, std::string_view pNodeName, const uno::Any& anyItem)
486{
487 auto aNode = rJson.startNode(pNodeName);
488 OUString aType = anyItem.getValueTypeName();
489 rJson.put("type", aType);
490
491 if (aType == "string")
492 rJson.put("value", anyItem.get<OUString>());
493 else if (aType == "unsigned long")
494 rJson.put("value", OString::number(anyItem.get<sal_uInt32>()));
495 else if (aType == "long")
496 rJson.put("value", OString::number(anyItem.get<sal_Int32>()));
497 else if (aType == "[]any")
498 {
500 if (anyItem >>= aSeq)
501 {
502 auto valueNode = rJson.startNode("value");
503
504 for (auto i = 0; i < aSeq.getLength(); ++i)
505 {
506 unoAnyToJson(rJson, OString::number(i), aSeq[i]);
507 }
508 }
509 }
510}
511
512static int lcl_getViewId(std::string_view payload);
513
514namespace desktop {
515
517{
518 RectangleAndPart aRet;
519 if (rPayload.startsWith("EMPTY")) // payload starts with "EMPTY"
520 {
523 {
524 int nSeparatorPos = rPayload.indexOf(',', 6);
525 bool bHasMode = nSeparatorPos > 0;
526 if (bHasMode)
527 {
528 aRet.m_nPart = o3tl::toInt32(rPayload.subView(6, nSeparatorPos - 6));
529 assert(rPayload.getLength() > nSeparatorPos);
530 aRet.m_nMode = o3tl::toInt32(rPayload.subView(nSeparatorPos + 1));
531 }
532 else
533 {
534 aRet.m_nPart = o3tl::toInt32(rPayload.subView(6));
535 aRet.m_nMode = 0;
536 }
537 }
538
539 return aRet;
540 }
541
542 // Read '<left>, <top>, <width>, <height>[, <part>, <mode>]'. C++ streams are simpler but slower.
543 const char* pos = rPayload.getStr();
544 const char* end = rPayload.getStr() + rPayload.getLength();
545 tools::Long nLeft = rtl_str_toInt64_WithLength(pos, 10, end - pos);
546 while( *pos != ',' )
547 ++pos;
548 ++pos;
549 assert(pos < end);
550 tools::Long nTop = rtl_str_toInt64_WithLength(pos, 10, end - pos);
551 while( *pos != ',' )
552 ++pos;
553 ++pos;
554 assert(pos < end);
555 tools::Long nWidth = rtl_str_toInt64_WithLength(pos, 10, end - pos);
556 while( *pos != ',' )
557 ++pos;
558 ++pos;
559 assert(pos < end);
560 tools::Long nHeight = rtl_str_toInt64_WithLength(pos, 10, end - pos);
561 tools::Long nPart = INT_MIN;
562 tools::Long nMode = 0;
564 {
565 while( *pos != ',' )
566 ++pos;
567 ++pos;
568 assert(pos < end);
569 nPart = rtl_str_toInt64_WithLength(pos, 10, end - pos);
570
571 while( *pos && *pos != ',' )
572 ++pos;
573 if (*pos)
574 {
575 ++pos;
576 assert(pos < end);
577 nMode = rtl_str_toInt64_WithLength(pos, 10, end - pos);
578 }
579 }
580
581 aRet.m_aRectangle = SanitizedRectangle(nLeft, nTop, nWidth, nHeight);
582 aRet.m_nPart = nPart;
583 aRet.m_nMode = nMode;
584 return aRet;
585}
586
588{
589 if (nWidth <= 0 || nHeight <= 0)
590 return tools::Rectangle();
591
592 // The top-left corner starts at (0, 0).
593 // Anything negative is invalid.
594 if (nLeft < 0)
595 {
596 nWidth += nLeft;
597 nLeft = 0;
598 }
599
600 if (nTop < 0)
601 {
602 nHeight += nTop;
603 nTop = 0;
604 }
605
606 if (nWidth > 0 && nHeight > 0)
607 return tools::Rectangle(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
608 // Else set empty rect.
609 return tools::Rectangle();
610}
611
613{
614 return SanitizedRectangle(rect.Left(), rect.Top(), rect.getOpenWidth(), rect.getOpenHeight());
615}
616
618{
619 if(PayloadString.isEmpty())
620 {
621 // Do to-string conversion on demand, as many calls will get dropped without
622 // needing the string.
623 if(PayloadObject.which() == 1)
625 }
626 return PayloadString;
627}
628
630{
631 PayloadObject = rRectAndPart;
632 PayloadString.clear(); // will be set on demand if needed
633}
634
636{
637 // TODO: In case of unittests, they do not pass invalidations in binary but as text messages.
638 // LO core should preferably always pass binary for performance.
639 if(PayloadObject.which() != 1)
640 PayloadObject = RectangleAndPart::Create(PayloadString);
641 return boost::get<RectangleAndPart>(PayloadObject);
642}
643
644boost::property_tree::ptree& CallbackFlushHandler::CallbackData::setJson(const std::string& payload)
645{
646 boost::property_tree::ptree aTree;
647 std::stringstream aStream(payload);
648 boost::property_tree::read_json(aStream, aTree);
649
650 // Let boost normalize the payload so it always matches the cache.
651 setJson(aTree);
652
653 // Return reference to the cached object.
654 return boost::get<boost::property_tree::ptree>(PayloadObject);
655}
656
657void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree& rTree)
658{
659 std::stringstream aJSONStream;
660 constexpr bool bPretty = false; // Don't waste time and bloat logs.
661 boost::property_tree::write_json(aJSONStream, rTree, bPretty);
662 PayloadString = OString(o3tl::trim(aJSONStream.str()));
663
664 PayloadObject = rTree;
665}
666
667const boost::property_tree::ptree& CallbackFlushHandler::CallbackData::getJson() const
668{
669 assert(PayloadObject.which() == 2);
670 return boost::get<boost::property_tree::ptree>(PayloadObject);
671}
672
674{
675 if (isCached())
676 {
677 assert(PayloadObject.which() == 3);
678 return boost::get<int>(PayloadObject);
679 }
680 return lcl_getViewId(getPayload());
681}
682
684{
685 switch (PayloadObject.which())
686 {
687 // Not cached.
688 case 0:
689 return true;
690
691 // RectangleAndPart.
692 case 1:
693 return getRectangleAndPart().toString().getStr() == getPayload();
694
695 // Json.
696 case 2:
697 {
698 std::stringstream aJSONStream;
699 boost::property_tree::write_json(aJSONStream, getJson(), false);
700 const std::string aExpected = boost::trim_copy(aJSONStream.str());
701 return getPayload() == std::string_view(aExpected);
702 }
703
704 // View id.
705 case 3:
706 return getViewId() == lcl_getViewId( getPayload());
707
708 default:
709 assert(!"Unknown variant type; please add an entry to validate.");
710 }
711
712 return false;
713}
714
715} // namespace desktop
716
717static bool lcl_isViewCallbackType(const int type)
718{
719 switch (type)
720 {
721 case LOK_CALLBACK_CELL_VIEW_CURSOR:
722 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
723 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
724 case LOK_CALLBACK_TEXT_VIEW_SELECTION:
725 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
726 return true;
727
728 default:
729 return false;
730 }
731}
732
733static bool isUpdatedType(int type)
734{
735 switch (type)
736 {
737 case LOK_CALLBACK_TEXT_SELECTION:
738 case LOK_CALLBACK_TEXT_SELECTION_START:
739 case LOK_CALLBACK_TEXT_SELECTION_END:
740 return true;
741 default:
742 return false;
743 }
744}
745
746static bool isUpdatedTypePerViewId(int type)
747{
748 switch (type)
749 {
750 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
751 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
752 case LOK_CALLBACK_TEXT_VIEW_SELECTION:
753 return true;
754 default:
755 return false;
756 }
757}
758
759static int lcl_getViewId(std::string_view payload)
760{
761 // this is a cheap way how to get the viewId from a JSON message; proper
762 // parsing is terribly expensive, and we just need the viewId here
763 size_t viewIdPos = payload.find("viewId");
764 if (viewIdPos == std::string::npos)
765 return 0;
766
767 size_t numberPos = payload.find(":", viewIdPos + 6);
768 if (numberPos == std::string::npos)
769 return 0;
770
771 for (++numberPos; numberPos < payload.length(); ++numberPos)
772 {
773 if (payload[numberPos] == ',' || payload[numberPos] == '}' || (payload[numberPos] >= '0' && payload[numberPos] <= '9'))
774 break;
775 }
776
777 if (numberPos < payload.length() && payload[numberPos] >= '0' && payload[numberPos] <= '9')
778 return o3tl::toInt32(payload.substr(numberPos));
779
780 return 0;
781}
782
783namespace {
784
785std::string extractCertificate(const std::string & certificate)
786{
787 const std::string header("-----BEGIN CERTIFICATE-----");
788 const std::string footer("-----END CERTIFICATE-----");
789
790 std::string result;
791
792 size_t pos1 = certificate.find(header);
793 if (pos1 == std::string::npos)
794 return result;
795
796 size_t pos2 = certificate.find(footer, pos1 + 1);
797 if (pos2 == std::string::npos)
798 return result;
799
800 pos1 = pos1 + header.length();
801 pos2 = pos2 - pos1;
802
803 return certificate.substr(pos1, pos2);
804}
805
806std::string extractPrivateKey(const std::string & privateKey)
807{
808 const std::string header("-----BEGIN PRIVATE KEY-----");
809 const std::string footer("-----END PRIVATE KEY-----");
810
811 std::string result;
812
813 size_t pos1 = privateKey.find(header);
814 if (pos1 == std::string::npos)
815 return result;
816
817 size_t pos2 = privateKey.find(footer, pos1 + 1);
818 if (pos2 == std::string::npos)
819 return result;
820
821 pos1 = pos1 + header.length();
822 pos2 = pos2 - pos1;
823
824 return privateKey.substr(pos1, pos2);
825}
826
827OUString lcl_getCurrentDocumentMimeType(const LibLODocument_Impl* pDocument)
828{
829 SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
830 if (!pBaseModel)
831 return "";
832
833 SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
834 if (!pObjectShell)
835 return "";
836
837 SfxMedium* pMedium = pObjectShell->GetMedium();
838 if (!pMedium)
839 return "";
840
841 auto pFilter = pMedium->GetFilter();
842 if (!pFilter)
843 return "";
844
845 return pFilter->GetMimeType();
846}
847
848// Gets an undo manager to enter and exit undo context. Needed by ToggleOrientation
849css::uno::Reference< css::document::XUndoManager > getUndoManager( const css::uno::Reference< css::frame::XFrame >& rxFrame )
850{
851 const css::uno::Reference< css::frame::XController >& xController = rxFrame->getController();
852 if ( xController.is() )
853 {
854 const css::uno::Reference< css::frame::XModel >& xModel = xController->getModel();
855 if ( xModel.is() )
856 {
857 const css::uno::Reference< css::document::XUndoManagerSupplier > xSuppUndo( xModel, css::uno::UNO_QUERY_THROW );
858 return css::uno::Reference< css::document::XUndoManager >( xSuppUndo->getUndoManager(), css::uno::UNO_SET_THROW );
859 }
860 }
861
862 return css::uno::Reference< css::document::XUndoManager > ();
863}
864
865// Adjusts page margins for Writer doc. Needed by ToggleOrientation
866void ExecuteMarginLRChange(
867 const tools::Long nPageLeftMargin,
868 const tools::Long nPageRightMargin,
869 SvxLongLRSpaceItem* pPageLRMarginItem)
870{
871 pPageLRMarginItem->SetLeft( nPageLeftMargin );
872 pPageLRMarginItem->SetRight( nPageRightMargin );
873 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_LRSPACE,
874 SfxCallMode::RECORD, { pPageLRMarginItem });
875}
876
877// Adjusts page margins for Writer doc. Needed by ToggleOrientation
878void ExecuteMarginULChange(
879 const tools::Long nPageTopMargin,
880 const tools::Long nPageBottomMargin,
881 SvxLongULSpaceItem* pPageULMarginItem)
882{
883 pPageULMarginItem->SetUpper( nPageTopMargin );
884 pPageULMarginItem->SetLower( nPageBottomMargin );
885 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_ULSPACE,
886 SfxCallMode::RECORD, { pPageULMarginItem });
887}
888
889// Main function which toggles page orientation of the Writer doc. Needed by ToggleOrientation
890void ExecuteOrientationChange()
891{
893 if (!pViewFrm)
894 return;
895
896 std::unique_ptr<SvxPageItem> pPageItem(new SvxPageItem(SID_ATTR_PAGE));
897
898 // 1mm in twips rounded
899 // This should be in sync with MINBODY in sw/source/uibase/sidebar/PageMarginControl.hxx
901
902 css::uno::Reference< css::document::XUndoManager > mxUndoManager(
903 getUndoManager( pViewFrm->GetFrame().GetFrameInterface() ) );
904
905 if ( mxUndoManager.is() )
906 mxUndoManager->enterUndoContext( "" );
907
908
909 const SvxSizeItem* pSizeItem;
910 pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_SIZE, pSizeItem);
911 std::unique_ptr<SvxSizeItem> pPageSizeItem(pSizeItem->Clone());
912
913 const SvxLongLRSpaceItem* pLRSpaceItem;
914 pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_LRSPACE, pLRSpaceItem);
915 std::unique_ptr<SvxLongLRSpaceItem> pPageLRMarginItem(pLRSpaceItem->Clone());
916
917 const SvxLongULSpaceItem* pULSpaceItem;
918 pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_ULSPACE, pULSpaceItem);
919 std::unique_ptr<SvxLongULSpaceItem> pPageULMarginItem(pULSpaceItem->Clone());
920
921 {
922 bool bIsLandscape = false;
923 if ( pPageSizeItem->GetSize().Width() > pPageSizeItem->GetSize().Height())
924 bIsLandscape = true;
925
926 // toggle page orientation
927 pPageItem->SetLandscape(!bIsLandscape);
928
929
930 // swap the width and height of the page size
931 const tools::Long nRotatedWidth = pPageSizeItem->GetSize().Height();
932 const tools::Long nRotatedHeight = pPageSizeItem->GetSize().Width();
933 pPageSizeItem->SetSize(Size(nRotatedWidth, nRotatedHeight));
934
935
936 // apply changed attributes
938 {
939 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_SIZE,
940 SfxCallMode::RECORD, { pPageSizeItem.get(), pPageItem.get() });
941 }
942 }
943
944
945 // check, if margin values still fit to the changed page size.
946 // if not, adjust margin values
947 {
948 const tools::Long nML = pPageLRMarginItem->GetLeft();
949 const tools::Long nMR = pPageLRMarginItem->GetRight();
950 const tools::Long nTmpPW = nML + nMR + MINBODY;
951
952 const tools::Long nPW = pPageSizeItem->GetSize().Width();
953
954 if ( nTmpPW > nPW )
955 {
956 if ( nML <= nMR )
957 {
958 ExecuteMarginLRChange( pPageLRMarginItem->GetLeft(), nMR - (nTmpPW - nPW ), pPageLRMarginItem.get() );
959 }
960 else
961 {
962 ExecuteMarginLRChange( nML - (nTmpPW - nPW ), pPageLRMarginItem->GetRight(), pPageLRMarginItem.get() );
963 }
964 }
965
966 const tools::Long nMT = pPageULMarginItem->GetUpper();
967 const tools::Long nMB = pPageULMarginItem->GetLower();
968 const tools::Long nTmpPH = nMT + nMB + MINBODY;
969
970 const tools::Long nPH = pPageSizeItem->GetSize().Height();
971
972 if ( nTmpPH > nPH )
973 {
974 if ( nMT <= nMB )
975 {
976 ExecuteMarginULChange( pPageULMarginItem->GetUpper(), nMB - ( nTmpPH - nPH ), pPageULMarginItem.get() );
977 }
978 else
979 {
980 ExecuteMarginULChange( nMT - ( nTmpPH - nPH ), pPageULMarginItem->GetLower(), pPageULMarginItem.get() );
981 }
982 }
983 }
984
985 if ( mxUndoManager.is() )
986 mxUndoManager->leaveUndoContext();
987}
988
989void setupSidebar(std::u16string_view sidebarDeckId = u"")
990{
991 SfxViewShell* pViewShell = SfxViewShell::Current();
992 SfxViewFrame* pViewFrame = pViewShell ? &pViewShell->GetViewFrame() : nullptr;
993 if (pViewFrame)
994 {
995 if (!pViewFrame->GetChildWindow(SID_SIDEBAR))
996 pViewFrame->SetChildWindow(SID_SIDEBAR, false /* create it */, true /* focus */);
997
998 pViewFrame->ShowChildWindow(SID_SIDEBAR, true);
999
1000 // Force synchronous population of panels
1001 SfxChildWindow *pChild = pViewFrame->GetChildWindow(SID_SIDEBAR);
1002 if (!pChild)
1003 return;
1004
1005 auto pDockingWin = dynamic_cast<sfx2::sidebar::SidebarDockingWindow *>(pChild->GetWindow());
1006 if (!pDockingWin)
1007 return;
1008
1009 pViewFrame->ShowChildWindow( SID_SIDEBAR );
1010
1012 = pDockingWin->GetOrCreateSidebarController();
1013
1014 xController->FadeIn();
1015 xController->RequestOpenDeck();
1016
1017 if (!sidebarDeckId.empty())
1018 {
1019 xController->SwitchToDeck(sidebarDeckId);
1020 }
1021 else
1022 {
1023 xController->SwitchToDefaultDeck();
1024 }
1025
1026 pDockingWin->SyncUpdate();
1027 }
1028 else
1029 SetLastExceptionMsg("No view shell or sidebar");
1030}
1031
1032void hideSidebar()
1033{
1034 SfxViewShell* pViewShell = SfxViewShell::Current();
1035 SfxViewFrame* pViewFrame = pViewShell ? &pViewShell->GetViewFrame() : nullptr;
1036 if (pViewFrame)
1037 pViewFrame->SetChildWindow(SID_SIDEBAR, false , false );
1038 else
1039 SetLastExceptionMsg("No view shell or sidebar");
1040}
1041
1042} // end anonymous namespace
1043
1044// Could be anonymous in principle, but for the unit testing purposes, we
1045// declare it in init.hxx.
1046OUString desktop::extractParameter(OUString& rOptions, std::u16string_view rName)
1047{
1048 OUString aValue;
1049
1050 OUString aNameEquals(OUString::Concat(rName) + "=");
1051 OUString aCommaNameEquals(OUString::Concat(",") + rName + "=");
1052
1053 int nIndex = -1;
1054 if (rOptions.startsWith(aNameEquals))
1055 {
1056 size_t nLen = aNameEquals.getLength();
1057 int nComma = rOptions.indexOf(",", nLen);
1058 if (nComma >= 0)
1059 {
1060 aValue = rOptions.copy(nLen, nComma - nLen);
1061 rOptions = rOptions.copy(nComma + 1);
1062 }
1063 else
1064 {
1065 aValue = rOptions.copy(nLen);
1066 rOptions.clear();
1067 }
1068 }
1069 else if ((nIndex = rOptions.indexOf(aCommaNameEquals)) >= 0)
1070 {
1071 size_t nLen = aCommaNameEquals.getLength();
1072 int nComma = rOptions.indexOf(",", nIndex + nLen);
1073 if (nComma >= 0)
1074 {
1075 aValue = rOptions.copy(nIndex + nLen, nComma - nIndex - nLen);
1076 rOptions = OUString::Concat(rOptions.subView(0, nIndex)) + rOptions.subView(nComma);
1077 }
1078 else
1079 {
1080 aValue = rOptions.copy(nIndex + nLen);
1081 rOptions = rOptions.copy(0, nIndex);
1082 }
1083 }
1084
1085 return aValue;
1086}
1087
1088extern "C"
1089{
1090
1091static void doc_destroy(LibreOfficeKitDocument* pThis);
1092static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* pUrl, const char* pFormat, const char* pFilterOptions);
1093static int doc_getDocumentType(LibreOfficeKitDocument* pThis);
1094static int doc_getParts(LibreOfficeKitDocument* pThis);
1095static char* doc_getPartPageRectangles(LibreOfficeKitDocument* pThis);
1096static int doc_getPart(LibreOfficeKitDocument* pThis);
1097static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart);
1098static void doc_selectPart(LibreOfficeKitDocument* pThis, int nPart, int nSelect);
1099static void doc_moveSelectedParts(LibreOfficeKitDocument* pThis, int nPosition, bool bDuplicate);
1100static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart);
1101static void doc_setPartMode(LibreOfficeKitDocument* pThis, int nPartMode);
1102static int doc_getEditMode(LibreOfficeKitDocument* pThis);
1103static void doc_paintTile(LibreOfficeKitDocument* pThis,
1104 unsigned char* pBuffer,
1105 const int nCanvasWidth, const int nCanvasHeight,
1106 const int nTilePosX, const int nTilePosY,
1107 const int nTileWidth, const int nTileHeight);
1108static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
1109 unsigned char* pBuffer,
1110 const int nPart,
1111 const int nMode,
1112 const int nCanvasWidth, const int nCanvasHeight,
1113 const int nTilePosX, const int nTilePosY,
1114 const int nTileWidth, const int nTileHeight);
1115static int doc_getTileMode(LibreOfficeKitDocument* pThis);
1116static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
1117 long* pWidth,
1118 long* pHeight);
1119static void doc_getDataArea(LibreOfficeKitDocument* pThis,
1120 long nTab,
1121 long* pCol,
1122 long* pRow);
1123static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
1124 const char* pArguments);
1125
1126static void doc_registerCallback(LibreOfficeKitDocument* pThis,
1127 LibreOfficeKitCallback pCallback,
1128 void* pData);
1129static void doc_postKeyEvent(LibreOfficeKitDocument* pThis,
1130 int nType,
1131 int nCharCode,
1132 int nKeyCode);
1133static void doc_setBlockedCommandList(LibreOfficeKitDocument* pThis,
1134 int nViewId,
1135 const char* blockedCommandList);
1136
1137static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis,
1138 unsigned nWindowId,
1139 int nType,
1140 const char* pText);
1141static void doc_removeTextContext(LibreOfficeKitDocument* pThis,
1142 unsigned nLOKWindowId,
1143 int nCharBefore,
1144 int nCharAfter);
1145static void doc_sendDialogEvent(LibreOfficeKitDocument* pThis,
1146 unsigned long long int nLOKWindowId,
1147 const char* pArguments);
1148static void doc_postWindowKeyEvent(LibreOfficeKitDocument* pThis,
1149 unsigned nLOKWindowId,
1150 int nType,
1151 int nCharCode,
1152 int nKeyCode);
1153static void doc_postMouseEvent (LibreOfficeKitDocument* pThis,
1154 int nType,
1155 int nX,
1156 int nY,
1157 int nCount,
1158 int nButtons,
1159 int nModifier);
1160static void doc_postWindowMouseEvent (LibreOfficeKitDocument* pThis,
1161 unsigned nLOKWindowId,
1162 int nType,
1163 int nX,
1164 int nY,
1165 int nCount,
1166 int nButtons,
1167 int nModifier);
1168static void doc_postWindowGestureEvent(LibreOfficeKitDocument* pThis,
1169 unsigned nLOKWindowId,
1170 const char* pType,
1171 int nX,
1172 int nY,
1173 int nOffset);
1174static void doc_postUnoCommand(LibreOfficeKitDocument* pThis,
1175 const char* pCommand,
1176 const char* pArguments,
1177 bool bNotifyWhenFinished);
1178static void doc_setWindowTextSelection(LibreOfficeKitDocument* pThis,
1179 unsigned nLOKWindowId,
1180 bool swap,
1181 int nX,
1182 int nY);
1183static void doc_setTextSelection (LibreOfficeKitDocument* pThis,
1184 int nType,
1185 int nX,
1186 int nY);
1187static char* doc_getTextSelection(LibreOfficeKitDocument* pThis,
1188 const char* pMimeType,
1189 char** pUsedMimeType);
1190static int doc_getSelectionType(LibreOfficeKitDocument* pThis);
1191static int doc_getSelectionTypeAndText(LibreOfficeKitDocument* pThis,
1192 const char* pMimeType,
1193 char** pText,
1194 char** pUsedMimeType);
1195static int doc_getClipboard (LibreOfficeKitDocument* pThis,
1196 const char **pMimeTypes,
1197 size_t *pOutCount,
1198 char ***pOutMimeTypes,
1199 size_t **pOutSizes,
1200 char ***pOutStreams);
1201static int doc_setClipboard (LibreOfficeKitDocument* pThis,
1202 const size_t nInCount,
1203 const char **pInMimeTypes,
1204 const size_t *pInSizes,
1205 const char **pInStreams);
1206static bool doc_paste(LibreOfficeKitDocument* pThis,
1207 const char* pMimeType,
1208 const char* pData,
1209 size_t nSize);
1210static void doc_setGraphicSelection (LibreOfficeKitDocument* pThis,
1211 int nType,
1212 int nX,
1213 int nY);
1214static void doc_resetSelection (LibreOfficeKitDocument* pThis);
1215static char* doc_getCommandValues(LibreOfficeKitDocument* pThis, const char* pCommand);
1216static void doc_setClientZoom(LibreOfficeKitDocument* pThis,
1217 int nTilePixelWidth,
1218 int nTilePixelHeight,
1219 int nTileTwipWidth,
1220 int nTileTwipHeight);
1221static void doc_setClientVisibleArea(LibreOfficeKitDocument* pThis, int nX, int nY, int nWidth, int nHeight);
1222static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int nLevel, int nIndex, bool bHidden);
1223static int doc_createView(LibreOfficeKitDocument* pThis);
1224static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis, const char* pOptions);
1225static void doc_destroyView(LibreOfficeKitDocument* pThis, int nId);
1226static void doc_setView(LibreOfficeKitDocument* pThis, int nId);
1227static int doc_getView(LibreOfficeKitDocument* pThis);
1228static int doc_getViewsCount(LibreOfficeKitDocument* pThis);
1229static bool doc_getViewIds(LibreOfficeKitDocument* pThis, int* pArray, size_t nSize);
1230static void doc_setViewLanguage(LibreOfficeKitDocument* pThis, int nId, const char* language);
1231static unsigned char* doc_renderFontOrientation(LibreOfficeKitDocument* pThis,
1232 const char *pFontName,
1233 const char *pChar,
1234 int* pFontWidth,
1235 int* pFontHeight,
1236 int pOrientation);
1237static unsigned char* doc_renderFont(LibreOfficeKitDocument* pThis,
1238 const char *pFontName,
1239 const char *pChar,
1240 int* pFontWidth,
1241 int* pFontHeight);
1242static char* doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart);
1243
1244static void doc_paintWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
1245 const int nX, const int nY,
1246 const int nWidth, const int nHeight);
1247
1248static void doc_paintWindowDPI(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
1249 const int nX, const int nY,
1250 const int nWidth, const int nHeight,
1251 const double fDPIScale);
1252
1253static void doc_paintWindowForView(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
1254 const int nX, const int nY,
1255 const int nWidth, const int nHeight,
1256 const double fDPIScale, int viewId);
1257
1258static void doc_postWindow(LibreOfficeKitDocument* pThis, unsigned
1259 nLOKWindowId, int nAction, const char* pData);
1260
1261static char* doc_getPartInfo(LibreOfficeKitDocument* pThis, int nPart);
1262
1263static bool doc_insertCertificate(LibreOfficeKitDocument* pThis,
1264 const unsigned char* pCertificateBinary,
1265 const int nCertificateBinarySize,
1266 const unsigned char* pPrivateKeyBinary,
1267 const int nPrivateKeyBinarySize);
1268
1269static bool doc_addCertificate(LibreOfficeKitDocument* pThis,
1270 const unsigned char* pCertificateBinary,
1271 const int nCertificateBinarySize);
1272
1273static int doc_getSignatureState(LibreOfficeKitDocument* pThis);
1274
1275static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOutput);
1276
1277static void doc_resizeWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
1278 const int nWidth, const int nHeight);
1279
1280static void doc_completeFunction(LibreOfficeKitDocument* pThis, const char*);
1281
1282
1283static void doc_sendFormFieldEvent(LibreOfficeKitDocument* pThis,
1284 const char* pArguments);
1285
1286static bool doc_renderSearchResult(LibreOfficeKitDocument* pThis,
1287 const char* pSearchResult, unsigned char** pBitmapBuffer,
1288 int* pWidth, int* pHeight, size_t* pByteSize);
1289
1290static void doc_sendContentControlEvent(LibreOfficeKitDocument* pThis, const char* pArguments);
1291
1292static void doc_setViewTimezone(LibreOfficeKitDocument* pThis, int nId, const char* timezone);
1293
1294static void doc_setAccessibilityState(LibreOfficeKitDocument* pThis, int nId, bool bEnabled);
1295
1296static char* doc_getA11yFocusedParagraph(LibreOfficeKitDocument* pThis);
1297
1298static int doc_getA11yCaretPosition(LibreOfficeKitDocument* pThis);
1299} // extern "C"
1300
1301namespace {
1302ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
1303{
1304 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
1305 return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get());
1306}
1307
1308#ifndef IOS
1309
1310/*
1311 * Unfortunately clipboard creation using UNO is insanely baroque.
1312 * we also need to ensure that this works for the first view which
1313 * has no clear 'createView' called for it (unfortunately).
1314 */
1315rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocument *pThis)
1316{
1317 ITiledRenderable* pDoc = getTiledRenderable(pThis);
1319
1320 SAL_INFO("lok", "Set to clipboard for view " << xClip.get());
1321 // FIXME: using a hammer here - should not be necessary if all tests used createView.
1322 pDoc->setClipboard(uno::Reference<datatransfer::clipboard::XClipboard>(xClip->getXI(), UNO_QUERY));
1323
1324 return xClip;
1325}
1326
1327#endif
1328
1329const vcl::Font* FindFont(std::u16string_view rFontName)
1330{
1332 if (!pDocSh)
1333 return nullptr;
1334 const SvxFontListItem* pFonts
1335 = static_cast<const SvxFontListItem*>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
1336 const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
1337 if (pList && !rFontName.empty())
1338 if (sal_Handle hMetric = pList->GetFirstFontMetric(rFontName))
1339 return &FontList::GetFontMetric(hMetric);
1340 return nullptr;
1341}
1342
1343vcl::Font FindFont_FallbackToDefault(std::u16string_view rFontName)
1344{
1345 if (auto pFound = FindFont(rFontName))
1346 return *pFound;
1347
1348 return OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE, LANGUAGE_NONE,
1349 GetDefaultFontFlags::NONE);
1350}
1351
1352int getDocumentType (LibreOfficeKitDocument* pThis)
1353{
1355
1356 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
1357
1358 try
1359 {
1360 uno::Reference<lang::XServiceInfo> xDocument(pDocument->mxComponent, uno::UNO_QUERY_THROW);
1361
1362 if (xDocument->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
1363 {
1364 return LOK_DOCTYPE_SPREADSHEET;
1365 }
1366 else if (xDocument->supportsService("com.sun.star.presentation.PresentationDocument"))
1367 {
1368 return LOK_DOCTYPE_PRESENTATION;
1369 }
1370 else if (xDocument->supportsService("com.sun.star.drawing.DrawingDocument"))
1371 {
1372 return LOK_DOCTYPE_DRAWING;
1373 }
1374 else if (xDocument->supportsService("com.sun.star.text.TextDocument") || xDocument->supportsService("com.sun.star.text.WebDocument"))
1375 {
1376 return LOK_DOCTYPE_TEXT;
1377 }
1378 else
1379 {
1380 SetLastExceptionMsg("unknown document type");
1381 }
1382 }
1383 catch (const uno::Exception& exception)
1384 {
1385 SetLastExceptionMsg("exception: " + exception.Message);
1386 }
1387 return LOK_DOCTYPE_OTHER;
1388}
1389
1390} // anonymous namespace
1391
1393 : mxComponent(std::move(xComponent))
1394 , mnDocumentId(nDocumentId)
1395{
1396 assert(nDocumentId != -1 && "Cannot set mnDocumentId to -1");
1397
1399 if (!m_pDocumentClass)
1400 {
1401 m_pDocumentClass = std::make_shared<LibreOfficeKitDocumentClass>();
1402
1403 m_pDocumentClass->nSize = sizeof(LibreOfficeKitDocumentClass);
1404
1405 m_pDocumentClass->destroy = doc_destroy;
1406 m_pDocumentClass->saveAs = doc_saveAs;
1407 m_pDocumentClass->getDocumentType = doc_getDocumentType;
1408 m_pDocumentClass->getParts = doc_getParts;
1409 m_pDocumentClass->getPartPageRectangles = doc_getPartPageRectangles;
1410 m_pDocumentClass->getPart = doc_getPart;
1411 m_pDocumentClass->setPart = doc_setPart;
1412 m_pDocumentClass->selectPart = doc_selectPart;
1413 m_pDocumentClass->moveSelectedParts = doc_moveSelectedParts;
1414 m_pDocumentClass->getPartName = doc_getPartName;
1415 m_pDocumentClass->setPartMode = doc_setPartMode;
1416 m_pDocumentClass->getEditMode = doc_getEditMode;
1417 m_pDocumentClass->paintTile = doc_paintTile;
1418 m_pDocumentClass->paintPartTile = doc_paintPartTile;
1419 m_pDocumentClass->getTileMode = doc_getTileMode;
1420 m_pDocumentClass->getDocumentSize = doc_getDocumentSize;
1421 m_pDocumentClass->getDataArea = doc_getDataArea;
1422 m_pDocumentClass->initializeForRendering = doc_initializeForRendering;
1423 m_pDocumentClass->registerCallback = doc_registerCallback;
1424 m_pDocumentClass->postKeyEvent = doc_postKeyEvent;
1425 m_pDocumentClass->postWindowExtTextInputEvent = doc_postWindowExtTextInputEvent;
1426 m_pDocumentClass->removeTextContext = doc_removeTextContext;
1427 m_pDocumentClass->postWindowKeyEvent = doc_postWindowKeyEvent;
1428 m_pDocumentClass->postMouseEvent = doc_postMouseEvent;
1429 m_pDocumentClass->postWindowMouseEvent = doc_postWindowMouseEvent;
1430 m_pDocumentClass->sendDialogEvent = doc_sendDialogEvent;
1431 m_pDocumentClass->postUnoCommand = doc_postUnoCommand;
1432 m_pDocumentClass->setTextSelection = doc_setTextSelection;
1433 m_pDocumentClass->setWindowTextSelection = doc_setWindowTextSelection;
1434 m_pDocumentClass->getTextSelection = doc_getTextSelection;
1435 m_pDocumentClass->getSelectionType = doc_getSelectionType;
1436 m_pDocumentClass->getSelectionTypeAndText = doc_getSelectionTypeAndText;
1437 m_pDocumentClass->getClipboard = doc_getClipboard;
1438 m_pDocumentClass->setClipboard = doc_setClipboard;
1439 m_pDocumentClass->paste = doc_paste;
1440 m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection;
1441 m_pDocumentClass->resetSelection = doc_resetSelection;
1442 m_pDocumentClass->getCommandValues = doc_getCommandValues;
1443 m_pDocumentClass->setClientZoom = doc_setClientZoom;
1444 m_pDocumentClass->setClientVisibleArea = doc_setClientVisibleArea;
1445 m_pDocumentClass->setOutlineState = doc_setOutlineState;
1446
1447 m_pDocumentClass->createView = doc_createView;
1448 m_pDocumentClass->destroyView = doc_destroyView;
1449 m_pDocumentClass->setView = doc_setView;
1450 m_pDocumentClass->getView = doc_getView;
1451 m_pDocumentClass->getViewsCount = doc_getViewsCount;
1452 m_pDocumentClass->getViewIds = doc_getViewIds;
1453
1454 m_pDocumentClass->renderFont = doc_renderFont;
1455 m_pDocumentClass->renderFontOrientation = doc_renderFontOrientation;
1456 m_pDocumentClass->getPartHash = doc_getPartHash;
1457
1458 m_pDocumentClass->paintWindow = doc_paintWindow;
1459 m_pDocumentClass->paintWindowDPI = doc_paintWindowDPI;
1460 m_pDocumentClass->paintWindowForView = doc_paintWindowForView;
1461 m_pDocumentClass->postWindow = doc_postWindow;
1462 m_pDocumentClass->resizeWindow = doc_resizeWindow;
1463
1464 m_pDocumentClass->setViewLanguage = doc_setViewLanguage;
1465
1466 m_pDocumentClass->getPartInfo = doc_getPartInfo;
1467
1468 m_pDocumentClass->insertCertificate = doc_insertCertificate;
1469 m_pDocumentClass->addCertificate = doc_addCertificate;
1470 m_pDocumentClass->getSignatureState = doc_getSignatureState;
1471
1472 m_pDocumentClass->renderShapeSelection = doc_renderShapeSelection;
1473 m_pDocumentClass->postWindowGestureEvent = doc_postWindowGestureEvent;
1474
1475 m_pDocumentClass->createViewWithOptions = doc_createViewWithOptions;
1476 m_pDocumentClass->completeFunction = doc_completeFunction;
1477
1478 m_pDocumentClass->sendFormFieldEvent = doc_sendFormFieldEvent;
1479 m_pDocumentClass->renderSearchResult = doc_renderSearchResult;
1480
1481 m_pDocumentClass->setBlockedCommandList = doc_setBlockedCommandList;
1482
1483 m_pDocumentClass->sendContentControlEvent = doc_sendContentControlEvent;
1484
1485 m_pDocumentClass->setViewTimezone = doc_setViewTimezone;
1486
1487 m_pDocumentClass->setAccessibilityState = doc_setAccessibilityState;
1488
1489 m_pDocumentClass->getA11yFocusedParagraph = doc_getA11yFocusedParagraph;
1490 m_pDocumentClass->getA11yCaretPosition = doc_getA11yCaretPosition;
1491
1493 }
1494 pClass = m_pDocumentClass.get();
1495
1496#ifndef IOS
1497 forceSetClipboardForCurrentView(this);
1498#endif
1499}
1500
1502{
1503 try
1504 {
1505 mxComponent->dispose();
1506 }
1507 catch (const css::lang::DisposedException&)
1508 {
1509 TOOLS_WARN_EXCEPTION("lok", "failed to dispose document");
1510 }
1511}
1512
1513static OUString getGenerator()
1514{
1515 OUString sGenerator(
1516 Translate::ExpandVariables("%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)"));
1517 OUString os("$_OS");
1518 ::rtl::Bootstrap::expandMacros(os);
1519 return sGenerator.replaceFirst("%1", os);
1520}
1521
1522extern "C" {
1523
1525 : Timer( "lokit timer callback" )
1526 , mHandler( handler )
1527{
1528 // A second timer with higher priority, it'll ensure we flush in reasonable time if we get too busy
1529 // to get POST_PAINT priority processing. Otherwise it could take a long time to flush.
1530 SetPriority(TaskPriority::DEFAULT);
1531 SetTimeout( 100 ); // 100 ms
1532}
1533
1535{
1536 mHandler->Invoke();
1537}
1538
1539// One of these is created per view to handle events cf. doc_registerCallback
1540CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, LibreOfficeKitCallback pCallback, void* pData)
1541 : Idle( "lokit idle callback" ),
1542 m_pDocument(pDocument),
1543 m_pCallback(pCallback),
1544 m_pData(pData),
1546 m_TimeoutIdle( this )
1547{
1548 SetPriority(TaskPriority::POST_PAINT);
1549
1550 // Add the states that are safe to skip duplicates on, even when
1551 // not consequent (i.e. do no emit them if unchanged from last).
1552 m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL");
1553 m_states.emplace(LOK_CALLBACK_GRAPHIC_SELECTION, "NIL");
1554 m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL");
1555 m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL");
1556 m_states.emplace(LOK_CALLBACK_MOUSE_POINTER, "NIL");
1557 m_states.emplace(LOK_CALLBACK_CELL_CURSOR, "NIL");
1558 m_states.emplace(LOK_CALLBACK_CELL_FORMULA, "NIL");
1559 m_states.emplace(LOK_CALLBACK_CELL_ADDRESS, "NIL");
1560 m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL");
1561 m_states.emplace(LOK_CALLBACK_SET_PART, "NIL");
1562 m_states.emplace(LOK_CALLBACK_TABLE_SELECTED, "NIL");
1563 m_states.emplace(LOK_CALLBACK_TAB_STOP_LIST, "NIL");
1564 m_states.emplace(LOK_CALLBACK_RULER_UPDATE, "NIL");
1565 m_states.emplace(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE, "NIL");
1566}
1567
1569{
1570 Stop();
1571}
1572
1573CallbackFlushHandler::queue_type2::iterator CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::iterator pos)
1574{
1575 int delta = std::distance(m_queue1.begin(), pos);
1576 return m_queue2.begin() + delta;
1577}
1578
1579CallbackFlushHandler::queue_type2::reverse_iterator CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::reverse_iterator pos)
1580{
1581 int delta = std::distance(m_queue1.rbegin(), pos);
1582 return m_queue2.rbegin() + delta;
1583}
1584
1585void CallbackFlushHandler::setUpdatedType( int nType, bool value )
1586{
1587 assert(isUpdatedType(nType));
1588 if( m_updatedTypes.size() <= o3tl::make_unsigned( nType ))
1589 m_updatedTypes.resize( nType + 1 ); // new are default-constructed, i.e. false
1591 if(value)
1592 startTimer();
1593}
1594
1596{
1597 setUpdatedType( nType, false );
1598}
1599
1600void CallbackFlushHandler::setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value )
1601{
1603 std::vector<PerViewIdData>& types = m_updatedTypesPerViewId[ nViewId ];
1604 if( types.size() <= o3tl::make_unsigned( nType ))
1605 types.resize( nType + 1 ); // new are default-constructed, i.e. 'set' is false
1606 types[ nType ] = PerViewIdData{ value, nSourceViewId };
1607 if(value)
1608 startTimer();
1609}
1610
1612{
1614 bool allViewIds = false;
1615 // Handle specially messages that do not have viewId for backwards compatibility.
1616 if( nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
1617 allViewIds = true;
1618 if( !allViewIds )
1619 {
1620 setUpdatedTypePerViewId( nType, nViewId, -1, false );
1621 return;
1622 }
1623 for( auto& it : m_updatedTypesPerViewId )
1624 {
1625 std::vector<PerViewIdData>& types = it.second;
1626 if( types.size() >= o3tl::make_unsigned( nType ))
1627 types[ nType ].set = false;
1628 }
1629}
1630
1631void CallbackFlushHandler::libreOfficeKitViewCallback(int nType, const OString& pPayload)
1632{
1633 CallbackData callbackData(pPayload);
1634 queue(nType, callbackData);
1635}
1636
1637void CallbackFlushHandler::libreOfficeKitViewCallbackWithViewId(int nType, const OString& pPayload, int nViewId)
1638{
1639 CallbackData callbackData(pPayload, nViewId);
1640 queue(nType, callbackData);
1641}
1642
1644{
1645 CallbackData callbackData(pRect, nPart, nMode);
1646 queue(LOK_CALLBACK_INVALIDATE_TILES, callbackData);
1647}
1648
1650{
1651 assert(isUpdatedType( nType ));
1652 std::unique_lock<std::recursive_mutex> lock(m_mutex);
1653 SAL_INFO("lok", "Updated: [" << nType << "]");
1654 setUpdatedType(nType, true);
1655}
1656
1657void CallbackFlushHandler::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId)
1658{
1659 assert(isUpdatedTypePerViewId( nType ));
1660 std::unique_lock<std::recursive_mutex> lock(m_mutex);
1661 SAL_INFO("lok", "Updated: [" << nType << "]");
1662 setUpdatedTypePerViewId(nType, nViewId, nSourceViewId, true);
1663}
1664
1665void CallbackFlushHandler::dumpState(rtl::OStringBuffer &rState)
1666{
1667 // NB. no locking
1668 rState.append("\nView:\t");
1669 rState.append(static_cast<sal_Int32>(m_viewId));
1670 rState.append("\n\tDisableCallbacks:\t");
1671 rState.append(static_cast<sal_Int32>(m_nDisableCallbacks));
1672 rState.append("\n\tStates:\n");
1673 for (const auto &i : m_states)
1674 {
1675 rState.append("\n\t\t");
1676 rState.append(static_cast<sal_Int32>(i.first));
1677 rState.append("\t");
1678 rState.append(i.second);
1679 }
1680}
1681
1683{
1684 // Invoke() will call flushPendingLOKInvalidateTiles(), so just make sure the timer is active.
1685 startTimer();
1686}
1687
1688void CallbackFlushHandler::queue(const int type, const OString& data)
1689{
1690 CallbackData callbackData(data);
1691 queue(type, callbackData);
1692}
1693
1694void CallbackFlushHandler::queue(const int type, CallbackData& aCallbackData)
1695{
1696 comphelper::ProfileZone aZone("CallbackFlushHandler::queue");
1697
1698 SAL_INFO("lok", "Queue: [" << type << "]: [" << aCallbackData.getPayload() << "] on " << m_queue1.size() << " entries.");
1699
1700 bool bIsChartActive = false;
1701 bool bIsComment = false;
1702 if (type == LOK_CALLBACK_GRAPHIC_SELECTION)
1703 {
1704 LokChartHelper aChartHelper(SfxViewShell::Current());
1705 bIsChartActive = aChartHelper.GetWindow() != nullptr;
1706 }
1707 else if (type == LOK_CALLBACK_COMMENT)
1708 {
1709 bIsComment = true;
1710 }
1711
1712 if (callbacksDisabled() && !bIsChartActive && !bIsComment)
1713 {
1714 // We drop notifications when this is set, except for important ones.
1715 // When we issue a complex command (such as .uno:InsertAnnotation)
1716 // there will be multiple notifications. On the first invalidation
1717 // we will start painting, but other events will get fired
1718 // while the complex command in question executes.
1719 // We don't want to suppress everything here on the wrong assumption
1720 // that no new events are fired during painting.
1721 if (type != LOK_CALLBACK_STATE_CHANGED &&
1722 type != LOK_CALLBACK_INVALIDATE_TILES &&
1723 type != LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR &&
1724 type != LOK_CALLBACK_CURSOR_VISIBLE &&
1725 type != LOK_CALLBACK_VIEW_CURSOR_VISIBLE &&
1726 type != LOK_CALLBACK_TEXT_SELECTION &&
1727 type != LOK_CALLBACK_TEXT_SELECTION_START &&
1728 type != LOK_CALLBACK_TEXT_SELECTION_END &&
1729 type != LOK_CALLBACK_MEDIA_SHAPE &&
1730 type != LOK_CALLBACK_REFERENCE_MARKS)
1731 {
1732 SAL_INFO("lok", "Skipping while painting [" << type << "]: [" << aCallbackData.getPayload() << "].");
1733 return;
1734 }
1735
1736 // In Writer we drop all notifications during painting.
1737 if (doc_getDocumentType(m_pDocument) == LOK_DOCTYPE_TEXT)
1738 return;
1739 }
1740
1741 // Suppress invalid payloads.
1742 if (type == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR &&
1743 aCallbackData.getPayload().indexOf(", 0, 0, ") != -1 &&
1744 aCallbackData.getPayload().indexOf("\"hyperlink\":\"\"") == -1 &&
1745 aCallbackData.getPayload().indexOf("\"hyperlink\": {}") == -1)
1746 {
1747 // The cursor position is often the relative coordinates of the widget
1748 // issuing it, instead of the absolute one that we expect.
1749 // This is temporary however, and, once the control is created and initialized
1750 // correctly, it eventually emits the correct absolute coordinates.
1751 SAL_INFO("lok", "Skipping invalid event [" << type << "]: [" << aCallbackData.getPayload() << "].");
1752 return;
1753 }
1754
1755 std::unique_lock<std::recursive_mutex> lock(m_mutex);
1756
1757 // Update types should be received via the updated callbacks for performance,
1758 // getting them as normal callbacks is technically not wrong, but probably should be avoided.
1759 // Reset the updated flag if we get a normal message.
1760 if(isUpdatedType(type))
1761 {
1762 SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
1764 }
1766 {
1767 SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
1768 resetUpdatedTypePerViewId(type, aCallbackData.getViewId());
1769 }
1770
1771 // drop duplicate callbacks for the listed types
1772 switch (type)
1773 {
1774 case LOK_CALLBACK_TEXT_SELECTION_START:
1775 case LOK_CALLBACK_TEXT_SELECTION_END:
1776 case LOK_CALLBACK_TEXT_SELECTION:
1777 case LOK_CALLBACK_GRAPHIC_SELECTION:
1778 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
1779 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
1780 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
1781 case LOK_CALLBACK_STATE_CHANGED:
1782 case LOK_CALLBACK_MOUSE_POINTER:
1783 case LOK_CALLBACK_CELL_CURSOR:
1784 case LOK_CALLBACK_CELL_VIEW_CURSOR:
1785 case LOK_CALLBACK_CELL_FORMULA:
1786 case LOK_CALLBACK_CELL_ADDRESS:
1787 case LOK_CALLBACK_CELL_SELECTION_AREA:
1788 case LOK_CALLBACK_CURSOR_VISIBLE:
1789 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
1790 case LOK_CALLBACK_SET_PART:
1791 case LOK_CALLBACK_TEXT_VIEW_SELECTION:
1792 case LOK_CALLBACK_INVALIDATE_HEADER:
1793 case LOK_CALLBACK_WINDOW:
1794 case LOK_CALLBACK_CALC_FUNCTION_LIST:
1795 case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY:
1796 case LOK_CALLBACK_REFERENCE_MARKS:
1797 case LOK_CALLBACK_CELL_AUTO_FILL_AREA:
1798 case LOK_CALLBACK_A11Y_FOCUS_CHANGED:
1799 case LOK_CALLBACK_A11Y_CARET_CHANGED:
1800 case LOK_CALLBACK_A11Y_TEXT_SELECTION_CHANGED:
1801 case LOK_CALLBACK_COLOR_PALETTES:
1802 {
1803 const auto& pos = std::find(m_queue1.rbegin(), m_queue1.rend(), type);
1804 auto pos2 = toQueue2(pos);
1805 if (pos != m_queue1.rend() && pos2->getPayload() == aCallbackData.getPayload())
1806 {
1807 SAL_INFO("lok", "Skipping queue duplicate [" << type << + "]: [" << aCallbackData.getPayload() << "].");
1808 return;
1809 }
1810 }
1811 break;
1812 }
1813
1814 if (type == LOK_CALLBACK_TEXT_SELECTION && aCallbackData.isEmpty())
1815 {
1816 const auto& posStart = std::find(m_queue1.rbegin(), m_queue1.rend(), LOK_CALLBACK_TEXT_SELECTION_START);
1817 auto posStart2 = toQueue2(posStart);
1818 if (posStart != m_queue1.rend())
1819 posStart2->clear();
1820
1821 const auto& posEnd = std::find(m_queue1.rbegin(), m_queue1.rend(), LOK_CALLBACK_TEXT_SELECTION_END);
1822 auto posEnd2 = toQueue2(posEnd);
1823 if (posEnd != m_queue1.rend())
1824 posEnd2->clear();
1825 }
1826
1827 // When payload is empty discards any previous state.
1828 if (aCallbackData.isEmpty())
1829 {
1830 switch (type)
1831 {
1832 case LOK_CALLBACK_TEXT_SELECTION_START:
1833 case LOK_CALLBACK_TEXT_SELECTION_END:
1834 case LOK_CALLBACK_TEXT_SELECTION:
1835 case LOK_CALLBACK_GRAPHIC_SELECTION:
1836 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
1837 case LOK_CALLBACK_INVALIDATE_TILES:
1838 if (removeAll(type))
1839 SAL_INFO("lok", "Removed dups of [" << type << "]: [" << aCallbackData.getPayload() << "].");
1840 break;
1841 }
1842 }
1843 else
1844 {
1845 switch (type)
1846 {
1847 // These are safe to use the latest state and ignore previous
1848 // ones (if any) since the last overrides previous ones.
1849 case LOK_CALLBACK_TEXT_SELECTION_START:
1850 case LOK_CALLBACK_TEXT_SELECTION_END:
1851 case LOK_CALLBACK_TEXT_SELECTION:
1852 case LOK_CALLBACK_MOUSE_POINTER:
1853 case LOK_CALLBACK_CELL_CURSOR:
1854 case LOK_CALLBACK_CELL_FORMULA:
1855 case LOK_CALLBACK_CELL_ADDRESS:
1856 case LOK_CALLBACK_CURSOR_VISIBLE:
1857 case LOK_CALLBACK_SET_PART:
1858 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
1859 case LOK_CALLBACK_RULER_UPDATE:
1860 case LOK_CALLBACK_A11Y_FOCUS_CHANGED:
1861 case LOK_CALLBACK_A11Y_CARET_CHANGED:
1862 case LOK_CALLBACK_A11Y_TEXT_SELECTION_CHANGED:
1863 case LOK_CALLBACK_COLOR_PALETTES:
1864 {
1865 if (removeAll(type))
1866 SAL_INFO("lok", "Removed dups of [" << type << "]: [" << aCallbackData.getPayload() << "].");
1867 }
1868 break;
1869
1870 // These are safe to use the latest state and ignore previous
1871 // ones (if any) since the last overrides previous ones,
1872 // but only if the view is the same.
1873 case LOK_CALLBACK_CELL_VIEW_CURSOR:
1874 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
1875 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
1876 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
1877 case LOK_CALLBACK_TEXT_VIEW_SELECTION:
1878 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
1879 case LOK_CALLBACK_CALC_FUNCTION_LIST:
1880 case LOK_CALLBACK_FORM_FIELD_BUTTON:
1881 {
1882 // deleting the duplicate of visible cursor message can cause hyperlink popup not to show up on second/or more click on the same place.
1883 // If the hyperlink is not empty we can bypass that to show the popup
1884 const bool hyperLinkException = type == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR &&
1885 aCallbackData.getPayload().indexOf("\"hyperlink\":\"\"") == -1 &&
1886 aCallbackData.getPayload().indexOf("\"hyperlink\": {}") == -1;
1887 if(!hyperLinkException)
1888 {
1889 const int nViewId = aCallbackData.getViewId();
1890 removeAll(type, [nViewId] (const CallbackData& elemData) {
1891 return (nViewId == elemData.getViewId());
1892 }
1893 );
1894 }
1895 }
1896 break;
1897
1898 case LOK_CALLBACK_INVALIDATE_TILES:
1899 if (processInvalidateTilesEvent(type, aCallbackData))
1900 return;
1901 break;
1902
1903 // State changes with same name override previous ones with a different value.
1904 // Ex. ".uno:PageStatus=Slide 20 of 83" overwrites any previous PageStatus.
1905 case LOK_CALLBACK_STATE_CHANGED:
1906 {
1907 // Compare the state name=value and overwrite earlier entries with same name.
1908 const auto pos = aCallbackData.getPayload().indexOf('=');
1909 if (pos != -1)
1910 {
1911 const std::string_view name = aCallbackData.getPayload().subView(0, pos + 1);
1912 // This is needed because otherwise it creates some problems when
1913 // a save occurs while a cell is still edited in Calc.
1914 if (name != ".uno:ModifiedStatus=")
1915 {
1916 removeAll(type, [&name] (const CallbackData& elemData) {
1917 return elemData.getPayload().startsWith(name);
1918 }
1919 );
1920 }
1921 }
1922 }
1923 break;
1924
1925 case LOK_CALLBACK_WINDOW:
1926 if (processWindowEvent(type, aCallbackData))
1927 return;
1928 break;
1929
1930 case LOK_CALLBACK_GRAPHIC_SELECTION:
1931 {
1932 // remove only selection ranges and 'EMPTY' messages
1933 // always send 'INPLACE' and 'INPLACE EXIT' messages
1934 removeAll(type, [] (const CallbackData& elemData)
1935 { return (elemData.getPayload().indexOf("INPLACE") == -1); });
1936 }
1937 break;
1938 }
1939 }
1940
1941 // Validate that the cached data and the payload string are identical.
1942 assert(aCallbackData.validate() && "Cached callback payload object and string mismatch!");
1943 m_queue1.emplace_back(type);
1944 m_queue2.emplace_back(aCallbackData);
1945 SAL_INFO("lok", "Queued #" << (m_queue1.size() - 1) <<
1946 " [" << type << "]: [" << aCallbackData.getPayload() << "] to have " << m_queue1.size() << " entries.");
1947
1948#ifdef DBG_UTIL
1949 {
1950 // Dump the queue state and validate cached data.
1951 int i = 1;
1952 std::ostringstream oss;
1953 if (m_queue1.empty())
1954 oss << "Empty";
1955 else
1956 oss << m_queue1.size() << " items\n";
1957 auto it1 = m_queue1.begin();
1958 auto it2 = m_queue2.begin();
1959 for (; it1 != m_queue1.end(); ++it1, ++it2)
1960 oss << i++ << ": [" << *it1 << "] [" << it2->getPayload() << "].\n";
1961 SAL_INFO("lok", "Current Queue: " << oss.str());
1962 assert(
1963 std::all_of(
1964 m_queue2.begin(), m_queue2.end(),
1965 [](const CallbackData& c) { return c.validate(); }));
1966 }
1967#endif
1968
1969 lock.unlock();
1970 startTimer();
1971}
1972
1974{
1975 RectangleAndPart rcNew = aCallbackData.getRectangleAndPart();
1976 if (rcNew.isEmpty())
1977 {
1978 SAL_INFO("lok", "Skipping invalid event [" << type << "]: [" << aCallbackData.getPayload() << "].");
1979 return true;
1980 }
1981
1982 // If we have to invalidate all tiles, we can skip any new tile invalidation.
1983 // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
1984 const auto& pos
1985 = std::find(m_queue1.rbegin(), m_queue1.rend(), LOK_CALLBACK_INVALIDATE_TILES);
1986 if (pos != m_queue1.rend())
1987 {
1988 auto pos2 = toQueue2(pos);
1989 const RectangleAndPart& rcOld = pos2->getRectangleAndPart();
1990 if (rcOld.isInfinite() && (rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart) &&
1991 (rcOld.m_nMode == rcNew.m_nMode))
1992 {
1993 SAL_INFO("lok", "Skipping queue [" << type << "]: [" << aCallbackData.getPayload()
1994 << "] since all tiles need to be invalidated.");
1995 return true;
1996 }
1997
1998 if ((rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart) && (rcOld.m_nMode == rcNew.m_nMode))
1999 {
2000 // If fully overlapping.
2001 if (rcOld.m_aRectangle.Contains(rcNew.m_aRectangle))
2002 {
2003 SAL_INFO("lok", "Skipping queue [" << type << "]: [" << aCallbackData.getPayload()
2004 << "] since overlaps existing all-parts.");
2005 return true;
2006 }
2007 }
2008 }
2009
2010 if (rcNew.isInfinite())
2011 {
2012 SAL_INFO("lok", "Have Empty [" << type << "]: [" << aCallbackData.getPayload()
2013 << "] so removing all with part " << rcNew.m_nPart << ".");
2014 removeAll(LOK_CALLBACK_INVALIDATE_TILES, [&rcNew](const CallbackData& elemData) {
2015 // Remove exiting if new is all-encompassing, or if of the same part.
2016 return ((rcNew.m_nPart == -1 || rcNew.m_nPart == elemData.getRectangleAndPart().m_nPart)
2017 && (rcNew.m_nMode == elemData.getRectangleAndPart().m_nMode));
2018 });
2019 }
2020 else
2021 {
2022 const auto rcOrig = rcNew;
2023
2024 SAL_INFO("lok", "Have [" << type << "]: [" << aCallbackData.getPayload() << "] so merging overlapping.");
2025 removeAll(LOK_CALLBACK_INVALIDATE_TILES,[&rcNew](const CallbackData& elemData) {
2026 const RectangleAndPart& rcOld = elemData.getRectangleAndPart();
2027 if (rcNew.m_nPart != -1 && rcOld.m_nPart != -1 &&
2028 (rcOld.m_nPart != rcNew.m_nPart || rcOld.m_nMode != rcNew.m_nMode))
2029 {
2030 SAL_INFO("lok", "Nothing to merge between new: "
2031 << rcNew.toString() << ", and old: " << rcOld.toString());
2032 return false;
2033 }
2034
2035 if (rcNew.m_nPart == -1)
2036 {
2037 // Don't merge unless fully overlapped.
2038 SAL_INFO("lok", "New " << rcNew.toString() << " has " << rcOld.toString()
2039 << "?");
2040 if (rcNew.m_aRectangle.Contains(rcOld.m_aRectangle) && rcOld.m_nMode == rcNew.m_nMode)
2041 {
2042 SAL_INFO("lok", "New " << rcNew.toString() << " engulfs old "
2043 << rcOld.toString() << ".");
2044 return true;
2045 }
2046 }
2047 else if (rcOld.m_nPart == -1)
2048 {
2049 // Don't merge unless fully overlapped.
2050 SAL_INFO("lok", "Old " << rcOld.toString() << " has " << rcNew.toString()
2051 << "?");
2052 if (rcOld.m_aRectangle.Contains(rcNew.m_aRectangle) && rcOld.m_nMode == rcNew.m_nMode)
2053 {
2054 SAL_INFO("lok", "New " << rcNew.toString() << " engulfs old "
2055 << rcOld.toString() << ".");
2056 return true;
2057 }
2058 }
2059 else
2060 {
2061 const tools::Rectangle rcOverlap
2062 = rcNew.m_aRectangle.GetIntersection(rcOld.m_aRectangle);
2063 const bool bOverlap = !rcOverlap.IsEmpty() && rcOld.m_nMode == rcNew.m_nMode;
2064 SAL_INFO("lok", "Merging " << rcNew.toString() << " & " << rcOld.toString()
2065 << " => " << rcOverlap.toString()
2066 << " Overlap: " << bOverlap);
2067 if (bOverlap)
2068 {
2069 rcNew.m_aRectangle.Union(rcOld.m_aRectangle);
2070 SAL_INFO("lok", "Merged: " << rcNew.toString());
2071 return true;
2072 }
2073 }
2074
2075 // Keep others.
2076 return false;
2077 });
2078
2079 if (rcNew.m_aRectangle != rcOrig.m_aRectangle)
2080 {
2081 SAL_INFO("lok", "Replacing: " << rcOrig.toString() << " by " << rcNew.toString());
2082 if (rcNew.m_aRectangle.GetWidth() < rcOrig.m_aRectangle.GetWidth()
2083 || rcNew.m_aRectangle.GetHeight() < rcOrig.m_aRectangle.GetHeight())
2084 {
2085 SAL_WARN("lok", "Error: merged rect smaller.");
2086 }
2087 }
2088 }
2089
2090 aCallbackData.updateRectangleAndPart(rcNew);
2091 // Queue this one.
2092 return false;
2093}
2094
2096{
2097 const OString& payload = aCallbackData.getPayload();
2098
2099 boost::property_tree::ptree& aTree = aCallbackData.setJson(std::string(payload));
2100 const unsigned nLOKWindowId = aTree.get<unsigned>("id", 0);
2101 const std::string aAction = aTree.get<std::string>("action", "");
2102 if (aAction == "invalidate")
2103 {
2104 std::string aRectStr = aTree.get<std::string>("rectangle", "");
2105 // no 'rectangle' field => invalidate all of the window =>
2106 // remove all previous window part invalidations
2107 if (aRectStr.empty())
2108 {
2109 removeAll(LOK_CALLBACK_WINDOW,[&nLOKWindowId](const CallbackData& elemData) {
2110 const boost::property_tree::ptree& aOldTree = elemData.getJson();
2111 if (nLOKWindowId == aOldTree.get<unsigned>("id", 0)
2112 && aOldTree.get<std::string>("action", "") == "invalidate")
2113 {
2114 return true;
2115 }
2116 return false;
2117 });
2118 }
2119 else
2120 {
2121 // if we have to invalidate all of the window, ignore
2122 // any part invalidation message
2123 bool invAllExist = false;
2124 auto it1 = m_queue1.rbegin();
2125 auto it2 = m_queue2.rbegin();
2126 for (;it1 != m_queue1.rend(); ++it1, ++it2)
2127 {
2128 if (*it1 != LOK_CALLBACK_WINDOW)
2129 continue;
2130 const boost::property_tree::ptree& aOldTree = it2->getJson();
2131 if (nLOKWindowId == aOldTree.get<unsigned>("id", 0)
2132 && aOldTree.get<std::string>("action", "") == "invalidate"
2133 && aOldTree.get<std::string>("rectangle", "").empty())
2134 {
2135 invAllExist = true;
2136 break;
2137 }
2138 }
2139
2140 // we found a invalidate-all window callback
2141 if (invAllExist)
2142 {
2143 SAL_INFO("lok.dialog", "Skipping queue ["
2144 << type << "]: [" << payload
2145 << "] since whole window needs to be invalidated.");
2146 return true;
2147 }
2148
2149 std::istringstream aRectStream(aRectStr);
2150 tools::Long nLeft, nTop, nWidth, nHeight;
2151 char nComma;
2152 aRectStream >> nLeft >> nComma >> nTop >> nComma >> nWidth >> nComma >> nHeight;
2153 tools::Rectangle aNewRect(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
2154 bool currentIsRedundant = false;
2155 removeAll(LOK_CALLBACK_WINDOW, [&aNewRect, &nLOKWindowId,
2156 &currentIsRedundant](const CallbackData& elemData) {
2157 const boost::property_tree::ptree& aOldTree = elemData.getJson();
2158 if (aOldTree.get<std::string>("action", "") == "invalidate")
2159 {
2160 // Not possible that we encounter an empty rectangle here; we already handled this case above.
2161 std::istringstream aOldRectStream(aOldTree.get<std::string>("rectangle", ""));
2162 tools::Long nOldLeft, nOldTop, nOldWidth, nOldHeight;
2163 char nOldComma;
2164 aOldRectStream >> nOldLeft >> nOldComma >> nOldTop >> nOldComma >> nOldWidth
2165 >> nOldComma >> nOldHeight;
2166 const tools::Rectangle aOldRect = tools::Rectangle(
2167 nOldLeft, nOldTop, nOldLeft + nOldWidth, nOldTop + nOldHeight);
2168
2169 if (nLOKWindowId == aOldTree.get<unsigned>("id", 0))
2170 {
2171 if (aNewRect == aOldRect)
2172 {
2173 SAL_INFO("lok.dialog", "Duplicate rect [" << aNewRect.toString()
2174 << "]. Skipping new.");
2175 // We have a rectangle in the queue already that makes the current Callback useless.
2176 currentIsRedundant = true;
2177 return false;
2178 }
2179 // new one engulfs the old one?
2180 else if (aNewRect.Contains(aOldRect))
2181 {
2182 SAL_INFO("lok.dialog",
2183 "New rect [" << aNewRect.toString() << "] engulfs old ["
2184 << aOldRect.toString() << "]. Replacing old.");
2185 return true;
2186 }
2187 // old one engulfs the new one?
2188 else if (aOldRect.Contains(aNewRect))
2189 {
2190 SAL_INFO("lok.dialog",
2191 "Old rect [" << aOldRect.toString() << "] engulfs new ["
2192 << aNewRect.toString() << "]. Skipping new.");
2193 // We have a rectangle in the queue already that makes the current Callback useless.
2194 currentIsRedundant = true;
2195 return false;
2196 }
2197 else
2198 {
2199 // Overlapping rects.
2200 const tools::Rectangle aPreMergeRect = aNewRect;
2201 aNewRect.Union(aOldRect);
2202 SAL_INFO("lok.dialog", "Merging rects ["
2203 << aPreMergeRect.toString() << "] & ["
2204 << aOldRect.toString() << "] = ["
2205 << aNewRect.toString()
2206 << "]. Replacing old.");
2207 return true;
2208 }
2209 }
2210 }
2211
2212 // keep rest
2213 return false;
2214 });
2215
2216 // Do not enqueue if redundant.
2217 if (currentIsRedundant)
2218 return true;
2219
2220 aTree.put("rectangle", aNewRect.toString().getStr());
2221 aCallbackData.setJson(aTree);
2222 assert(aCallbackData.validate() && "Validation after setJson failed!");
2223 }
2224 }
2225 else if (aAction == "created")
2226 {
2227 // Remove all previous actions on same dialog, if we are creating it anew.
2228 removeAll(LOK_CALLBACK_WINDOW,[&nLOKWindowId](const CallbackData& elemData) {
2229 const boost::property_tree::ptree& aOldTree = elemData.getJson();
2230 if (nLOKWindowId == aOldTree.get<unsigned>("id", 0))
2231 return true;
2232 return false;
2233 });
2234
2235 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
2236 if (!pWindow)
2237 {
2238 gImpl->maLastExceptionMsg = "Document doesn't support dialog rendering, or window not found.";
2239 return false;
2240 }
2241
2242#ifndef IOS
2243 auto xClip = forceSetClipboardForCurrentView(m_pDocument);
2244
2246 pWindow->SetClipboard(xClipboard);
2247#endif
2248 }
2249 else if (aAction == "size_changed")
2250 {
2251 // A size change is practically re-creation of the window.
2252 // But at a minimum it's a full invalidation.
2253 removeAll(LOK_CALLBACK_WINDOW, [&nLOKWindowId](const CallbackData& elemData) {
2254 const boost::property_tree::ptree& aOldTree = elemData.getJson();
2255 if (nLOKWindowId == aOldTree.get<unsigned>("id", 0))
2256 {
2257 const std::string aOldAction = aOldTree.get<std::string>("action", "");
2258 if (aOldAction == "invalidate")
2259 return true;
2260 }
2261 return false;
2262 });
2263 }
2264
2265 // Queue this one.
2266 return false;
2267}
2268
2270{
2271 if( m_updatedTypes.empty() && m_updatedTypesPerViewId.empty())
2272 return;
2273 assert(m_viewId >= 0);
2274 SfxViewShell* viewShell = SfxViewShell::GetFirst( false,
2275 [this](const SfxViewShell* shell) { return shell->GetViewShellId().get() == m_viewId; } );
2276 assert(viewShell != nullptr);
2277
2278 // First move data to local structures, so that callbacks don't possibly modify it.
2279 std::vector<bool> updatedTypes;
2280 std::swap(updatedTypes, m_updatedTypes);
2281 boost::container::flat_map<int, std::vector<PerViewIdData>> updatedTypesPerViewId;
2282 std::swap(updatedTypesPerViewId, m_updatedTypesPerViewId);
2283
2284 // Some types must always precede other types, for example
2285 // LOK_CALLBACK_TEXT_SELECTION_START and LOK_CALLBACK_TEXT_SELECTION_END
2286 // must always precede LOK_CALLBACK_TEXT_SELECTION if present.
2287 // Only these types should be present (see isUpdatedType()) and should be processed in this order.
2288 static const int orderedUpdatedTypes[] = {
2289 LOK_CALLBACK_TEXT_SELECTION_START, LOK_CALLBACK_TEXT_SELECTION_END, LOK_CALLBACK_TEXT_SELECTION };
2290 // Only these types should be present (see isUpdatedTypePerViewId()) and (as of now)
2291 // the order doesn't matter.
2292 static const int orderedUpdatedTypesPerViewId[] = {
2293 LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR,
2294 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR,
2295 LOK_CALLBACK_TEXT_VIEW_SELECTION };
2296
2297 for( int type : orderedUpdatedTypes )
2298 {
2299 if(o3tl::make_unsigned( type ) < updatedTypes.size() && updatedTypes[ type ])
2300 {
2301 enqueueUpdatedType( type, viewShell, m_viewId );
2302 }
2303 }
2304 for( const auto& it : updatedTypesPerViewId )
2305 {
2306 int viewId = it.first;
2307 const std::vector<PerViewIdData>& types = it.second;
2308 for( int type : orderedUpdatedTypesPerViewId )
2309 {
2310 if(o3tl::make_unsigned( type ) < types.size() && types[ type ].set)
2311 {
2312 SfxViewShell* sourceViewShell = viewShell;
2313 const int sourceViewId = types[ type ].sourceViewId;
2314 if( sourceViewId != m_viewId )
2315 {
2316 assert(sourceViewId >= 0);
2317 sourceViewShell = SfxViewShell::GetFirst( false,
2318 [sourceViewId](const SfxViewShell* shell) { return shell->GetViewShellId().get() == sourceViewId; } );
2319 }
2320 if(sourceViewShell == nullptr)
2321 {
2322 SAL_INFO("lok", "View #" << sourceViewId << " no longer found for updated event [" << type << "]");
2323 continue; // View removed, probably cleaning up.
2324 }
2325 enqueueUpdatedType( type, sourceViewShell, viewId );
2326 }
2327 }
2328 }
2329}
2330
2331void CallbackFlushHandler::enqueueUpdatedType( int type, const SfxViewShell* viewShell, int viewId )
2332{
2333 if (type == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR)
2334 {
2335 if (const SfxViewShell* viewShell2 = LokStarMathHelper(viewShell).GetSmViewShell())
2336 viewShell = viewShell2;
2337 }
2338 std::optional<OString> payload = viewShell->getLOKPayload( type, viewId );
2339 if(!payload)
2340 return; // No actual payload to send.
2341 CallbackData callbackData(*payload, viewId);
2342 m_queue1.emplace_back(type);
2343 m_queue2.emplace_back(callbackData);
2344 SAL_INFO("lok", "Queued updated [" << type << "]: [" << callbackData.getPayload()
2345 << "] to have " << m_queue1.size() << " entries.");
2346}
2347
2349{
2350 comphelper::ProfileZone aZone("CallbackFlushHandler::Invoke");
2351
2352 if (!m_pCallback)
2353 return;
2354
2355 // Get any pending invalidate tile events. This will call our callbacks,
2356 // so it must be done before taking the mutex.
2357 assert(m_viewId >= 0);
2358 if(SfxViewShell* viewShell = SfxViewShell::GetFirst( false,
2359 [this](const SfxViewShell* shell) { return shell->GetViewShellId().get() == m_viewId; } ))
2360 {
2361 viewShell->flushPendingLOKInvalidateTiles();
2362 }
2363
2364 std::unique_lock<std::recursive_mutex> lock(m_mutex);
2365
2366 // Append messages for updated types, fetch them only now.
2368
2369 SAL_INFO("lok", "Flushing " << m_queue1.size() << " elements.");
2370 auto it1 = m_queue1.begin();
2371 auto it2 = m_queue2.begin();
2372 for (; it1 != m_queue1.end(); ++it1, ++it2)
2373 {
2374 const int type = *it1;
2375 const auto& payload = it2->getPayload();
2376 const int viewId = lcl_isViewCallbackType(type) ? it2->getViewId() : -1;
2377
2378 SAL_INFO("lok", "processing event: [" << type << ',' << viewId << "]: [" << payload << "].");
2379
2380 // common code-path for events on this view:
2381 if (viewId == -1)
2382 {
2383 sal_Int32 idx;
2384 // key-value pairs
2385 if (type == LOK_CALLBACK_STATE_CHANGED &&
2386 (idx = payload.indexOf('=')) != -1)
2387 {
2388 OString key = payload.copy(0, idx);
2389 OString value = payload.copy(idx+1);
2390 const auto stateIt = m_lastStateChange.find(key);
2391 if (stateIt != m_lastStateChange.end())
2392 {
2393 // If the value didn't change, it's safe to ignore.
2394 if (stateIt->second == value)
2395 {
2396 SAL_INFO("lok", "Skipping new state duplicate: [" << type << "]: [" << payload << "].");
2397 continue;
2398 }
2399 SAL_INFO("lok", "Replacing a state element [" << type << "]: [" << payload << "].");
2400 stateIt->second = value;
2401 }
2402 else
2403 {
2404 SAL_INFO("lok", "Inserted a new state element: [" << type << "]: [" << payload << "]");
2405 m_lastStateChange.emplace(key, value);
2406 }
2407 }
2408 else
2409 {
2410 const auto stateIt = m_states.find(type);
2411 if (stateIt != m_states.end())
2412 {
2413 // If the state didn't change, it's safe to ignore.
2414 if (stateIt->second == payload)
2415 {
2416 SAL_INFO("lok", "Skipping duplicate [" << type << "]: [" << payload << "].");
2417 continue;
2418 }
2419 stateIt->second = payload;
2420 }
2421 }
2422 }
2423 else // less common path for events relating to other views
2424 {
2425 const auto statesIt = m_viewStates.find(viewId);
2426 if (statesIt != m_viewStates.end())
2427 {
2428 auto& states = statesIt->second;
2429 const auto stateIt = states.find(type);
2430 if (stateIt != states.end())
2431 {
2432 // If the state didn't change, it's safe to ignore.
2433 if (stateIt->second == payload)
2434 {
2435 SAL_INFO("lok", "Skipping view duplicate [" << type << ',' << viewId << "]: [" << payload << "].");
2436 continue;
2437 }
2438
2439 SAL_INFO("lok", "Replacing an element in view states [" << type << ',' << viewId << "]: [" << payload << "].");
2440 stateIt->second = payload;
2441 }
2442 else
2443 {
2444 SAL_INFO("lok", "Inserted a new element in view states: [" << type << ',' << viewId << "]: [" << payload << "]");
2445 states.emplace(type, payload);
2446
2447 }
2448 }
2449 }
2450
2451 m_pCallback(type, payload.getStr(), m_pData);
2452 }
2453
2454 m_queue1.clear();
2455 m_queue2.clear();
2456 Stop();
2458}
2459
2461{
2462 if (!IsActive())
2463 Start();
2464 if (!m_TimeoutIdle.IsActive())
2466}
2467
2469{
2470 bool bErased = false;
2471 auto it1 = m_queue1.begin();
2472 for(;;)
2473 {
2474 it1 = std::find(it1, m_queue1.end(), type);
2475 if(it1 == m_queue1.end())
2476 break;
2477 m_queue2.erase(toQueue2(it1));
2478 it1 = m_queue1.erase(it1);
2479 bErased = true;
2480 }
2481 return bErased;
2482}
2483
2484bool CallbackFlushHandler::removeAll(int type, const std::function<bool (const CallbackData&)>& rTestFunc)
2485{
2486 bool bErased = false;
2487 auto it1 = m_queue1.begin();
2488 for(;;)
2489 {
2490 it1 = std::find(it1, m_queue1.end(), type);
2491 if(it1 == m_queue1.end())
2492 break;
2493 auto it2 = toQueue2(it1);
2494 if (rTestFunc(*it2))
2495 {
2496 m_queue2.erase(it2);
2497 it1 = m_queue1.erase(it1);
2498 bErased = true;
2499 }
2500 else
2501 ++it1;
2502 }
2503 return bErased;
2504}
2505
2507{
2508 const auto& result = m_viewStates.emplace(viewId, decltype(m_viewStates)::mapped_type());
2509 if (!result.second && result.first != m_viewStates.end())
2510 {
2511 result.first->second.clear();
2512 }
2513}
2514
2516{
2517 m_viewStates.erase(viewId);
2518}
2519
2520
2521static void doc_destroy(LibreOfficeKitDocument *pThis)
2522{
2523 comphelper::ProfileZone aZone("doc_destroy");
2524
2525 SolarMutexGuard aGuard;
2526
2527#ifndef IOS
2529#endif
2530
2531 LibLODocument_Impl *pDocument = static_cast<LibLODocument_Impl*>(pThis);
2532 delete pDocument;
2533}
2534
2535static void lo_destroy (LibreOfficeKit* pThis);
2536static int lo_initialize (LibreOfficeKit* pThis, const char* pInstallPath, const char* pUserProfilePath);
2537static LibreOfficeKitDocument* lo_documentLoad (LibreOfficeKit* pThis, const char* pURL);
2538static char * lo_getError (LibreOfficeKit* pThis);
2539static void lo_freeError (char* pFree);
2540static LibreOfficeKitDocument* lo_documentLoadWithOptions (LibreOfficeKit* pThis,
2541 const char* pURL,
2542 const char* pOptions);
2543static void lo_registerCallback (LibreOfficeKit* pThis,
2544 LibreOfficeKitCallback pCallback,
2545 void* pData);
2546static char* lo_getFilterTypes(LibreOfficeKit* pThis);
2547static void lo_setOptionalFeatures(LibreOfficeKit* pThis, unsigned long long features);
2548static void lo_setDocumentPassword(LibreOfficeKit* pThis,
2549 const char* pURL,
2550 const char* pPassword);
2551static char* lo_getVersionInfo(LibreOfficeKit* pThis);
2552static int lo_runMacro (LibreOfficeKit* pThis, const char* pURL);
2553
2554static bool lo_signDocument(LibreOfficeKit* pThis,
2555 const char* pUrl,
2556 const unsigned char* pCertificateBinary,
2557 const int nCertificateBinarySize,
2558 const unsigned char* pPrivateKeyBinary,
2559 const int nPrivateKeyBinarySize);
2560
2561static char* lo_extractRequest(LibreOfficeKit* pThis,
2562 const char* pFilePath);
2563
2564static void lo_trimMemory(LibreOfficeKit* pThis, int nTarget);
2565
2566static void lo_runLoop(LibreOfficeKit* pThis,
2567 LibreOfficeKitPollCallback pPollCallback,
2568 LibreOfficeKitWakeCallback pWakeCallback,
2569 void* pData);
2570
2571static void lo_sendDialogEvent(LibreOfficeKit* pThis,
2572 unsigned long long int nLOKWindowId,
2573 const char* pArguments);
2574
2575static void lo_setOption(LibreOfficeKit* pThis, const char* pOption, const char* pValue);
2576
2577static void lo_dumpState(LibreOfficeKit* pThis, const char* pOptions, char** pState);
2578
2580 : m_pOfficeClass( gOfficeClass.lock() )
2581 , maThread(nullptr)
2582 , mpCallback(nullptr)
2583 , mpCallbackData(nullptr)
2584 , mOptionalFeatures(0)
2585{
2586 if(!m_pOfficeClass) {
2587 m_pOfficeClass = std::make_shared<LibreOfficeKitClass>();
2588 m_pOfficeClass->nSize = sizeof(LibreOfficeKitClass);
2589
2590 m_pOfficeClass->destroy = lo_destroy;
2591 m_pOfficeClass->documentLoad = lo_documentLoad;
2592 m_pOfficeClass->getError = lo_getError;
2593 m_pOfficeClass->freeError = lo_freeError;
2594 m_pOfficeClass->documentLoadWithOptions = lo_documentLoadWithOptions;
2595 m_pOfficeClass->registerCallback = lo_registerCallback;
2596 m_pOfficeClass->getFilterTypes = lo_getFilterTypes;
2597 m_pOfficeClass->setOptionalFeatures = lo_setOptionalFeatures;
2598 m_pOfficeClass->setDocumentPassword = lo_setDocumentPassword;
2599 m_pOfficeClass->getVersionInfo = lo_getVersionInfo;
2600 m_pOfficeClass->runMacro = lo_runMacro;
2601 m_pOfficeClass->signDocument = lo_signDocument;
2602 m_pOfficeClass->runLoop = lo_runLoop;
2603 m_pOfficeClass->sendDialogEvent = lo_sendDialogEvent;
2604 m_pOfficeClass->setOption = lo_setOption;
2605 m_pOfficeClass->dumpState = lo_dumpState;
2606 m_pOfficeClass->extractRequest = lo_extractRequest;
2607 m_pOfficeClass->trimMemory = lo_trimMemory;
2608
2610 }
2611
2612 pClass = m_pOfficeClass.get();
2613}
2614
2616{
2617}
2618
2619namespace
2620{
2621
2622void setLanguageAndLocale(OUString const & aLangISO)
2623{
2624 SvtSysLocaleOptions aLocalOptions;
2625 aLocalOptions.SetLocaleConfigString(aLangISO);
2626 aLocalOptions.SetUILocaleConfigString(aLangISO);
2627 aLocalOptions.Commit();
2628}
2629
2630void setFormatSpecificFilterData(std::u16string_view sFormat, comphelper::SequenceAsHashMap & rFilterDataMap)
2631{
2632 if (sFormat == u"pdf")
2633 {
2634 // always export bookmarks, which is needed for annotations
2635 rFilterDataMap["ExportBookmarks"] <<= true;
2636 }
2637}
2638
2639} // anonymous namespace
2640
2641// Wonder global state ...
2645
2646static LibreOfficeKitDocument* lo_documentLoad(LibreOfficeKit* pThis, const char* pURL)
2647{
2648 return lo_documentLoadWithOptions(pThis, pURL, nullptr);
2649}
2650
2651static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis, const char* pURL, const char* pOptions)
2652{
2653 comphelper::ProfileZone aZone("lo_documentLoadWithOptions");
2654
2655 SolarMutexGuard aGuard;
2656
2657 static int nDocumentIdCounter = 0;
2658
2659 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
2660 pLib->maLastExceptionMsg.clear();
2661
2662 const OUString aURL(getAbsoluteURL(pURL));
2663 if (aURL.isEmpty())
2664 {
2665 pLib->maLastExceptionMsg = "Filename to load was not provided.";
2666 SAL_INFO("lok", "URL for load is empty");
2667 return nullptr;
2668 }
2669
2670 pLib->maLastExceptionMsg.clear();
2671
2672 if (!xContext.is())
2673 {
2674 pLib->maLastExceptionMsg = "ComponentContext is not available";
2675 SAL_INFO("lok", "ComponentContext is not available");
2676 return nullptr;
2677 }
2678
2680
2681 if (!xComponentLoader.is())
2682 {
2683 pLib->maLastExceptionMsg = "ComponentLoader is not available";
2684 SAL_INFO("lok", "ComponentLoader is not available");
2685 return nullptr;
2686 }
2687
2688 try
2689 {
2690 // 'Language=...' is an option that LOK consumes by itself, and does
2691 // not pass it as a parameter to the filter
2692 OUString aOptions = getUString(pOptions);
2693 const OUString aLanguage = extractParameter(aOptions, u"Language");
2694 bool isValidLangTag = LanguageTag::isValidBcp47(aLanguage, nullptr);
2695
2696 if (!aLanguage.isEmpty() && isValidLangTag)
2697 {
2698 static bool isLoading = true;
2699 if (isLoading)
2700 {
2701 // Capture the language used to load the document.
2703 isLoading = false;
2704 }
2705
2707 // Set the LOK language tag, used for dialog tunneling.
2710
2711 SAL_INFO("lok", "Set document language to " << aLanguage);
2712 // use with care - it sets it for the entire core, not just the
2713 // document
2714 setLanguageAndLocale(aLanguage);
2715 // Need to reset the static initialized values
2717 }
2718
2719 // Set the timezone, if not empty.
2720 const OUString aTimezone = extractParameter(aOptions, u"Timezone");
2721 if (!aTimezone.isEmpty())
2722 {
2723 SfxLokHelper::setDefaultTimezone(true, aTimezone);
2724 }
2725 else
2726 {
2727 // Default to the TZ envar, if set.
2728 const char* tz = ::getenv("TZ");
2729 if (tz)
2730 {
2732 OStringToOUString(tz, RTL_TEXTENCODING_UTF8));
2733 }
2734 else
2735 {
2736 SfxLokHelper::setDefaultTimezone(false, OUString());
2737 }
2738 }
2739
2740 const OUString aDeviceFormFactor = extractParameter(aOptions, u"DeviceFormFactor");
2741 SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor);
2742
2743 const OUString aBatch = extractParameter(aOptions, u"Batch");
2744 if (!aBatch.isEmpty())
2745 {
2746 Application::SetDialogCancelMode(DialogCancelMode::LOKSilent);
2747 }
2748
2749 const OUString sFilterOptions = aOptions;
2750
2751 rtl::Reference<LOKInteractionHandler> const pInteraction(
2752 new LOKInteractionHandler("load", pLib));
2753 auto const pair(pLib->mInteractionMap.insert(std::make_pair(aURL.toUtf8(), pInteraction)));
2754 comphelper::ScopeGuard const g([&] () {
2755 if (pair.second)
2756 {
2757 pLib->mInteractionMap.erase(aURL.toUtf8());
2758 }
2759 });
2760 uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction);
2761
2762 int nMacroSecurityLevel = 1;
2763 const OUString aMacroSecurityLevel = extractParameter(aOptions, u"MacroSecurityLevel");
2764 if (!aMacroSecurityLevel.isEmpty())
2765 {
2766 double nNumber;
2767 sal_uInt32 nFormat = 1;
2768 SvNumberFormatter aFormatter(::comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US);
2769 if (aFormatter.IsNumberFormat(aMacroSecurityLevel, nFormat, nNumber))
2770 nMacroSecurityLevel = static_cast<int>(nNumber);
2771 }
2772 SvtSecurityOptions::SetMacroSecurityLevel(nMacroSecurityLevel);
2773
2774#if defined(ANDROID) && HAVE_FEATURE_ANDROID_LOK
2775 sal_Int16 nMacroExecMode = document::MacroExecMode::USE_CONFIG;
2776#else
2777 const OUString aEnableMacrosExecution = extractParameter(aOptions, u"EnableMacrosExecution");
2778 sal_Int16 nMacroExecMode = aEnableMacrosExecution == "true" ? document::MacroExecMode::USE_CONFIG :
2779 document::MacroExecMode::NEVER_EXECUTE;
2780#endif
2781
2782 // set AsTemplate explicitly false to be able to load template files
2783 // as regular files, otherwise we cannot save them; it will try
2784 // to bring saveas dialog which cannot work with LOK case
2786 comphelper::makePropertyValue("FilterOptions", sFilterOptions),
2787 comphelper::makePropertyValue("InteractionHandler", xInteraction),
2788 comphelper::makePropertyValue("MacroExecutionMode", nMacroExecMode),
2789 comphelper::makePropertyValue("AsTemplate", false),
2790 comphelper::makePropertyValue("Silent", !aBatch.isEmpty())
2791 };
2792
2793 /* TODO
2794 sal_Int16 nUpdateDoc = document::UpdateDocMode::ACCORDING_TO_CONFIG;
2795 aFilterOptions[3].Name = "UpdateDocMode";
2796 aFilterOptions[3].Value <<= nUpdateDoc;
2797 */
2798
2800
2801 const int nThisDocumentId = nDocumentIdCounter++;
2803 uno::Reference<lang::XComponent> xComponent = xComponentLoader->loadComponentFromURL(
2804 aURL, "_blank", 0,
2805 aFilterOptions);
2806
2807 assert(!xComponent.is() || pair.second); // concurrent loading of same URL ought to fail
2808
2809 if (!xComponent.is())
2810 {
2811 pLib->maLastExceptionMsg = "loadComponentFromURL returned an empty reference";
2812 SAL_INFO("lok", "Document can't be loaded - " << pLib->maLastExceptionMsg);
2813 return nullptr;
2814 }
2815
2816 LibLODocument_Impl* pDocument = new LibLODocument_Impl(xComponent, nThisDocumentId);
2817
2818 // After loading the document, its initial view is the "current" view.
2819 if (pLib->mpCallback)
2820 {
2821 int nState = doc_getSignatureState(pDocument);
2822 pLib->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS, OString::number(nState).getStr(), pLib->mpCallbackData);
2823 }
2824
2825 auto aFontMappingUseData = OutputDevice::FinishTrackingFontMappingUse();
2826
2827 if (aFontMappingUseData.size() > 0)
2828 {
2829 SAL_INFO("lok.fontsubst", "================ Original substitutions:");
2830 for (const auto &i : aFontMappingUseData)
2831 {
2832 SAL_INFO("lok.fontsubst", i.mOriginalFont);
2833 for (const auto &j : i.mUsedFonts)
2834 SAL_INFO("lok.fontsubst", " " << j);
2835 }
2836 }
2837
2838 // Filter out font substitutions that actually aren't any substitutions, like "Liberation
2839 // Serif" -> "Liberation Serif/Regular". If even one of the "substitutions" of a font is to
2840 // the same font, don't count that as a missing font.
2841
2842 aFontMappingUseData.erase
2843 (std::remove_if(aFontMappingUseData.begin(), aFontMappingUseData.end(),
2845 {
2846 // If the original font had an empty style and one of its
2847 // replacement fonts has the same family name, we assume the font is
2848 // present. The root problem here is that the code that collects
2849 // font substitutions tends to get just empty styles for the font
2850 // that is being substituted, as vcl::Font::GetStyleName() tends to
2851 // return an empty string. (Italicness is instead indicated by what
2852 // vcl::Font::GetItalic() returns and boldness by what
2853 // vcl::Font::GetWeight() returns.)
2854
2855 if (x.mOriginalFont.indexOf('/') == -1)
2856 for (const auto &j : x.mUsedFonts)
2857 if (j == x.mOriginalFont ||
2858 j.startsWith(Concat2View(x.mOriginalFont + "/")))
2859 return true;
2860
2861 return false;
2862 }),
2863 aFontMappingUseData.end());
2864
2865 // Filter out substitutions where a proprietary font has been substituted by a
2866 // metric-compatible one. Obviously this is just a heuristic and implemented only for some
2867 // well-known cases.
2868
2869 aFontMappingUseData.erase
2870 (std::remove_if(aFontMappingUseData.begin(), aFontMappingUseData.end(),
2872 {
2873 // Again, handle only cases where the original font does not include
2874 // a style. Unclear whether there ever will be a style part included
2875 // in the mOriginalFont.
2876
2877 if (x.mOriginalFont.indexOf('/') == -1)
2878 for (const auto &j : x.mUsedFonts)
2879 if ((x.mOriginalFont == "Arial" &&
2880 j.startsWith("Liberation Sans/")) ||
2881 (x.mOriginalFont == "Times New Roman" &&
2882 j.startsWith("Liberation Serif/")) ||
2883 (x.mOriginalFont == "Courier New" &&
2884 j.startsWith("Liberation Mono/")) ||
2885 (x.mOriginalFont == "Arial Narrow" &&
2886 j.startsWith("Liberation Sans Narrow/")) ||
2887 (x.mOriginalFont == "Cambria" &&
2888 j.startsWith("Caladea/")) ||
2889 (x.mOriginalFont == "Calibri" &&
2890 j.startsWith("Carlito/")) ||
2891 (x.mOriginalFont == "Palatino Linotype" &&
2892 j.startsWith("P052/")) ||
2893 // Perhaps a risky heuristic? If some glyphs from Symbol
2894 // have been mapped to ones in OpenSymbol, don't warn
2895 // that Symbol is missing.
2896 (x.mOriginalFont == "Symbol" &&
2897 j.startsWith("OpenSymbol/")))
2898 {
2899 return true;
2900 }
2901
2902 return false;
2903 }),
2904 aFontMappingUseData.end());
2905
2906 if (aFontMappingUseData.size() > 0)
2907 {
2908 SAL_INFO("lok.fontsubst", "================ Pruned substitutions:");
2909 for (const auto &i : aFontMappingUseData)
2910 {
2911 SAL_INFO("lok.fontsubst", i.mOriginalFont);
2912 for (const auto &j : i.mUsedFonts)
2913 SAL_INFO("lok.fontsubst", " " << j);
2914 }
2915 }
2916
2917 for (std::size_t i = 0; i < aFontMappingUseData.size(); ++i)
2918 {
2919 pDocument->maFontsMissing.insert(aFontMappingUseData[i].mOriginalFont);
2920 }
2921
2922 return pDocument;
2923 }
2924 catch (const uno::Exception& exception)
2925 {
2926 pLib->maLastExceptionMsg = exception.Message;
2927 TOOLS_INFO_EXCEPTION("lok", "Document can't be loaded");
2928 }
2929
2930 return nullptr;
2931}
2932
2933static int lo_runMacro(LibreOfficeKit* pThis, const char *pURL)
2934{
2935 comphelper::ProfileZone aZone("lo_runMacro");
2936
2937 SolarMutexGuard aGuard;
2938
2939 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
2940 pLib->maLastExceptionMsg.clear();
2941
2942 OUString sURL( pURL, strlen(pURL), RTL_TEXTENCODING_UTF8 );
2943 if (sURL.isEmpty())
2944 {
2945 pLib->maLastExceptionMsg = "Macro to run was not provided.";
2946 SAL_INFO("lok", "Macro URL is empty");
2947 return false;
2948 }
2949
2950 if (!sURL.startsWith("macro://"))
2951 {
2952 pLib->maLastExceptionMsg = "This doesn't look like macro URL";
2953 SAL_INFO("lok", "Macro URL is invalid");
2954 return false;
2955 }
2956
2957 pLib->maLastExceptionMsg.clear();
2958
2959 if (!xContext.is())
2960 {
2961 pLib->maLastExceptionMsg = "ComponentContext is not available";
2962 SAL_INFO("lok", "ComponentContext is not available");
2963 return false;
2964 }
2965
2966 util::URL aURL;
2967 aURL.Complete = sURL;
2968
2970
2971 if( xParser.is() )
2972 xParser->parseStrict( aURL );
2973
2975
2976 if (!xComponentLoader.is())
2977 {
2978 pLib->maLastExceptionMsg = "ComponentLoader is not available";
2979 SAL_INFO("lok", "ComponentLoader is not available");
2980 return false;
2981 }
2982
2983 xFactory = xContext->getServiceManager();
2984
2985 if (!xFactory)
2986 return false;
2987
2989 xSFactory.set(xFactory, uno::UNO_QUERY_THROW);
2990 xDP.set( xSFactory->createInstance("com.sun.star.comp.sfx2.SfxMacroLoader"), uno::UNO_QUERY );
2991 uno::Reference<frame::XDispatch> xD = xDP->queryDispatch( aURL, OUString(), 0);
2992
2993 if (!xD.is())
2994 {
2995 pLib->maLastExceptionMsg = "Macro loader is not available";
2996 SAL_INFO("lok", "Macro loader is not available");
2997 return false;
2998 }
2999
3000 uno::Reference < frame::XSynchronousDispatch > xSyncDisp( xD, uno::UNO_QUERY_THROW );
3002 css::beans::PropertyValue aErr;
3003 uno::Any aRet = xSyncDisp->dispatchWithReturnValue( aURL, aEmpty );
3004 aRet >>= aErr;
3005
3006 if (aErr.Name == "ErrorCode")
3007 {
3008 sal_uInt32 nErrCode = 0; // ERRCODE_NONE
3009 aErr.Value >>= nErrCode;
3010
3011 pLib->maLastExceptionMsg = "An error occurred running macro (error code: " + OUString::number( nErrCode ) + ")";
3012 SAL_INFO("lok", "Macro execution terminated with error code " << nErrCode);
3013
3014 return false;
3015 }
3016
3017 return true;
3018}
3019
3020static bool lo_signDocument(LibreOfficeKit* /*pThis*/,
3021 const char* pURL,
3022 const unsigned char* pCertificateBinary,
3023 const int nCertificateBinarySize,
3024 const unsigned char* pPrivateKeyBinary,
3025 const int nPrivateKeyBinarySize)
3026{
3027 comphelper::ProfileZone aZone("lo_signDocument");
3028
3029 OUString aURL(getAbsoluteURL(pURL));
3030 if (aURL.isEmpty())
3031 return false;
3032
3033 if (!xContext.is())
3034 return false;
3035
3036 uno::Sequence<sal_Int8> aCertificateSequence;
3037
3038 std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize);
3039 std::string aCertificateBase64String = extractCertificate(aCertificateString);
3040 if (!aCertificateBase64String.empty())
3041 {
3042 OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String);
3043 comphelper::Base64::decode(aCertificateSequence, aBase64OUString);
3044 }
3045 else
3046 {
3047 aCertificateSequence.realloc(nCertificateBinarySize);
3048 std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.getArray());
3049 }
3050
3051 uno::Sequence<sal_Int8> aPrivateKeySequence;
3052 std::string aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary), nPrivateKeyBinarySize);
3053 std::string aPrivateKeyBase64String = extractPrivateKey(aPrivateKeyString);
3054 if (!aPrivateKeyBase64String.empty())
3055 {
3056 OUString aBase64OUString = OUString::createFromAscii(aPrivateKeyBase64String);
3057 comphelper::Base64::decode(aPrivateKeySequence, aBase64OUString);
3058 }
3059 else
3060 {
3061 aPrivateKeySequence.realloc(nPrivateKeyBinarySize);
3062 std::copy(pPrivateKeyBinary, pPrivateKeyBinary + nPrivateKeyBinarySize, aPrivateKeySequence.getArray());
3063 }
3064
3066 uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
3067 if (!xSecurityContext.is())
3068 return false;
3069
3070 uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
3071 uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY);
3072
3073 if (!xCertificateCreator.is())
3074 return false;
3075
3076 uno::Reference<security::XCertificate> xCertificate = xCertificateCreator->createDERCertificateWithPrivateKey(aCertificateSequence, aPrivateKeySequence);
3077
3078 if (!xCertificate.is())
3079 return false;
3080
3081 sfx2::DocumentSigner aDocumentSigner(aURL);
3082 if (!aDocumentSigner.signDocument(xCertificate))
3083 return false;
3084
3085 return true;
3086}
3087
3088
3089static char* lo_extractRequest(LibreOfficeKit* /*pThis*/, const char* pFilePath)
3090{
3093 OUString aURL(getAbsoluteURL(pFilePath));
3094 OUString result;
3095 if (!aURL.isEmpty())
3096 {
3097 if (xComponentLoader.is())
3098 {
3099 try
3100 {
3102 {
3103 {"Hidden", css::uno::Any(true)},
3104 {"ReadOnly", css::uno::Any(true)}
3105 }));
3106 xComp = xComponentLoader->loadComponentFromURL( aURL, "_blank", 0, aFilterOptions );
3107 }
3108 catch ( const lang::IllegalArgumentException& ex )
3109 {
3110 SAL_WARN("lok", "lo_extractRequest: IllegalArgumentException: " << ex.Message);
3111 result = "{ }";
3112 return convertOUString(result);
3113 }
3114 catch (...)
3115 {
3116 SAL_WARN("lok", "lo_extractRequest: Exception on loadComponentFromURL, url= " << aURL);
3117 result = "{ }";
3118 return convertOUString(result);
3119 }
3120
3121 if (xComp.is())
3122 {
3123 uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, uno::UNO_QUERY );
3124
3125 if( xLTS.is() )
3126 {
3127 tools::JsonWriter aJson;
3128 {
3129 auto aNode = aJson.startNode("Targets");
3130 extractLinks(xLTS->getLinks(), false, aJson);
3131 }
3132 return strdup(aJson.finishAndGetAsOString().getStr());
3133 }
3134 xComp->dispose();
3135 }
3136 else
3137 {
3138 result = "{ }";
3139 return convertOUString(result);
3140 }
3141
3142 }
3143 }
3144 result = "{ }";
3145 return convertOUString(result);
3146}
3147
3148static void lo_trimMemory(LibreOfficeKit* /* pThis */, int nTarget)
3149{
3150 vcl::lok::trimMemory(nTarget);
3151 if (nTarget > 1000)
3152 {
3153#ifdef HAVE_MALLOC_TRIM
3154 malloc_trim(0);
3155#endif
3156 }
3157}
3158
3159static void lo_registerCallback (LibreOfficeKit* pThis,
3160 LibreOfficeKitCallback pCallback,
3161 void* pData)
3162{
3163 SolarMutexGuard aGuard;
3164
3165 Application* pApp = GetpApp();
3166 assert(pApp);
3167
3168 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
3169 pLib->maLastExceptionMsg.clear();
3170
3171 pApp->m_pCallback = pLib->mpCallback = pCallback;
3172 pApp->m_pCallbackData = pLib->mpCallbackData = pData;
3173}
3174
3175static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const char* pFormat, const char* pFilterOptions)
3176{
3177 comphelper::ProfileZone aZone("doc_saveAs");
3178
3179 SolarMutexGuard aGuard;
3181
3182 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
3183
3184 OUString sFormat = getUString(pFormat);
3185 OUString aURL(getAbsoluteURL(sUrl));
3186
3187 uno::Reference<frame::XStorable> xStorable(pDocument->mxComponent, uno::UNO_QUERY_THROW);
3188
3189 if (aURL.isEmpty())
3190 {
3191 SetLastExceptionMsg("Filename to save to was not provided.");
3192 SAL_INFO("lok", "URL for save is empty");
3193 return false;
3194 }
3195
3196 try
3197 {
3198 const ExtensionMap* pMap;
3199
3200 switch (doc_getDocumentType(pThis))
3201 {
3202 case LOK_DOCTYPE_SPREADSHEET:
3203 pMap = aCalcExtensionMap;
3204 break;
3205 case LOK_DOCTYPE_PRESENTATION:
3206 pMap = aImpressExtensionMap;
3207 break;
3208 case LOK_DOCTYPE_DRAWING:
3209 pMap = aDrawExtensionMap;
3210 break;
3211 case LOK_DOCTYPE_TEXT:
3212 pMap = aWriterExtensionMap;
3213 break;
3214 case LOK_DOCTYPE_OTHER:
3215 default:
3216 SAL_INFO("lok", "Can't save document - unsupported document type.");
3217 return false;
3218 }
3219
3220 if (pFormat == nullptr)
3221 {
3222 // sniff from the extension
3223 sal_Int32 idx = aURL.lastIndexOf(".");
3224 if( idx > 0 )
3225 {
3226 sFormat = aURL.copy( idx + 1 );
3227 }
3228 else
3229 {
3230 SetLastExceptionMsg("input URL '" + aURL + "' lacks a suffix");
3231 return false;
3232 }
3233 }
3234
3235 OUString aFilterName;
3236 for (sal_Int32 i = 0; pMap[i].extn; ++i)
3237 {
3238 if (sFormat.equalsIgnoreAsciiCaseAscii(pMap[i].extn))
3239 {
3240 aFilterName = getUString(pMap[i].filterName);
3241 break;
3242 }
3243 }
3244 if (aFilterName.isEmpty())
3245 {
3246 SetLastExceptionMsg("no output filter found for provided suffix");
3247 return false;
3248 }
3249
3250 OUString aFilterOptions = getUString(pFilterOptions);
3251
3252 // Check if watermark for pdf is passed by filteroptions...
3253 // It is not a real filter option so it must be filtered out.
3254 OUString watermarkText;
3255 std::u16string_view sFullSheetPreview;
3256 int aIndex = -1;
3257 if ((aIndex = aFilterOptions.indexOf(",Watermark=")) >= 0)
3258 {
3259 int bIndex = aFilterOptions.indexOf("WATERMARKEND");
3260 watermarkText = aFilterOptions.subView(aIndex+11, bIndex-(aIndex+11));
3261 aFilterOptions = OUString::Concat(aFilterOptions.subView(0, aIndex)) + aFilterOptions.subView(bIndex+12);
3262 }
3263
3264 if ((aIndex = aFilterOptions.indexOf(",FullSheetPreview=")) >= 0)
3265 {
3266 int bIndex = aFilterOptions.indexOf("FULLSHEETPREVEND");
3267 sFullSheetPreview = aFilterOptions.subView(aIndex+18, bIndex-(aIndex+18));
3268 aFilterOptions = OUString::Concat(aFilterOptions.subView(0, aIndex)) + aFilterOptions.subView(bIndex+16);
3269 }
3270
3271 bool bFullSheetPreview = sFullSheetPreview == u"true";
3272
3273 OUString filePassword;
3274 if ((aIndex = aFilterOptions.indexOf(",Password=")) >= 0)
3275 {
3276 int bIndex = aFilterOptions.indexOf("PASSWORDEND");
3277 filePassword = aFilterOptions.subView(aIndex + 10, bIndex - (aIndex + 10));
3278 aFilterOptions = OUString::Concat(aFilterOptions.subView(0, aIndex))
3279 + aFilterOptions.subView(bIndex + 11);
3280 }
3281 OUString filePasswordToModify;
3282 if ((aIndex = aFilterOptions.indexOf(",PasswordToModify=")) >= 0)
3283 {
3284 int bIndex = aFilterOptions.indexOf("PASSWORDTOMODIFYEND");
3285 filePassword = aFilterOptions.subView(aIndex + 18, bIndex - (aIndex + 18));
3286 aFilterOptions = OUString::Concat(aFilterOptions.subView(0, aIndex))
3287 + aFilterOptions.subView(bIndex + 19);
3288 }
3289
3290 // Select a pdf version if specified a valid one. If not specified then ignore.
3291 // If invalid then fail.
3292 sal_Int32 pdfVer = 0;
3293 if ((aIndex = aFilterOptions.indexOf(",PDFVer=")) >= 0)
3294 {
3295 int bIndex = aFilterOptions.indexOf("PDFVEREND");
3296 std::u16string_view sPdfVer = aFilterOptions.subView(aIndex+8, bIndex-(aIndex+8));
3297 aFilterOptions = OUString::Concat(aFilterOptions.subView(0, aIndex)) + aFilterOptions.subView(bIndex+9);
3298
3299 if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF/A-1b"))
3300 pdfVer = 1;
3301 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF/A-2b"))
3302 pdfVer = 2;
3303 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF/A-3b"))
3304 pdfVer = 3;
3305 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF-1.5"))
3306 pdfVer = 15;
3307 else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF-1.6"))
3308 pdfVer = 16;
3309 else
3310 {
3311 SetLastExceptionMsg("wrong PDF version");
3312 return false;
3313 }
3314 }
3315
3316 // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
3317 // gets a new name). When this is not provided, the meaning of
3318 // saveAs() is more like save-a-copy, which allows saving to any
3319 // random format like PDF or PNG.
3320 // It is not a real filter option, so we have to filter it out.
3321 const uno::Sequence<OUString> aOptionSeq = comphelper::string::convertCommaSeparated(aFilterOptions);
3322 std::vector<OUString> aFilteredOptionVec;
3323 bool bTakeOwnership = false;
3324 MediaDescriptor aSaveMediaDescriptor;
3325 for (const auto& rOption : aOptionSeq)
3326 {
3327 if (rOption == "TakeOwnership")
3328 bTakeOwnership = true;
3329 else if (rOption == "NoFileSync")
3330 aSaveMediaDescriptor["NoFileSync"] <<= true;
3331 else
3332 aFilteredOptionVec.push_back(rOption);
3333 }
3334
3335 aSaveMediaDescriptor["Overwrite"] <<= true;
3336 aSaveMediaDescriptor["FilterName"] <<= aFilterName;
3337
3338 auto aFilteredOptionSeq = comphelper::containerToSequence<OUString>(aFilteredOptionVec);
3339 aFilterOptions = comphelper::string::convertCommaSeparated(aFilteredOptionSeq);
3340 aSaveMediaDescriptor[MediaDescriptor::PROP_FILTEROPTIONS] <<= aFilterOptions;
3341
3342 comphelper::SequenceAsHashMap aFilterDataMap;
3343
3344 // If filter options is JSON string, then make sure aFilterDataMap stays empty, otherwise we
3345 // would ignore the filter options.
3346 if (!aFilterOptions.startsWith("{"))
3347 {
3348 setFormatSpecificFilterData(sFormat, aFilterDataMap);
3349 }
3350
3351 if (!watermarkText.isEmpty())
3352 aFilterDataMap["TiledWatermark"] <<= watermarkText;
3353
3354 if (bFullSheetPreview)
3355 aFilterDataMap["SinglePageSheets"] <<= true;
3356
3357 if (pdfVer)
3358 aFilterDataMap["SelectPdfVersion"] <<= pdfVer;
3359
3360 if (!aFilterDataMap.empty())
3361 {
3362 aSaveMediaDescriptor["FilterData"] <<= aFilterDataMap.getAsConstPropertyValueList();
3363 }
3364 if (!filePassword.isEmpty())
3365 aSaveMediaDescriptor["Password"] <<= filePassword;
3366 if (!filePasswordToModify.isEmpty())
3367 aSaveMediaDescriptor["PasswordToModify"] <<= filePasswordToModify;
3368
3369 // add interaction handler too
3370 if (gImpl)
3371 {
3372 // gImpl does not have to exist when running from a unit test
3373 rtl::Reference<LOKInteractionHandler> const pInteraction(
3374 new LOKInteractionHandler("saveas", gImpl, pDocument));
3375 uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction);
3376
3377 aSaveMediaDescriptor[MediaDescriptor::PROP_INTERACTIONHANDLER] <<= xInteraction;
3378 }
3379
3380
3381 if (bTakeOwnership)
3382 xStorable->storeAsURL(aURL, aSaveMediaDescriptor.getAsConstPropertyValueList());
3383 else
3384 xStorable->storeToURL(aURL, aSaveMediaDescriptor.getAsConstPropertyValueList());
3385
3386 return true;
3387 }
3388 catch (const uno::Exception& exception)
3389 {
3390 SetLastExceptionMsg("exception: " + exception.Message);
3391 }
3392 return false;
3393}
3394
3402{
3403 SolarMutexGuard aGuard;
3405
3406 OUString sUnoCommands[] =
3407 {
3408 OUString(".uno:AlignLeft"),
3409 OUString(".uno:AlignHorizontalCenter"),
3410 OUString(".uno:AlignRight"),
3411 OUString(".uno:BackColor"),
3412 OUString(".uno:BackgroundColor"),
3413 OUString(".uno:TableCellBackgroundColor"),
3414 OUString(".uno:Bold"),
3415 OUString(".uno:CenterPara"),
3416 OUString(".uno:CharBackColor"),
3417 OUString(".uno:CharBackgroundExt"),
3418 OUString(".uno:CharFontName"),
3419 OUString(".uno:Color"),
3420 OUString(".uno:ControlCodes"),
3421 OUString(".uno:DecrementIndent"),
3422 OUString(".uno:DefaultBullet"),
3423 OUString(".uno:DefaultNumbering"),
3424 OUString(".uno:FontColor"),
3425 OUString(".uno:FontHeight"),
3426 OUString(".uno:IncrementIndent"),
3427 OUString(".uno:Italic"),
3428 OUString(".uno:JustifyPara"),
3429 OUString(".uno:JumpToMark"),
3430 OUString(".uno:OutlineFont"),
3431 OUString(".uno:LeftPara"),
3432 OUString(".uno:LanguageStatus"),
3433 OUString(".uno:RightPara"),
3434 OUString(".uno:Shadowed"),
3435 OUString(".uno:SubScript"),
3436 OUString(".uno:SuperScript"),
3437 OUString(".uno:Strikeout"),
3438 OUString(".uno:StyleApply"),
3439 OUString(".uno:Underline"),
3440 OUString(".uno:ModifiedStatus"),
3441 OUString(".uno:Undo"),
3442 OUString(".uno:Redo"),
3443 OUString(".uno:InsertPage"),
3444 OUString(".uno:DeletePage"),
3445 OUString(".uno:DuplicatePage"),
3446 OUString(".uno:InsertSlide"),
3447 OUString(".uno:DeleteSlide"),
3448 OUString(".uno:DuplicateSlide"),
3449 OUString(".uno:ChangeTheme"),
3450 OUString(".uno:Cut"),
3451 OUString(".uno:Copy"),
3452 OUString(".uno:Paste"),
3453 OUString(".uno:SelectAll"),
3454 OUString(".uno:ReplyComment"),
3455 OUString(".uno:ResolveComment"),
3456 OUString(".uno:ResolveCommentThread"),
3457 OUString(".uno:InsertRowsBefore"),
3458 OUString(".uno:InsertRowsAfter"),
3459 OUString(".uno:InsertColumnsBefore"),
3460 OUString(".uno:InsertColumnsAfter"),
3461 OUString(".uno:DeleteRows"),
3462 OUString(".uno:DeleteColumns"),
3463 OUString(".uno:DeleteTable"),
3464 OUString(".uno:SelectTable"),
3465 OUString(".uno:EntireRow"),
3466 OUString(".uno:EntireColumn"),
3467 OUString(".uno:EntireCell"),
3468 OUString(".uno:AssignLayout"),
3469 OUString(".uno:StatusDocPos"),
3470 OUString(".uno:RowColSelCount"),
3471 OUString(".uno:StatusPageStyle"),
3472 OUString(".uno:InsertMode"),
3473 OUString(".uno:SpellOnline"),
3474 OUString(".uno:StatusSelectionMode"),
3475 OUString(".uno:StateTableCell"),
3476 OUString(".uno:StatusBarFunc"),
3477 OUString(".uno:StatePageNumber"),
3478 OUString(".uno:StateWordCount"),
3479 OUString(".uno:SelectionMode"),
3480 OUString(".uno:PageStatus"),
3481 OUString(".uno:LayoutStatus"),
3482 OUString(".uno:Scale"),
3483 OUString(".uno:Context"),
3484 OUString(".uno:WrapText"),
3485 OUString(".uno:ToggleMergeCells"),
3486 OUString(".uno:NumberFormatCurrency"),
3487 OUString(".uno:NumberFormatPercent"),
3488 OUString(".uno:NumberFormatDecimal"),
3489 OUString(".uno:NumberFormatIncDecimals"),
3490 OUString(".uno:NumberFormatDecDecimals"),
3491 OUString(".uno:NumberFormatDate"),
3492 OUString(".uno:EditHeaderAndFooter"),
3493 OUString(".uno:FrameLineColor"),
3494 OUString(".uno:SortAscending"),
3495 OUString(".uno:SortDescending"),
3496 OUString(".uno:TrackChanges"),
3497 OUString(".uno:ShowTrackedChanges"),
3498 OUString(".uno:NextTrackedChange"),
3499 OUString(".uno:PreviousTrackedChange"),
3500 OUString(".uno:AcceptAllTrackedChanges"),
3501 OUString(".uno:RejectAllTrackedChanges"),
3502 OUString(".uno:TableDialog"),
3503 OUString(".uno:FormatCellDialog"),
3504 OUString(".uno:FontDialog"),
3505 OUString(".uno:ParagraphDialog"),
3506 OUString(".uno:OutlineBullet"),
3507 OUString(".uno:InsertIndexesEntry"),
3508 OUString(".uno:DocumentRepair"),
3509 OUString(".uno:TransformDialog"),
3510 OUString(".uno:InsertPageHeader"),
3511 OUString(".uno:InsertPageFooter"),
3512 OUString(".uno:OnlineAutoFormat"),
3513 OUString(".uno:InsertObjectChart"),
3514 OUString(".uno:InsertSection"),
3515 OUString(".uno:InsertAnnotation"),
3516 OUString(".uno:DeleteAnnotation"),
3517 OUString(".uno:InsertPagebreak"),
3518 OUString(".uno:InsertColumnBreak"),
3519 OUString(".uno:HyperlinkDialog"),
3520 OUString(".uno:InsertSymbol"),
3521 OUString(".uno:EditRegion"),
3522 OUString(".uno:ThesaurusDialog"),
3523 OUString(".uno:FormatArea"),
3524 OUString(".uno:FormatLine"),
3525 OUString(".uno:FormatColumns"),
3526 OUString(".uno:Watermark"),
3527 OUString(".uno:ResetAttributes"),
3528 OUString(".uno:Orientation"),
3529 OUString(".uno:ObjectAlignLeft"),
3530 OUString(".uno:ObjectAlignRight"),
3531 OUString(".uno:AlignCenter"),
3532 OUString(".uno:TransformPosX"),
3533 OUString(".uno:TransformPosY"),
3534 OUString(".uno:TransformWidth"),
3535 OUString(".uno:TransformHeight"),
3536 OUString(".uno:ObjectBackOne"),
3537 OUString(".uno:SendToBack"),
3538 OUString(".uno:ObjectForwardOne"),
3539 OUString(".uno:BringToFront"),
3540 OUString(".uno:WrapRight"),
3541 OUString(".uno:WrapThrough"),
3542 OUString(".uno:WrapLeft"),
3543 OUString(".uno:WrapIdeal"),
3544 OUString(".uno:WrapOn"),
3545 OUString(".uno:WrapOff"),
3546 OUString(".uno:UpdateCurIndex"),
3547 OUString(".uno:InsertCaptionDialog"),
3548 OUString(".uno:FormatGroup"),
3549 OUString(".uno:SplitTable"),
3550 OUString(".uno:SplitCell"),
3551 OUString(".uno:MergeCells"),
3552 OUString(".uno:DeleteNote"),
3553 OUString(".uno:AcceptChanges"),
3554 OUString(".uno:FormatPaintbrush"),
3555 OUString(".uno:SetDefault"),
3556 OUString(".uno:ParaLeftToRight"),
3557 OUString(".uno:ParaRightToLeft"),
3558 OUString(".uno:ParaspaceIncrease"),
3559 OUString(".uno:ParaspaceDecrease"),
3560 OUString(".uno:AcceptTrackedChange"),
3561 OUString(".uno:RejectTrackedChange"),
3562 OUString(".uno:ShowResolvedAnnotations"),
3563 OUString(".uno:InsertBreak"),
3564 OUString(".uno:InsertEndnote"),
3565 OUString(".uno:InsertFootnote"),
3566 OUString(".uno:InsertReferenceField"),
3567 OUString(".uno:InsertBookmark"),
3568 OUString(".uno:InsertAuthoritiesEntry"),
3569 OUString(".uno:InsertMultiIndex"),
3570 OUString(".uno:InsertField"),
3571 OUString(".uno:PageNumberWizard"),
3572 OUString(".uno:InsertPageNumberField"),
3573 OUString(".uno:InsertPageCountField"),
3574 OUString(".uno:InsertDateField"),
3575 OUString(".uno:InsertTitleField"),
3576 OUString(".uno:InsertFieldCtrl"),
3577 OUString(".uno:CharmapControl"),
3578 OUString(".uno:EnterGroup"),
3579 OUString(".uno:LeaveGroup"),
3580 OUString(".uno:AlignUp"),
3581 OUString(".uno:AlignMiddle"),
3582 OUString(".uno:AlignDown"),
3583 OUString(".uno:TraceChangeMode"),
3584 OUString(".uno:Combine"),
3585 OUString(".uno:Merge"),
3586 OUString(".uno:Dismantle"),
3587 OUString(".uno:Substract"),
3588 OUString(".uno:DistributeSelection"),
3589 OUString(".uno:Intersect"),
3590 OUString(".uno:BorderInner"),
3591 OUString(".uno:BorderOuter"),
3592 OUString(".uno:FreezePanes"),
3593 OUString(".uno:FreezePanesColumn"),
3594 OUString(".uno:FreezePanesRow"),
3595 OUString(".uno:Sidebar"),
3596 OUString(".uno:SheetRightToLeft"),
3597 OUString(".uno:RunMacro"),
3598 OUString(".uno:SpacePara1"),
3599 OUString(".uno:SpacePara15"),
3600 OUString(".uno:SpacePara2"),
3601 OUString(".uno:InsertSparkline"),
3602 OUString(".uno:DeleteSparkline"),
3603 OUString(".uno:DeleteSparklineGroup"),
3604 OUString(".uno:EditSparklineGroup"),
3605 OUString(".uno:EditSparkline"),
3606 OUString(".uno:GroupSparklines"),
3607 OUString(".uno:UngroupSparklines"),
3608 OUString(".uno:FormatSparklineMenu"),
3609 OUString(".uno:Protect"),
3610 OUString(".uno:UnsetCellsReadOnly"),
3611 OUString(".uno:ContentControlProperties"),
3612 OUString(".uno:InsertCheckboxContentControl"),
3613 OUString(".uno:InsertContentControl"),
3614 OUString(".uno:InsertDateContentControl"),
3615 OUString(".uno:InsertDropdownContentControl"),
3616 OUString(".uno:InsertPlainTextContentControl"),
3617 OUString(".uno:InsertPictureContentControl"),
3618 OUString(".uno:DataFilterAutoFilter")
3619 };
3620
3621 util::URL aCommandURL;
3622 SfxViewShell* pViewShell = SfxViewShell::Current();
3623 SfxViewFrame* pViewFrame = pViewShell ? &pViewShell->GetViewFrame() : nullptr;
3624
3625 // check if Frame-Controller were created.
3626 if (!pViewFrame)
3627 {
3628 SAL_WARN("lok", "iniUnoCommands: No Frame-Controller created.");
3629 return;
3630 }
3631
3632 if (!xContext.is())
3634 if (!xContext.is())
3635 {
3636 SAL_WARN("lok", "iniUnoCommands: Component context is not available");
3637 return;
3638 }
3639
3640#if !defined IOS && !defined ANDROID && !defined __EMSCRIPTEN__
3642 if (!xSEInitializer.is())
3643 {
3644 SAL_WARN("lok", "iniUnoCommands: XSEInitializer is not available");
3645 return;
3646 }
3647
3649 xSEInitializer->createSecurityContext(OUString());
3650 if (!xSecurityContext.is())
3651 {
3652 SAL_WARN("lok", "iniUnoCommands: failed to create security context");
3653 }
3654#endif
3655
3656 SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool(pViewFrame);
3658
3659 for (const auto & sUnoCommand : sUnoCommands)
3660 {
3661 aCommandURL.Complete = sUnoCommand;
3662 xParser->parseStrict(aCommandURL);
3663
3664 // when null, this command is not supported by the given component
3665 // (like eg. Calc does not have ".uno:DefaultBullet" etc.)
3666 if (const SfxSlot* pSlot = rSlotPool.GetUnoSlot(aCommandURL.Path))
3667 {
3668 // Initialize slot to dispatch .uno: Command.
3669 pViewFrame->GetBindings().GetDispatch(pSlot, aCommandURL, false);
3670 }
3671 }
3672}
3673
3674static int doc_getDocumentType (LibreOfficeKitDocument* pThis)
3675{
3676 comphelper::ProfileZone aZone("doc_getDocumentType");
3677
3678 SolarMutexGuard aGuard;
3679 return getDocumentType(pThis);
3680}
3681
3682static int doc_getParts (LibreOfficeKitDocument* pThis)
3683{
3684 comphelper::ProfileZone aZone("doc_getParts");
3685
3686 SolarMutexGuard aGuard;
3687
3688 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3689 if (!pDoc)
3690 {
3691 SetLastExceptionMsg("Document doesn't support tiled rendering");
3692 return 0;
3693 }
3694
3695 return pDoc->getParts();
3696}
3697
3698static int doc_getPart (LibreOfficeKitDocument* pThis)
3699{
3700 comphelper::ProfileZone aZone("doc_getPart");
3701
3702 SolarMutexGuard aGuard;
3704
3705 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3706 if (!pDoc)
3707 {
3708 SetLastExceptionMsg("Document doesn't support tiled rendering");
3709 return 0;
3710 }
3711
3712 return pDoc->getPart();
3713}
3714
3715static void doc_setPartImpl(LibreOfficeKitDocument* pThis, int nPart, bool bAllowChangeFocus = true)
3716{
3717 comphelper::ProfileZone aZone("doc_setPart");
3718
3719 SolarMutexGuard aGuard;
3721
3722 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3723 if (!pDoc)
3724 {
3725 SetLastExceptionMsg("Document doesn't support tiled rendering");
3726 return;
3727 }
3728
3729 pDoc->setPart( nPart, bAllowChangeFocus );
3730}
3731
3732static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart)
3733{
3734 doc_setPartImpl(pThis, nPart, true);
3735}
3736
3737static char* doc_getPartInfo(LibreOfficeKitDocument* pThis, int nPart)
3738{
3739 comphelper::ProfileZone aZone("doc_getPartInfo");
3740
3741 SolarMutexGuard aGuard;
3742 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3743 if (!pDoc)
3744 {
3745 SetLastExceptionMsg("Document doesn't support tiled rendering");
3746 return nullptr;
3747 }
3748
3749 return convertOUString(pDoc->getPartInfo(nPart));
3750}
3751
3752static void doc_selectPart(LibreOfficeKitDocument* pThis, int nPart, int nSelect)
3753{
3754 SolarMutexGuard aGuard;
3755 if (gImpl)
3756 gImpl->maLastExceptionMsg.clear();
3757
3758 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3759 if (!pDoc)
3760 {
3761 gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
3762 return;
3763 }
3764
3765 pDoc->selectPart( nPart, nSelect );
3766}
3767
3768static void doc_moveSelectedParts(LibreOfficeKitDocument* pThis, int nPosition, bool bDuplicate)
3769{
3770 SolarMutexGuard aGuard;
3771 if (gImpl)
3772 gImpl->maLastExceptionMsg.clear();
3773
3774 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3775 if (!pDoc)
3776 {
3777 gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
3778 return;
3779 }
3780
3781 pDoc->moveSelectedParts(nPosition, bDuplicate);
3782}
3783
3784static char* doc_getPartPageRectangles(LibreOfficeKitDocument* pThis)
3785{
3786 comphelper::ProfileZone aZone("doc_getPartPageRectangles");
3787
3788 SolarMutexGuard aGuard;
3790
3791 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3792 if (!pDoc)
3793 {
3794 SetLastExceptionMsg("Document doesn't support tiled rendering");
3795 return nullptr;
3796 }
3797
3798 return convertOUString(pDoc->getPartPageRectangles());
3799}
3800
3801static char* doc_getA11yFocusedParagraph(LibreOfficeKitDocument* pThis)
3802{
3803 SolarMutexGuard aGuard;
3805
3806 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3807 if (!pDoc)
3808 {
3809 SetLastExceptionMsg("Document doesn't support tiled rendering");
3810 return nullptr;
3811 }
3812
3813 if (SfxViewShell* pViewShell = SfxViewShell::Current())
3814 {
3815 return convertOUString(pViewShell->getA11yFocusedParagraph());
3816
3817 }
3818 return nullptr;
3819}
3820
3821static int doc_getA11yCaretPosition(LibreOfficeKitDocument* pThis)
3822{
3823 SolarMutexGuard aGuard;
3825
3826 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3827 if (!pDoc)
3828 {
3829 SetLastExceptionMsg("Document doesn't support tiled rendering");
3830 return -1;
3831 }
3832 if (SfxViewShell* pViewShell = SfxViewShell::Current())
3833 {
3834 return pViewShell->getA11yCaretPosition();
3835
3836 }
3837 return -1;
3838
3839}
3840
3841static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart)
3842{
3843 comphelper::ProfileZone aZone("doc_getPartName");
3844
3845 SolarMutexGuard aGuard;
3847
3848 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3849 if (!pDoc)
3850 {
3851 SetLastExceptionMsg("Document doesn't support tiled rendering");
3852 return nullptr;
3853 }
3854
3855 return convertOUString(pDoc->getPartName(nPart));
3856}
3857
3858static char* doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart)
3859{
3860 comphelper::ProfileZone aZone("doc_getPartHash");
3861
3862 SolarMutexGuard aGuard;
3864
3865 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3866 if (!pDoc)
3867 {
3868 SetLastExceptionMsg("Document doesn't support tiled rendering");
3869 return nullptr;
3870 }
3871
3872 return convertOUString(pDoc->getPartHash(nPart));
3873}
3874
3875static void doc_setPartMode(LibreOfficeKitDocument* pThis,
3876 int nPartMode)
3877{
3878 comphelper::ProfileZone aZone("doc_setPartMode");
3879
3880 SolarMutexGuard aGuard;
3882
3883 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3884 if (!pDoc)
3885 {
3886 SetLastExceptionMsg("Document doesn't support tiled rendering");
3887 return;
3888 }
3889
3890
3891 int nCurrentPart = pDoc->getPart();
3892
3893 pDoc->setPartMode(nPartMode);
3894
3895 // We need to make sure the internal state is updated, just changing the mode
3896 // might not update the relevant shells (i.e. impress will keep rendering the
3897 // previous mode unless we do this).
3898 // TODO: we might want to do this within the relevant components rather than
3899 // here, but that's also dependent on how we implement embedded object
3900 // rendering I guess?
3901 // TODO: we could be clever and e.g. set to 0 when we change to/from
3902 // embedded object mode, and not when changing between slide/notes/combined
3903 // modes?
3904 if ( nCurrentPart < pDoc->getParts() )
3905 {
3906 pDoc->setPart( nCurrentPart );
3907 }
3908 else
3909 {
3910 pDoc->setPart( 0 );
3911 }
3912}
3913
3914static int doc_getEditMode(LibreOfficeKitDocument* pThis)
3915{
3916 comphelper::ProfileZone aZone("doc_getEditMode");
3917
3918 SolarMutexGuard aGuard;
3920
3921 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3922 if (!pDoc)
3923 {
3924 SetLastExceptionMsg("Document doesn't support tiled rendering");
3925 return 0;
3926 }
3927
3928 return pDoc->getEditMode();
3929}
3930
3931static void doc_paintTile(LibreOfficeKitDocument* pThis,
3932 unsigned char* pBuffer,
3933 const int nCanvasWidth, const int nCanvasHeight,
3934 const int nTilePosX, const int nTilePosY,
3935 const int nTileWidth, const int nTileHeight)
3936{
3937 comphelper::ProfileZone aZone("doc_paintTile");
3938
3939 SolarMutexGuard aGuard;
3941
3942 SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth << "x" << nTileHeight <<
3943 "]@(" << nTilePosX << ", " << nTilePosY << ") to [" <<
3944 nCanvasWidth << "x" << nCanvasHeight << "]px" );
3945
3946 ITiledRenderable* pDoc = getTiledRenderable(pThis);
3947 if (!pDoc)
3948 {
3949 SetLastExceptionMsg("Document doesn't support tiled rendering");
3950 return;
3951 }
3952
3953#if defined(UNX) && !defined(MACOSX) || defined(_WIN32)
3954
3955 // Painting of zoomed or HiDPI spreadsheets is special, we actually draw everything at 100%,
3956 // and only set cairo's (or CoreGraphic's, in the iOS case) scale factor accordingly, so that
3957 // everything is painted bigger or smaller. This is different to what Calc's internal scaling
3958 // would do - because that one is trying to fit the lines between cells to integer multiples of
3959 // pixels.
3961
3962#if defined(IOS)
3963 double fDPIScale = 1.0;
3964
3965 // Onine uses the LOK_TILEMODE_RGBA by default so flip the normal flags
3966 // to kCGImageAlphaPremultipliedLast | kCGImageByteOrder32Big
3967 CGContextRef pCGContext = CGBitmapContextCreate(pBuffer, nCanvasWidth, nCanvasHeight, 8,
3968 nCanvasWidth * 4, CGColorSpaceCreateDeviceRGB(),
3969 kCGImageAlphaPremultipliedLast | kCGImageByteOrder32Big);
3970
3971 CGContextTranslateCTM(pCGContext, 0, nCanvasHeight);
3972 CGContextScaleCTM(pCGContext, fDPIScale, -fDPIScale);
3973
3974 SAL_INFO( "lok.tiledrendering", "doc_paintTile: painting [" << nTileWidth << "x" << nTileHeight <<
3975 "]@(" << nTilePosX << ", " << nTilePosY << ") to [" <<
3976 nCanvasWidth << "x" << nCanvasHeight << "]px" );
3977
3978 Size aCanvasSize(nCanvasWidth, nCanvasHeight);
3979
3981 aData.rCGContext = reinterpret_cast<CGContextRef>(pCGContext);
3982
3983 ScopedVclPtrInstance<VirtualDevice> pDevice(aData, Size(1, 1), DeviceFormat::WITHOUT_ALPHA);
3984 pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
3985 pDevice->SetOutputSizePixel(aCanvasSize);
3986 pDoc->paintTile(*pDevice, aCanvasSize.Width(), aCanvasSize.Height(),
3987 nTilePosX, nTilePosY, nTileWidth, nTileHeight);
3988
3989 CGContextRelease(pCGContext);
3990#else
3991 ScopedVclPtrInstance< VirtualDevice > pDevice(DeviceFormat::WITHOUT_ALPHA);
3992
3993 // Set background to transparent by default.
3994 pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
3995
3996 pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(
3997 Size(nCanvasWidth, nCanvasHeight), Fraction(1.0), Point(),
3998 pBuffer);
3999
4000 pDoc->paintTile(*pDevice, nCanvasWidth, nCanvasHeight,
4001 nTilePosX, nTilePosY, nTileWidth, nTileHeight);
4002
4003 static bool bDebug = getenv("LOK_DEBUG_TILES") != nullptr;
4004 if (bDebug)
4005 {
4006 // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
4007 tools::Rectangle aRect(0, 0, 5, 5);
4008 aRect = pDevice->PixelToLogic(aRect);
4009 pDevice->Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
4010 pDevice->SetFillColor(COL_LIGHTRED);
4011 pDevice->SetLineColor();
4012 pDevice->DrawRect(aRect);
4013 pDevice->Pop();
4014 }
4015
4016#ifdef _WIN32
4017 // pBuffer was not used there
4018 pDevice->EnableMapMode(false);
4019 BitmapEx aBmpEx = pDevice->GetBitmapEx({ 0, 0 }, { nCanvasWidth, nCanvasHeight });
4020 Bitmap aBmp = aBmpEx.GetBitmap();
4021 AlphaMask aAlpha = aBmpEx.GetAlphaMask();
4022 Bitmap::ScopedReadAccess sraBmp(aBmp);
4023 Bitmap::ScopedReadAccess sraAlpha(aAlpha);
4024
4025 assert(sraBmp->Height() == nCanvasHeight);
4026 assert(sraBmp->Width() == nCanvasWidth);
4027 assert(!sraAlpha || sraBmp->Height() == sraAlpha->Height());
4028 assert(!sraAlpha || sraBmp->Width() == sraAlpha->Width());
4029 auto p = pBuffer;
4030 for (tools::Long y = 0; y < sraBmp->Height(); ++y)
4031 {
4032 Scanline dataBmp = sraBmp->GetScanline(y);
4033 Scanline dataAlpha = sraAlpha ? sraAlpha->GetScanline(y) : nullptr;
4034 for (tools::Long x = 0; x < sraBmp->Width(); ++x)
4035 {
4036 BitmapColor color = sraBmp->GetPixelFromData(dataBmp, x);
4037 sal_uInt8 alpha = dataAlpha ? sraAlpha->GetPixelFromData(dataAlpha, x).GetBlue() : 255;
4038 *p++ = color.GetBlue();
4039 *p++ = color.GetGreen();
4040 *p++ = color.GetRed();
4041 *p++ = alpha;
4042 }
4043 }
4044#endif
4045#endif
4046
4047#else
4048 (void) pBuffer;
4049#endif
4050}
4051
4052static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
4053 unsigned char* pBuffer,
4054 const int nPart,
4055 const int nMode,
4056 const int nCanvasWidth, const int nCanvasHeight,
4057 const int nTilePosX, const int nTilePosY,
4058 const int nTileWidth, const int nTileHeight)
4059{
4060 comphelper::ProfileZone aZone("doc_paintPartTile");
4061
4062 SolarMutexGuard aGuard;
4064
4065 SAL_INFO( "lok.tiledrendering", "paintPartTile: painting @ " << nPart << " : " << nMode << " ["
4066 << nTileWidth << "x" << nTileHeight << "]@("
4067 << nTilePosX << ", " << nTilePosY << ") to ["
4068 << nCanvasWidth << "x" << nCanvasHeight << "]px" );
4069
4070 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
4071 int nOrigViewId = doc_getView(pThis);
4072
4073 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4074 if (!pDoc)
4075 {
4076 SetLastExceptionMsg("Document doesn't support tiled rendering");
4077 return;
4078 }
4079
4080 if (nOrigViewId < 0)
4081 {
4082 // tile painting always needs a SfxViewShell::Current(), but actually
4083 // it does not really matter which one - all of them should paint the
4084 // same thing. It's important to get a view for the correct document,
4085 // though.
4086 // doc_getViewsCount() returns the count of views for the document in the current view.
4087 int viewCount = doc_getViewsCount(pThis);
4088 if (viewCount == 0)
4089 return;
4090
4091 std::vector<int> viewIds(viewCount);
4092 doc_getViewIds(pThis, viewIds.data(), viewCount);
4093
4094 nOrigViewId = viewIds[0];
4095 doc_setView(pThis, nOrigViewId);
4096 }
4097
4098 // Disable callbacks while we are painting.
4099 if (nOrigViewId >= 0)
4100 {
4101 const auto handlerIt = pDocument->mpCallbackFlushHandlers.find(nOrigViewId);
4102 if (handlerIt != pDocument->mpCallbackFlushHandlers.end())
4103 handlerIt->second->disableCallbacks();
4104 }
4105
4106 try
4107 {
4108 // Text documents have a single coordinate system; don't change part.
4109 int nOrigPart = 0;
4110 const int aType = doc_getDocumentType(pThis);
4111 const bool isText = (aType == LOK_DOCTYPE_TEXT);
4112 const bool isCalc = (aType == LOK_DOCTYPE_SPREADSHEET);
4113 int nOrigEditMode = 0;
4114 bool bPaintTextEdit = true;
4115 int nViewId = nOrigViewId;
4116 int nLastNonEditorView = -1;
4117 int nViewMatchingMode = -1;
4118 if (!isText)
4119 {
4120 // Check if just switching to another view is enough, that has
4121 // less side-effects.
4122 if (nPart != doc_getPart(pThis) || nMode != pDoc->getEditMode())
4123 {
4124 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
4125 while (pViewShell)
4126 {
4127 bool bIsInEdit = pViewShell->GetDrawView() &&
4128 pViewShell->GetDrawView()->GetTextEditOutliner();
4129 if (!bIsInEdit)
4130 nLastNonEditorView = pViewShell->GetViewShellId().get();
4131
4132 if (pViewShell->getPart() == nPart &&
4133 pViewShell->getEditMode() == nMode &&
4134 !bIsInEdit)
4135 {
4136 nViewId = pViewShell->GetViewShellId().get();
4137 nViewMatchingMode = nViewId;
4138 nLastNonEditorView = nViewId;
4139 doc_setView(pThis, nViewId);
4140 break;
4141 }
4142 else if (pViewShell->getEditMode() == nMode && !bIsInEdit)
4143 {
4144 nViewMatchingMode = pViewShell->GetViewShellId().get();
4145 }
4146
4147 pViewShell = SfxViewShell::GetNext(*pViewShell);
4148 }
4149 }
4150
4151 // if not found view with correct part
4152 // - at least avoid rendering active textbox, This is for Impress.
4153 // - prefer view with the same mode
4154 SfxViewShell* pCurrentViewShell = SfxViewShell::Current();
4155 if (nViewMatchingMode >= 0 && nViewMatchingMode != nViewId)
4156 {
4157 nViewId = nViewMatchingMode;
4158 doc_setView(pThis, nViewId);
4159 }
4160 else if (!isCalc && nLastNonEditorView >= 0 && nLastNonEditorView != nViewId &&
4161 pCurrentViewShell && pCurrentViewShell->GetDrawView() &&
4162 pCurrentViewShell->GetDrawView()->GetTextEditOutliner())
4163 {
4164 nViewId = nLastNonEditorView;
4165 doc_setView(pThis, nViewId);
4166 }
4167
4168 // Disable callbacks while we are painting - after setting the view
4169 if (nViewId != nOrigViewId && nViewId >= 0)
4170 {
4171 const auto handlerIt = pDocument->mpCallbackFlushHandlers.find(nViewId);
4172 if (handlerIt != pDocument->mpCallbackFlushHandlers.end())
4173 handlerIt->second->disableCallbacks();
4174 }
4175
4176 nOrigPart = doc_getPart(pThis);
4177 if (nPart != nOrigPart)
4178 {
4179 doc_setPartImpl(pThis, nPart, false);
4180 }
4181
4182 nOrigEditMode = pDoc->getEditMode();
4183 if (nOrigEditMode != nMode)
4184 {
4185 SfxLokHelper::setEditMode(nMode, pDoc);
4186 }
4187
4188 bPaintTextEdit = (nPart == nOrigPart && nMode == nOrigEditMode);
4189 pDoc->setPaintTextEdit(bPaintTextEdit);
4190 }
4191
4192 doc_paintTile(pThis, pBuffer, nCanvasWidth, nCanvasHeight, nTilePosX, nTilePosY, nTileWidth, nTileHeight);
4193
4194 if (!isText)
4195 {
4196 pDoc->setPaintTextEdit(true);
4197
4198 if (nMode != nOrigEditMode)
4199 {
4200 SfxLokHelper::setEditMode(nOrigEditMode, pDoc);
4201 }
4202
4203 if (nPart != nOrigPart)
4204 {
4205 doc_setPartImpl(pThis, nOrigPart, false);
4206 }
4207
4208 if (nViewId != nOrigViewId)
4209 {
4210 if (nViewId >= 0)
4211 {
4212 const auto handlerIt = pDocument->mpCallbackFlushHandlers.find(nViewId);
4213 if (handlerIt != pDocument->mpCallbackFlushHandlers.end())
4214 handlerIt->second->enableCallbacks();
4215 }
4216
4217 doc_setView(pThis, nOrigViewId);
4218 }
4219 }
4220 }
4221 catch (const std::exception&)
4222 {
4223 // Nothing to do but restore the PartTilePainting flag.
4224 }
4225
4226 if (nOrigViewId >= 0)
4227 {
4228 const auto handlerIt = pDocument->mpCallbackFlushHandlers.find(nOrigViewId);
4229 if (handlerIt != pDocument->mpCallbackFlushHandlers.end())
4230 handlerIt->second->enableCallbacks();
4231 }
4232}
4233
4234static int doc_getTileMode(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/)
4235{
4237#if ENABLE_CAIRO_RGBA || defined IOS
4238 return LOK_TILEMODE_RGBA;
4239#else
4240 return LOK_TILEMODE_BGRA;
4241#endif
4242}
4243
4244static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
4245 long* pWidth,
4246 long* pHeight)
4247{
4248 comphelper::ProfileZone aZone("doc_getDocumentSize");
4249
4250 SolarMutexGuard aGuard;
4252
4253 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4254 if (pDoc)
4255 {
4256 Size aDocumentSize = pDoc->getDocumentSize();
4257 *pWidth = aDocumentSize.Width();
4258 *pHeight = aDocumentSize.Height();
4259 }
4260 else
4261 {
4262 SetLastExceptionMsg("Document doesn't support tiled rendering");
4263 }
4264}
4265
4266static void doc_getDataArea(LibreOfficeKitDocument* pThis,
4267 long nTab,
4268 long* pCol,
4269 long* pRow)
4270{
4271 comphelper::ProfileZone aZone("doc_getDataArea");
4272
4273 SolarMutexGuard aGuard;
4275
4276 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4277 if (pDoc)
4278 {
4279 Size aDocumentSize = pDoc->getDataArea(nTab);
4280 *pCol = aDocumentSize.Width();
4281 *pRow = aDocumentSize.Height();
4282 }
4283 else
4284 {
4285 SetLastExceptionMsg("Document doesn't support tiled rendering");
4286 }
4287}
4288
4289static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
4290 const char* pArguments)
4291{
4292 comphelper::ProfileZone aZone("doc_initializeForRendering");
4293
4294 SolarMutexGuard aGuard;
4296
4297 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4298 if (pDoc)
4299 {
4301 pDoc->initializeForTiledRendering(
4303 }
4304}
4305
4306static void doc_registerCallback(LibreOfficeKitDocument* pThis,
4307 LibreOfficeKitCallback pCallback,
4308 void* pData)
4309{
4310 SolarMutexGuard aGuard;
4312
4313 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
4314
4315 const int nView = SfxLokHelper::getView();
4316 if (nView < 0)
4317 return;
4318
4319 const size_t nId = nView;
4320 if (pCallback != nullptr)
4321 {
4322 for (auto& pair : pDocument->mpCallbackFlushHandlers)
4323 {
4324 if (pair.first == nId)
4325 continue;
4326
4327 pair.second->addViewStates(nView);
4328 }
4329 }
4330 else
4331 {
4332 for (auto& pair : pDocument->mpCallbackFlushHandlers)
4333 {
4334 if (pair.first == nId)
4335 continue;
4336
4337 pair.second->removeViewStates(nView);
4338 }
4339 }
4340
4341 pDocument->mpCallbackFlushHandlers[nView] = std::make_shared<CallbackFlushHandler>(pThis, pCallback, pData);
4342
4343 if (pCallback != nullptr)
4344 {
4345 for (const auto& pair : pDocument->mpCallbackFlushHandlers)
4346 {
4347 if (pair.first == nId)
4348 continue;
4349
4350 pDocument->mpCallbackFlushHandlers[nView]->addViewStates(pair.first);
4351 }
4352
4353 if (SfxViewShell* pViewShell = SfxViewShell::Current())
4354 {
4355 pDocument->mpCallbackFlushHandlers[nView]->setViewId(pViewShell->GetViewShellId().get());
4356 pViewShell->setLibreOfficeKitViewCallback(pDocument->mpCallbackFlushHandlers[nView].get());
4357 }
4358
4359 if (pDocument->maFontsMissing.size() != 0)
4360 {
4361 std::string sPayload = "{ \"fontsmissing\": [ ";
4362 bool bFirst = true;
4363 for (const auto &f : pDocument->maFontsMissing)
4364 {
4365 if (bFirst)
4366 bFirst = false;
4367 else
4368 sPayload += ", ";
4369 sPayload += "\"" + std::string(f.toUtf8()) + "\"";
4370 }
4371 sPayload += " ] }";
4372 pCallback(LOK_CALLBACK_FONTS_MISSING, sPayload.c_str(), pData);
4373 pDocument->maFontsMissing.clear();
4374 }
4375 }
4376 else
4377 {
4378 if (SfxViewShell* pViewShell = SfxViewShell::Current())
4379 {
4380 pViewShell->setLibreOfficeKitViewCallback(nullptr);
4381 pDocument->mpCallbackFlushHandlers[nView]->setViewId(-1);
4382 }
4383 }
4384}
4385
4387static char* getPostIts(LibreOfficeKitDocument* pThis)
4388{
4390 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4391 if (!pDoc)
4392 {
4393 SetLastExceptionMsg("Document doesn't support tiled rendering");
4394 return nullptr;
4395 }
4396 tools::JsonWriter aJsonWriter;
4397 pDoc->getPostIts(aJsonWriter);
4398 return strdup(aJsonWriter.finishAndGetAsOString().getStr());
4399}
4400
4402static char* getPostItsPos(LibreOfficeKitDocument* pThis)
4403{
4405 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4406 if (!pDoc)
4407 {
4408 SetLastExceptionMsg("Document doesn't support tiled rendering");
4409 return nullptr;
4410 }
4411 tools::JsonWriter aJsonWriter;
4412 pDoc->getPostItsPos(aJsonWriter);
4413 return strdup(aJsonWriter.finishAndGetAsOString().getStr());
4414}
4415
4416static char* getRulerState(LibreOfficeKitDocument* pThis)
4417{
4419 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4420 if (!pDoc)
4421 {
4422 SetLastExceptionMsg("Document doesn't support tiled rendering");
4423 return nullptr;
4424 }
4425 tools::JsonWriter aJsonWriter;
4426 pDoc->getRulerState(aJsonWriter);
4427 return strdup(aJsonWriter.finishAndGetAsOString().getStr());
4428}
4429
4430static void doc_postKeyEvent(LibreOfficeKitDocument* pThis, int nType, int nCharCode, int nKeyCode)
4431{
4432 comphelper::ProfileZone aZone("doc_postKeyEvent");
4433
4434 SolarMutexGuard aGuard;
4436
4437 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4438 if (!pDoc)
4439 {
4440 SetLastExceptionMsg("Document doesn't support tiled rendering");
4441 return;
4442 }
4443
4444 try
4445 {
4446 pDoc->postKeyEvent(nType, nCharCode, nKeyCode);
4447 }
4448 catch (const uno::Exception& exception)
4449 {
4450 SetLastExceptionMsg(exception.Message);
4451 SAL_INFO("lok", "Failed to postKeyEvent " << exception.Message);
4452 }
4453}
4454
4455static void doc_setBlockedCommandList(LibreOfficeKitDocument* /*pThis*/, int nViewId, const char* blockedCommandList)
4456{
4457 SolarMutexGuard aGuard;
4458 SfxLokHelper::setBlockedCommandList(nViewId, blockedCommandList);
4459}
4460
4461static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis, unsigned nWindowId, int nType, const char* pText)
4462{
4463 comphelper::ProfileZone aZone("doc_postWindowExtTextInputEvent");
4464
4465 SolarMutexGuard aGuard;
4466 VclPtr<vcl::Window> pWindow;
4467 if (nWindowId == 0)
4468 {
4469 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4470 if (!pDoc)
4471 {
4472 SetLastExceptionMsg("Document doesn't support tiled rendering");
4473 return;
4474 }
4475 pWindow = pDoc->getDocWindow();
4476 }
4477 else
4478 {
4479 pWindow = vcl::Window::FindLOKWindow(nWindowId);
4480 }
4481
4482 if (!pWindow)
4483 {
4484 SetLastExceptionMsg("No window found for window id: " + OUString::number(nWindowId));
4485 return;
4486 }
4487
4488 SfxLokHelper::postExtTextEventAsync(pWindow, nType, OUString::fromUtf8(std::string_view(pText, strlen(pText))));
4489}
4490
4491static void doc_removeTextContext(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, int nCharBefore, int nCharAfter)
4492{
4493 SolarMutexGuard aGuard;
4494 VclPtr<vcl::Window> pWindow;
4495 if (nLOKWindowId == 0)
4496 {
4497 ITiledRenderable* pDoc = getTiledRenderable(pThis);
4498 if (!pDoc)
4499 {
4500 gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
4501 return;
4502 }
4503 pWindow = pDoc->getDocWindow();
4504 }
4505 else
4506 {
4507 pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
4508 }
4509
4510 if (!pWindow)
4511 {
4512 gImpl->maLastExceptionMsg = "No window found for window id: " + OUString::number(nLOKWindowId);
4513 return;
4514 }
4515
4516 // Annoyingly - backspace and delete are handled in the apps via an accelerator
4517 // which are PostMessage'd by SfxViewShell::ExecKey_Impl so to stay in the same
4518 // order we do this synchronously here, unless we're in a dialog.
4519 if (nCharBefore > 0)
4520 {
4521 // backspace
4522 if (nLOKWindowId == 0)
4523 {
4524 KeyEvent aEvt(8, 1283);
4525 for (int i = 0; i < nCharBefore; ++i)
4526 pWindow->KeyInput(aEvt);
4527 }
4528 else
4529 SfxLokHelper::postKeyEventAsync(pWindow, LOK_KEYEVENT_KEYINPUT, 8, 1283, nCharBefore - 1);
4530 }
4531
4532 if (nCharAfter > 0)
4533 {
4534 // delete (forward)
4535 if (nLOKWindowId == 0)
4536 {
4537 KeyEvent aEvt(46, 1286);
4538 for (int i = 0; i < nCharAfter; ++i)
4539 pWindow->KeyInput(aEvt);
4540 }
4541 else
4542 SfxLokHelper::postKeyEventAsync(pWindow, LOK_KEYEVENT_KEYINPUT, 46, 1286, nCharAfter - 1);
4543 }
4544}
4545
4546static void doc_postWindowKeyEvent(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, int nType, int nCharCode, int nKeyCode)
4547{
4548 comphelper::ProfileZone aZone("doc_postWindowKeyEvent");
4549
4550 SolarMutexGuard aGuard;
4552
4553 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
4554 if (!pWindow)
4555 {
4556 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4557 return;
4558 }
4559
4560 KeyEvent aEvent(nCharCode, nKeyCode, 0);
4561
4562 switch (nType)
4563 {
4564 case LOK_KEYEVENT_KEYINPUT:
4565 Application::PostKeyEvent(VclEventId::WindowKeyInput, pWindow, &aEvent);
4566 break;
4567 case LOK_KEYEVENT_KEYUP:
4568 Application::PostKeyEvent(VclEventId::WindowKeyUp, pWindow, &aEvent);
4569 break;
4570 default:
4571 assert(false);
4572 break;
4573 }
4574}
4575
4576static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOutput)
4577{
4578 comphelper::ProfileZone aZone("doc_renderShapeSelection");
4579
4580 SolarMutexGuard aGuard;
4582
4583 LokChartHelper aChartHelper(SfxViewShell::Current());
4584
4585 if (aChartHelper.GetWindow())
4586 return 0;
4587
4588 try
4589 {
4590 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
4591
4592 uno::Reference<frame::XStorable> xStorable(pDocument->mxComponent, uno::UNO_QUERY_THROW);
4593
4594 SvMemoryStream aOutStream;
4596
4597 utl::MediaDescriptor aMediaDescriptor;
4598 switch (doc_getDocumentType(pThis))
4599 {
4600 case LOK_DOCTYPE_PRESENTATION:
4601 aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export");
4602 break;
4603 case LOK_DOCTYPE_DRAWING:
4604 aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export");
4605 break;
4606 case LOK_DOCTYPE_TEXT:
4607 aMediaDescriptor["FilterName"] <<= OUString("writer_svg_Export");
4608 break;
4609 case LOK_DOCTYPE_SPREADSHEET:
4610 aMediaDescriptor["FilterName"] <<= OUString("calc_svg_Export");
4611 break;
4612 default:
4613 SAL_WARN("lok", "Failed to render shape selection: Document type is not supported");
4614 }
4615 aMediaDescriptor["SelectionOnly"] <<= true;
4616 aMediaDescriptor["OutputStream"] <<= xOut;
4617 aMediaDescriptor["IsPreview"] <<= true; // will down-scale graphics
4618
4619 xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
4620
4621 if (pOutput)
4622 {
4623 const size_t nOutputSize = aOutStream.GetEndOfData();
4624 *pOutput = static_cast<char*>(malloc(nOutputSize));
4625 if (*pOutput)
4626 {
4627 std::memcpy(*pOutput, aOutStream.GetData(), nOutputSize);
4628 return nOutputSize;
4629 }
4630 }
4631 }
4632 catch (const uno::Exception& exception)
4633 {
4634 css::uno::Any exAny( cppu::getCaughtException() );
4635 SetLastExceptionMsg(exception.Message);
4636 SAL_WARN("lok", "Failed to render shape selection: " << exceptionToString(exAny));
4637 }
4638
4639 return 0;
4640}
4641
4642namespace {
4643
4651class DispatchResultListener : public cppu::WeakImplHelper<css::frame::XDispatchResultListener>
4652{
4653 const OString maCommand;
4654 const std::shared_ptr<CallbackFlushHandler> mpCallback;
4655 const std::chrono::steady_clock::time_point mSaveTime; //< The time we started saving.
4656 const bool mbWasModified; //< Whether or not the document was modified before saving.
4657
4658public:
4659 DispatchResultListener(const char* pCommand, std::shared_ptr<CallbackFlushHandler> pCallback)
4660 : maCommand(pCommand)
4661 , mpCallback(std::move(pCallback))
4662 , mSaveTime(std::chrono::steady_clock::now())
4663 , mbWasModified(SfxObjectShell::Current()->IsModified())
4664 {
4665 assert(mpCallback);
4666 }
4667
4668 virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& rEvent) override
4669 {
4670 tools::JsonWriter aJson;
4671 aJson.put("commandName", maCommand);
4672
4673 if (rEvent.State != frame::DispatchResultState::DONTKNOW)
4674 {
4675 bool bSuccess = (rEvent.State == frame::DispatchResultState::SUCCESS);
4676 aJson.put("success", bSuccess);
4677 }
4678
4679 unoAnyToJson(aJson, "result", rEvent.Result);
4680 aJson.put("wasModified", mbWasModified);
4681 aJson.put("startUnixTimeMics",
4682 std::chrono::time_point_cast<std::chrono::microseconds>(mSaveTime)
4683 .time_since_epoch()
4684 .count());
4685 aJson.put("saveDurationMics", std::chrono::duration_cast<std::chrono::microseconds>(
4686 std::chrono::steady_clock::now() - mSaveTime)
4687 .count());
4688 mpCallback->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.finishAndGetAsOString());
4689 }
4690
4691 virtual void SAL_CALL disposing(const css::lang::EventObject&) override {}
4692};
4693
4694} // anonymous namespace
4695
4696
4697static void lcl_sendDialogEvent(unsigned long long int nWindowId, const char* pArguments)
4698{
4699 SolarMutexGuard aGuard;
4700
4702
4703 if (aMap.find("id") == aMap.end())
4704 return;
4705
4706 sal_uInt64 nCurrentShellId = reinterpret_cast<sal_uInt64>(SfxViewShell::Current());
4707
4708 try
4709 {
4710 OUString sControlId = aMap["id"];
4711
4712 // dialogs send own id but notebookbar and sidebar controls are remembered by SfxViewShell id
4713 if (jsdialog::ExecuteAction(OUString::number(nWindowId), sControlId, aMap))
4714 return;
4715 auto sCurrentShellId = OUString::number(nCurrentShellId);
4716 if (jsdialog::ExecuteAction(sCurrentShellId + "sidebar", sControlId, aMap))
4717 return;
4718 if (jsdialog::ExecuteAction(sCurrentShellId + "notebookbar", sControlId, aMap))
4719 return;
4720 if (jsdialog::ExecuteAction(sCurrentShellId + "formulabar", sControlId, aMap))
4721 return;
4722 // this is needed for dialogs shown before document is loaded: MacroWarning dialog, etc...
4723 // these dialogs are created with WindowId "0"
4724 if (!SfxViewShell::Current() && jsdialog::ExecuteAction("0", sControlId, aMap))
4725 return;
4726
4727 // force resend - used in mobile-wizard
4728 jsdialog::SendFullUpdate(sCurrentShellId + "sidebar", "Panel");
4729
4730 } catch(...) {}
4731}
4732
4733
4734static void doc_sendDialogEvent(LibreOfficeKitDocument* /*pThis*/, unsigned long long int nWindowId, const char* pArguments)
4735{
4736 lcl_sendDialogEvent(nWindowId, pArguments);
4737}
4738
4739static void lo_sendDialogEvent(LibreOfficeKit* /*pThis*/, unsigned long long int nWindowId, const char* pArguments)
4740{
4741 lcl_sendDialogEvent(nWindowId, pArguments);
4742}
4743
4744static void lo_setOption(LibreOfficeKit* /*pThis*/, const char *pOption, const char* pValue)
4745{
4746 static char* pCurrentSalLogOverride = nullptr;
4747
4748 if (strcmp(pOption, "traceeventrecording") == 0)
4749 {
4750 if (strcmp(pValue, "start") == 0)
4751 {
4752 comphelper::TraceEvent::setBufferSizeAndCallback(100, TraceEventDumper::flushRecordings);
4754 if (traceEventDumper == nullptr)
4755 traceEventDumper = new TraceEventDumper();
4756 }
4757 else if (strcmp(pValue, "stop") == 0)
4759 }
4760 else if (strcmp(pOption, "sallogoverride") == 0)
4761 {
4762 if (pCurrentSalLogOverride != nullptr)
4763 free(pCurrentSalLogOverride);
4764 if (pValue == nullptr)
4765 pCurrentSalLogOverride = nullptr;
4766 else
4767 pCurrentSalLogOverride = strdup(pValue);
4768
4769 if (pCurrentSalLogOverride == nullptr || pCurrentSalLogOverride[0] == '\0')
4770 sal_detail_set_log_selector(nullptr);
4771 else
4772 sal_detail_set_log_selector(pCurrentSalLogOverride);
4773 }
4774#ifdef LINUX
4775 else if (strcmp(pOption, "addfont") == 0)
4776 {
4777 if (memcmp(pValue, "file://", 7) == 0)
4778 pValue += 7;
4779
4780 int fd = open(pValue, O_RDONLY);
4781 if (fd == -1)
4782 {
4783 std::cerr << "Could not open font file '" << pValue << "': " << strerror(errno) << std::endl;
4784 return;
4785 }
4786
4787 OUString sMagicFileName = "file:///:FD:/" + OUString::number(fd);
4788
4791 pDevice->AddTempDevFont(sMagicFileName, "");
4793 }
4794#endif
4795}
4796
4797static void lo_dumpState (LibreOfficeKit* pThis, const char* /* pOptions */, char** pState)
4798{
4799 if (!pState)
4800 return;
4801
4802 // NB. no SolarMutexGuard since this may be caused in some extremis / deadlock
4804
4805 *pState = nullptr;
4806 OStringBuffer aState(4096*256);
4807
4808 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
4809
4810 pLib->dumpState(aState);
4811
4812 OString aStr = aState.makeStringAndClear();
4813 *pState = strdup(aStr.getStr());
4814}
4815
4816void LibLibreOffice_Impl::dumpState(rtl::OStringBuffer &rState)
4817{
4818 rState.append("LibreOfficeKit state:");
4819 rState.append("\n\tLastExceptionMsg:\t");
4820 rState.append(rtl::OUStringToOString(maLastExceptionMsg, RTL_TEXTENCODING_UTF8));
4821 rState.append("\n\tUnipoll:\t");
4822 rState.append(vcl::lok::isUnipoll() ? "yes" : "no: events on thread");
4823 rState.append("\n\tOptionalFeatures:\t0x");
4824 rState.append(static_cast<sal_Int64>(mOptionalFeatures), 16);
4825 rState.append("\n\tCallbackData:\t0x");
4826 rState.append(reinterpret_cast<sal_Int64>(mpCallback), 16);
4827 // TODO: dump mInteractionMap
4829 vcl::lok::dumpState(rState);
4830}
4831
4832static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished)
4833{
4834 comphelper::ProfileZone aZone("doc_postUnoCommand");
4835
4836 SolarMutexGuard aGuard;
4838
4840 OUString aCommand(pCommand, strlen(pCommand), RTL_TEXTENCODING_UTF8);
4841 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
4842
4843 std::vector<beans::PropertyValue> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments));
4844
4845 if (!vcl::lok::isUnipoll())
4846 {
4847 beans::PropertyValue aSynchronMode;
4848 aSynchronMode.Name = "SynchronMode";
4849 aSynchronMode.Value <<= false;
4850 aPropertyValuesVector.push_back(aSynchronMode);
4851 }
4852
4853 int nView = SfxLokHelper::getView();
4854 if (nView < 0)
4855 return;
4856
4857 if (gImpl && aCommand == ".uno:ToggleOrientation")
4858 {
4859 ExecuteOrientationChange();
4860 return;
4861 }
4862
4863 // handle potential interaction
4864 if (gImpl && aCommand == ".uno:Save")
4865 {
4866 // Check if saving a PDF file
4867 OUString aMimeType = lcl_getCurrentDocumentMimeType(pDocument);
4868 if (pDocSh && pDocSh->IsModified() && aMimeType == "application/pdf")
4869 {
4870 // If we have a PDF file (for saving annotations for example), we need
4871 // to run save-as to the same file as the opened document. Plain save
4872 // doesn't work as the PDF is not a "native" format.
4873 uno::Reference<frame::XStorable> xStorable(pDocument->mxComponent, uno::UNO_QUERY_THROW);
4874 OUString aURL = xStorable->getLocation();
4875 OString aURLUtf8 = OUStringToOString(aURL, RTL_TEXTENCODING_UTF8);
4876 bool bResult = doc_saveAs(pThis, aURLUtf8.getStr(), "pdf", nullptr);
4877
4878 // Send the result of save
4879 tools::JsonWriter aJson;
4880 aJson.put("commandName", pCommand);
4881 aJson.put("success", bResult);
4882 pDocument->mpCallbackFlushHandlers[nView]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.finishAndGetAsOString());
4883 return;
4884 }
4885
4886
4887 rtl::Reference<LOKInteractionHandler> const pInteraction(
4888 new LOKInteractionHandler("save", gImpl, pDocument));
4889 uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction);
4890
4891 beans::PropertyValue aValue;
4892 aValue.Name = "InteractionHandler";
4893 aValue.Value <<= xInteraction;
4894 aPropertyValuesVector.push_back(aValue);
4895
4896 bool bDontSaveIfUnmodified = false;
4897 aPropertyValuesVector.erase(std::remove_if(aPropertyValuesVector.begin(),
4898 aPropertyValuesVector.end(),
4899 [&bDontSaveIfUnmodified](const beans::PropertyValue& aItem){
4900 if (aItem.Name == "DontSaveIfUnmodified")
4901 {
4902 bDontSaveIfUnmodified = aItem.Value.get<bool>();
4903 return true;
4904 }
4905 return false;
4906 }), aPropertyValuesVector.end());
4907
4908 // skip saving and tell the result via UNO_COMMAND_RESULT
4909 if (bDontSaveIfUnmodified && (!pDocSh || !pDocSh->IsModified()))
4910 {
4911 tools::JsonWriter aJson;
4912 aJson.put("commandName", pCommand);
4913 aJson.put("success", false);
4914 // Add the reason for not saving
4915 {
4916 auto resultNode = aJson.startNode("result");
4917 aJson.put("type", "string");
4918 aJson.put("value", "unmodified");
4919 }
4920 pDocument->mpCallbackFlushHandlers[nView]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.finishAndGetAsOString());
4921 return;
4922 }
4923 }
4924 else if (gImpl && aCommand == ".uno:TransformDialog")
4925 {
4926 bool bNeedConversion = false;
4927 SfxViewShell* pViewShell = SfxViewShell::Current();
4928 LokChartHelper aChartHelper(pViewShell);
4929
4930 if (aChartHelper.GetWindow() )
4931 {
4932 bNeedConversion = true;
4933 }
4934 else if (const SdrView* pView = pViewShell->GetDrawView())
4935 {
4936 if (OutputDevice* pOutputDevice = pView->GetFirstOutputDevice())
4937 {
4938 bNeedConversion = (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM);
4939 }
4940 }
4941
4942 if (bNeedConversion)
4943 {
4944 sal_Int32 value;
4945 for (beans::PropertyValue& rPropValue: aPropertyValuesVector)
4946 {
4947 if (rPropValue.Name == "TransformPosX"
4948 || rPropValue.Name == "TransformPosY"
4949 || rPropValue.Name == "TransformWidth"
4950 || rPropValue.Name == "TransformHeight"
4951 || rPropValue.Name == "TransformRotationX"
4952 || rPropValue.Name == "TransformRotationY")
4953 {
4954 rPropValue.Value >>= value;
4956 rPropValue.Value <<= value;
4957 }
4958 }
4959 }
4960
4961 if (aChartHelper.GetWindow() && aPropertyValuesVector.size() > 0)
4962 {
4963 if (aPropertyValuesVector[0].Name != "Action")
4964 {
4965 tools::Rectangle aChartBB = aChartHelper.GetChartBoundingBox();
4966
4967 int nLeft = o3tl::convert(aChartBB.Left(), o3tl::Length::twip, o3tl::Length::mm100);
4969
4970 for (beans::PropertyValue& rPropValue: aPropertyValuesVector)
4971 {
4972 if (rPropValue.Name == "TransformPosX" || rPropValue.Name == "TransformRotationX")
4973 {
4974 auto const value = *o3tl::doAccess<sal_Int32>(rPropValue.Value);
4975 rPropValue.Value <<= value - nLeft;
4976 }
4977 else if (rPropValue.Name == "TransformPosY" || rPropValue.Name == "TransformRotationY")
4978 {
4979 auto const value = *o3tl::doAccess<sal_Int32>(rPropValue.Value);
4980 rPropValue.Value <<= value - nTop;
4981 }
4982 }
4983 }
4984 util::URL aCommandURL;
4985 aCommandURL.Path = "LOKTransform";
4986 css::uno::Reference<css::frame::XDispatch>& aChartDispatcher = aChartHelper.GetXDispatcher();
4987 aChartDispatcher->dispatch(aCommandURL, comphelper::containerToSequence(aPropertyValuesVector));
4988 return;
4989 }
4990 }
4991 else if (gImpl && aCommand == ".uno:LOKSidebarWriterPage")
4992 {
4993 setupSidebar(u"WriterPageDeck");
4994 return;
4995 }
4996 else if (gImpl && aCommand == ".uno:SidebarShow")
4997 {
4998 setupSidebar();
4999 return;
5000 }
5001 else if (gImpl && aCommand == ".uno:SidebarHide")
5002 {
5003 hideSidebar();
5004 return;
5005 }
5006
5007 bool bResult = false;
5008 LokChartHelper aChartHelper(SfxViewShell::Current());
5009
5010 if (aChartHelper.GetWindow() && aCommand != ".uno:Save" )
5011 {
5012 util::URL aCommandURL;
5013 aCommandURL.Path = aCommand.copy(5);
5014 css::uno::Reference<css::frame::XDispatch>& aChartDispatcher = aChartHelper.GetXDispatcher();
5015 aChartDispatcher->dispatch(aCommandURL, comphelper::containerToSequence(aPropertyValuesVector));
5016 return;
5017 }
5018 if (LokStarMathHelper aMathHelper(SfxViewShell::Current());
5019 aMathHelper.GetGraphicWindow() && aCommand != ".uno:Save")
5020 {
5021 aMathHelper.Dispatch(aCommand, comphelper::containerToSequence(aPropertyValuesVector));
5022 return;
5023 }
5024 if (bNotifyWhenFinished && pDocument->mpCallbackFlushHandlers.count(nView))
5025 {
5026 bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector),
5027 new DispatchResultListener(pCommand, pDocument->mpCallbackFlushHandlers[nView]));
5028 }
5029 else
5030 bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector));
5031
5032 if (!bResult)
5033 {
5034 SetLastExceptionMsg("Failed to dispatch " + aCommand);
5035 }
5036}
5037
5038static void doc_postMouseEvent(LibreOfficeKitDocument* pThis, int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
5039{
5040 comphelper::ProfileZone aZone("doc_postMouseEvent");
5041
5042 SolarMutexGuard aGuard;
5044
5045 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5046 if (!pDoc)
5047 {
5048 SetLastExceptionMsg("Document doesn't support tiled rendering");
5049 return;
5050 }
5051 try
5052 {
5053 pDoc->postMouseEvent(nType, nX, nY, nCount, nButtons, nModifier);
5054 }
5055 catch (const uno::Exception& exception)
5056 {
5057 SetLastExceptionMsg(exception.Message);
5058 SAL_INFO("lok", "Failed to postMouseEvent " << exception.Message);
5059 }
5060}
5061
5062static void doc_postWindowMouseEvent(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
5063{
5064 comphelper::ProfileZone aZone("doc_postWindowMouseEvent");
5065
5066 SolarMutexGuard aGuard;
5068
5069 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
5070 if (!pWindow)
5071 {
5072 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5073 return;
5074 }
5075
5076 const Point aPos(nX, nY);
5077
5078 MouseEvent aEvent(aPos, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
5079
5080 vcl::EnableDialogInput(pWindow);
5081
5082 switch (nType)
5083 {
5084 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
5085 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown, pWindow, &aEvent);
5086 break;
5087 case LOK_MOUSEEVENT_MOUSEBUTTONUP:
5088 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp, pWindow, &aEvent);
5089 break;
5090 case LOK_MOUSEEVENT_MOUSEMOVE:
5091 Application::PostMouseEvent(VclEventId::WindowMouseMove, pWindow, &aEvent);
5092 break;
5093 default:
5094 assert(false);
5095 break;
5096 }
5097}
5098
5099static void doc_postWindowGestureEvent(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, const char* pType, int nX, int nY, int nOffset)
5100{
5101 comphelper::ProfileZone aZone("doc_postWindowGestureEvent");
5102
5103 SolarMutexGuard aGuard;
5105
5106 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
5107 if (!pWindow)
5108 {
5109 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5110 return;
5111 }
5112
5113 OString aType(pType);
5114 GestureEventPanType eEventType = GestureEventPanType::Update;
5115
5116 if (aType == "panBegin")
5117 eEventType = GestureEventPanType::Begin;
5118 else if (aType == "panEnd")
5119 eEventType = GestureEventPanType::End;
5120
5122 sal_Int32(nX),
5123 sal_Int32(nY),
5124 eEventType,
5125 sal_Int32(nOffset),
5126 PanningOrientation::Vertical,
5127 };
5128
5129 vcl::EnableDialogInput(pWindow);
5130
5131 Application::PostGestureEvent(VclEventId::WindowGestureEvent, pWindow, &aEvent);
5132}
5133
5134static void doc_setTextSelection(LibreOfficeKitDocument* pThis, int nType, int nX, int nY)
5135{
5136 comphelper::ProfileZone aZone("doc_setTextSelection");
5137
5138 SolarMutexGuard aGuard;
5140
5141 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5142 if (!pDoc)
5143 {
5144 SetLastExceptionMsg("Document doesn't support tiled rendering");
5145 return;
5146 }
5147
5148 pDoc->setTextSelection(nType, nX, nY);
5149}
5150
5151static void doc_setWindowTextSelection(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, bool swap, int nX, int nY)
5152{
5153 comphelper::ProfileZone aZone("doc_setWindowTextSelection");
5154
5155 SolarMutexGuard aGuard;
5157
5158 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
5159 if (!pWindow)
5160 {
5161 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5162 return;
5163 }
5164
5165
5166 Size aOffset(pWindow->GetOutOffXPixel(), pWindow->GetOutOffYPixel());
5167 Point aCursorPos(nX, nY);
5168 aCursorPos.Move(aOffset);
5169 sal_uInt16 nModifier = swap ? KEY_MOD1 + KEY_MOD2 : KEY_SHIFT;
5170
5171 MouseEvent aCursorEvent(aCursorPos, 1, MouseEventModifiers::SIMPLECLICK, 0, nModifier);
5172 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown, pWindow, &aCursorEvent);
5173 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp, pWindow, &aCursorEvent);
5174}
5175
5176static bool getFromTransferable(
5177 const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
5178 const OString &aInMimeType, OString &aRet);
5179
5181 const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
5182 const OString &aMimeType, OString &aRet)
5183{
5184 if (!getFromTransferable(xTransferable, aMimeType, aRet))
5185 return false;
5186
5187 // Encode in base64.
5188 auto aSeq = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),
5189 aRet.getLength());
5190 OStringBuffer aBase64Data;
5191 comphelper::Base64::encode(aBase64Data, aSeq);
5192
5193 // Embed in HTML.
5194 aRet = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
5195 "<html><head>"
5196 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
5197 "name=\"generator\" content=\""
5198 + getGenerator().toUtf8()
5199 + "\"/>"
5200 "</head><body><img src=\"data:" + aMimeType + ";base64,"
5201 + aBase64Data + "\"/></body></html>";
5202
5203 return true;
5204}
5205
5207 const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
5208 const OString &aMimeType, OString &aRet)
5209{
5210 if (!getFromTransferable(xTransferable, aMimeType, aRet))
5211 return false;
5212
5213 // Embed in HTML - FIXME: needs some escaping.
5214 aRet = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
5215 "<html><head>"
5216 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
5217 "name=\"generator\" content=\""
5218 + getGenerator().toUtf8()
5219 + "\"/></head><body><pre>" + aRet + "</pre></body></html>";
5220
5221 return true;
5222}
5223
5225 const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
5226 const OString &aInMimeType, OString &aRet)
5227{
5228 OString aMimeType(aInMimeType);
5229
5230 // Take care of UTF-8 text here.
5231 bool bConvert = false;
5232 sal_Int32 nIndex = 0;
5233 if (o3tl::getToken(aMimeType, 0, ';', nIndex) == "text/plain")
5234 {
5235 if (o3tl::getToken(aMimeType, 0, ';', nIndex) == "charset=utf-8")
5236 {
5237 aMimeType = "text/plain;charset=utf-16";
5238 bConvert = true;
5239 }
5240 }
5241
5242 datatransfer::DataFlavor aFlavor;
5243 aFlavor.MimeType = OUString::fromUtf8(aMimeType);
5244 if (aMimeType == "text/plain;charset=utf-16")
5245 aFlavor.DataType = cppu::UnoType<OUString>::get();
5246 else
5247 aFlavor.DataType = cppu::UnoType< uno::Sequence<sal_Int8> >::get();
5248
5249 if (!xTransferable->isDataFlavorSupported(aFlavor))
5250 {
5251 // Try harder for HTML it is our copy/paste meta-file format
5252 if (aInMimeType == "text/html")
5253 {
5254 // Desperate measures - convert text to HTML instead.
5255 if (encodeTextAsHTML(xTransferable, "text/plain;charset=utf-8", aRet))
5256 return true;
5257 // If html is not supported, might be a graphic-selection,
5258 if (encodeImageAsHTML(xTransferable, "image/png", aRet))
5259 return true;
5260 }
5261
5262 SetLastExceptionMsg("Flavor " + aFlavor.MimeType + " is not supported");
5263 return false;
5264 }
5265
5266 uno::Any aAny;
5267 try
5268 {
5269 aAny = xTransferable->getTransferData(aFlavor);
5270 }
5271 catch (const css::datatransfer::UnsupportedFlavorException& e)
5272 {
5273 SetLastExceptionMsg("Unsupported flavor " + aFlavor.MimeType + " exception " + e.Message);
5274 return false;
5275 }
5276 catch (const css::uno::Exception& e)
5277 {
5278 SetLastExceptionMsg("Exception getting " + aFlavor.MimeType + " exception " + e.Message);
5279 return false;
5280 }
5281
5282 if (aFlavor.DataType == cppu::UnoType<OUString>::get())
5283 {
5284 OUString aString;
5285 aAny >>= aString;
5286 if (bConvert)
5287 aRet = OUStringToOString(aString, RTL_TEXTENCODING_UTF8);
5288 else
5289 aRet = OString(reinterpret_cast<const char *>(aString.getStr()), aString.getLength() * sizeof(sal_Unicode));
5290 }
5291 else
5292 {
5293 uno::Sequence<sal_Int8> aSequence;
5294 aAny >>= aSequence;
5295 aRet = OString(reinterpret_cast<const char*>(aSequence.getConstArray()), aSequence.getLength());
5296 }
5297
5298 return true;
5299}
5300
5301static char* doc_getTextSelection(LibreOfficeKitDocument* pThis, const char* pMimeType, char** pUsedMimeType)
5302{
5303 comphelper::ProfileZone aZone("doc_getTextSelection");
5304
5305 SolarMutexGuard aGuard;
5307
5308 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5309 if (!pDoc)
5310 {
5311 SetLastExceptionMsg("Document doesn't support tiled rendering");
5312 return nullptr;
5313 }
5314
5315 css::uno::Reference<css::datatransfer::XTransferable> xTransferable = pDoc->getSelection();
5316 if (!xTransferable)
5317 {
5318 SetLastExceptionMsg("No selection available");
5319 return nullptr;
5320 }
5321
5322 const char *pType = pMimeType;
5323 if (!pType || pType[0] == '\0')
5324 pType = "text/plain;charset=utf-8";
5325
5326 OString aRet;
5327 bool bSuccess = getFromTransferable(xTransferable, OString(pType), aRet);
5328 if (!bSuccess)
5329 return nullptr;
5330
5331 if (pUsedMimeType) // legacy
5332 {
5333 if (pMimeType)
5334 *pUsedMimeType = strdup(pMimeType);
5335 else
5336 *pUsedMimeType = nullptr;
5337 }
5338
5339 return convertOString(aRet);
5340}
5341
5342static int doc_getSelectionType(LibreOfficeKitDocument* pThis)
5343{
5344 comphelper::ProfileZone aZone("doc_getSelectionType");
5345
5346 SolarMutexGuard aGuard;
5348
5349 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5350 if (!pDoc)
5351 {
5352 SetLastExceptionMsg("Document doesn't support tiled rendering");
5353 return LOK_SELTYPE_NONE;
5354 }
5355
5356 css::uno::Reference<css::datatransfer::XTransferable> xTransferable = pDoc->getSelection();
5357 if (!xTransferable)
5358 {
5359 SetLastExceptionMsg("No selection available");
5360 return LOK_SELTYPE_NONE;
5361 }
5362
5363 css::uno::Reference<css::datatransfer::XTransferable2> xTransferable2(xTransferable, css::uno::UNO_QUERY);
5364 if (xTransferable2.is() && xTransferable2->isComplex())
5365 return LOK_SELTYPE_COMPLEX;
5366
5367 OString aRet;
5368 bool bSuccess = getFromTransferable(xTransferable, "text/plain;charset=utf-8", aRet);
5369 if (!bSuccess)
5370 return LOK_SELTYPE_NONE;
5371
5372 if (aRet.getLength() > 10000)
5373 return LOK_SELTYPE_COMPLEX;
5374
5375 return !aRet.isEmpty() ? LOK_SELTYPE_TEXT : LOK_SELTYPE_NONE;
5376}
5377
5378static int doc_getSelectionTypeAndText(LibreOfficeKitDocument* pThis, const char* pMimeType, char** pText, char** pUsedMimeType)
5379{
5380 // The purpose of this function is to avoid double call to pDoc->getSelection(),
5381 // which may be expensive.
5382 comphelper::ProfileZone aZone("doc_getSelectionTypeAndText");
5383
5384 SolarMutexGuard aGuard;
5386
5387 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5388 if (!pDoc)
5389 {
5390 SetLastExceptionMsg("Document doesn't support tiled rendering");
5391 return LOK_SELTYPE_NONE;
5392 }
5393
5394 css::uno::Reference<css::datatransfer::XTransferable> xTransferable = pDoc->getSelection();
5395 if (!xTransferable)
5396 {
5397 SetLastExceptionMsg("No selection available");
5398 return LOK_SELTYPE_NONE;
5399 }
5400
5401 css::uno::Reference<css::datatransfer::XTransferable2> xTransferable2(xTransferable, css::uno::UNO_QUERY);
5402 if (xTransferable2.is() && xTransferable2->isComplex())
5403 return LOK_SELTYPE_COMPLEX;
5404
5405 const char *pType = pMimeType;
5406 if (!pType || pType[0] == '\0')
5407 pType = "text/plain;charset=utf-8";
5408
5409 OString aRet;
5410 bool bSuccess = getFromTransferable(xTransferable, OString(pType), aRet);
5411 if (!bSuccess)
5412 return LOK_SELTYPE_NONE;
5413
5414 if (aRet.getLength() > 10000)
5415 return LOK_SELTYPE_COMPLEX;
5416
5417 if (aRet.isEmpty())
5418 return LOK_SELTYPE_NONE;
5419
5420 if (pText)
5421 *pText = convertOString(aRet);
5422
5423 if (pUsedMimeType) // legacy
5424 {
5425 if (pMimeType)
5426 *pUsedMimeType = strdup(pMimeType);
5427 else
5428 *pUsedMimeType = nullptr;
5429 }
5430
5431 return LOK_SELTYPE_TEXT;
5432}
5433
5434static int doc_getClipboard(LibreOfficeKitDocument* pThis,
5435 const char **pMimeTypes,
5436 size_t *pOutCount,
5437 char ***pOutMimeTypes,
5438 size_t **pOutSizes,
5439 char ***pOutStreams)
5440{
5441#ifdef IOS
5442 (void) pThis;
5443 (void) pMimeTypes;
5444 (void) pOutCount;
5445 (void) pOutMimeTypes;
5446 (void) pOutSizes;
5447 (void) pOutStreams;
5448
5449 assert(!"doc_getClipboard should not be called on iOS");
5450
5451 return 0;
5452#else
5453 comphelper::ProfileZone aZone("doc_getClipboard");
5454
5455 SolarMutexGuard aGuard;
5457
5458 assert (pOutCount);
5459 assert (pOutMimeTypes);
5460 assert (pOutSizes);
5461 assert (pOutStreams);
5462
5463 *pOutCount = 0;
5464 *pOutMimeTypes = nullptr;
5465 *pOutSizes = nullptr;
5466 *pOutStreams = nullptr;
5467
5468 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5469 if (!pDoc)
5470 {
5471 SetLastExceptionMsg("Document doesn't support tiled rendering");
5472 return 0;
5473 }
5474
5476
5477 css::uno::Reference<css::datatransfer::XTransferable> xTransferable = xClip->getContents();
5478 SAL_INFO("lok", "Got from clip: " << xClip.get() << " transferable: " << xTransferable);
5479 if (!xTransferable)
5480 {
5481 SetLastExceptionMsg("No clipboard content available");
5482 return 0;
5483 }
5484
5485 std::vector<OString> aMimeTypes;
5486 if (!pMimeTypes) // everything
5487 {
5488 const uno::Sequence< css::datatransfer::DataFlavor > flavors = xTransferable->getTransferDataFlavors();
5489 if (!flavors.getLength())
5490 {
5491 SetLastExceptionMsg("Flavourless selection");
5492 return 0;
5493 }
5494 for (const auto &it : flavors)
5495 aMimeTypes.push_back(OUStringToOString(it.MimeType, RTL_TEXTENCODING_UTF8));
5496 }
5497 else
5498 {
5499 for (size_t i = 0; pMimeTypes[i]; ++i)
5500 aMimeTypes.push_back(OString(pMimeTypes[i]));
5501 }
5502
5503 *pOutCount = aMimeTypes.size();
5504 *pOutSizes = static_cast<size_t *>(malloc(*pOutCount * sizeof(size_t)));
5505 *pOutMimeTypes = static_cast<char **>(malloc(*pOutCount * sizeof(char *)));
5506 *pOutStreams = static_cast<char **>(malloc(*pOutCount * sizeof(char *)));
5507 for (size_t i = 0; i < aMimeTypes.size(); ++i)
5508 {
5509 if (aMimeTypes[i] == "text/plain;charset=utf-16")
5510 (*pOutMimeTypes)[i] = strdup("text/plain;charset=utf-8");
5511 else
5512 (*pOutMimeTypes)[i] = strdup(aMimeTypes[i].getStr());
5513
5514 OString aRet;
5515 bool bSuccess = getFromTransferable(xTransferable, (*pOutMimeTypes)[i], aRet);
5516 if (!bSuccess || aRet.getLength() < 1)
5517 {
5518 (*pOutSizes)[i] = 0;
5519 (*pOutStreams)[i] = nullptr;
5520 }
5521 else
5522 {
5523 (*pOutSizes)[i] = aRet.getLength();
5524 (*pOutStreams)[i] = convertOString(aRet);
5525 }
5526 }
5527
5528 return 1;
5529#endif
5530}
5531
5532static int doc_setClipboard(LibreOfficeKitDocument* pThis,
5533 const size_t nInCount,
5534 const char **pInMimeTypes,
5535 const size_t *pInSizes,
5536 const char **pInStreams)
5537{
5538#ifdef IOS
5539 (void) pThis;
5540 (void) nInCount;
5541 (void) pInMimeTypes;
5542 (void) pInSizes;
5543 (void) pInStreams;
5544#else
5545 comphelper::ProfileZone aZone("doc_setClipboard");
5546
5547 SolarMutexGuard aGuard;
5549
5550 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5551 if (!pDoc)
5552 {
5553 SetLastExceptionMsg("Document doesn't support tiled rendering");
5554 return false;
5555 }
5556
5557 uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable(nInCount, pInMimeTypes, pInSizes, pInStreams));
5558
5559 auto xClip = forceSetClipboardForCurrentView(pThis);
5560 xClip->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
5561
5562 SAL_INFO("lok", "Set clip: " << xClip.get() << " to: " << xTransferable);
5563
5564 if (!pDoc->isMimeTypeSupported())
5565 {
5566 SetLastExceptionMsg("Document doesn't support this mime type");
5567 return false;
5568 }
5569#endif
5570 return true;
5571}
5572
5573static bool doc_paste(LibreOfficeKitDocument* pThis, const char* pMimeType, const char* pData, size_t nSize)
5574{
5575 comphelper::ProfileZone aZone("doc_paste");
5576
5577 SolarMutexGuard aGuard;
5578
5579 const char *pInMimeTypes[1];
5580 const char *pInStreams[1];
5581 size_t pInSizes[1];
5582 pInMimeTypes[0] = pMimeType;
5583 pInSizes[0] = nSize;
5584 pInStreams[0] = pData;
5585
5586 if (!doc_setClipboard(pThis, 1, pInMimeTypes, pInSizes, pInStreams))
5587 return false;
5588
5590 {
5591 {"AnchorType", uno::Any(static_cast<sal_uInt16>(css::text::TextContentAnchorType_AS_CHARACTER))},
5592 {"IgnoreComments", uno::Any(true)},
5593 }));
5594 if (!comphelper::dispatchCommand(".uno:Paste", aPropertyValues))
5595 {
5596 SetLastExceptionMsg("Failed to dispatch the .uno: command");
5597 return false;
5598 }
5599
5600 return true;
5601}
5602
5603static void doc_setGraphicSelection(LibreOfficeKitDocument* pThis, int nType, int nX, int nY)
5604{
5605 comphelper::ProfileZone aZone("doc_setGraphicSelection");
5606
5607 SolarMutexGuard aGuard;
5609
5610 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5611 if (!pDoc)
5612 {
5613 SetLastExceptionMsg("Document doesn't support tiled rendering");
5614 return;
5615 }
5616
5617 pDoc->setGraphicSelection(nType, nX, nY);
5618}
5619
5620static void getDocLanguages(LibreOfficeKitDocument* pThis, uno::Sequence<lang::Locale>& rSeq)
5621{
5622 SfxViewFrame* pViewFrame = SfxViewFrame::Current();
5623 if (!pViewFrame)
5624 return;
5625
5626 SfxDispatcher* pDispatcher = pViewFrame->GetBindings().GetDispatcher();
5627 if (!pDispatcher)
5628 return;
5629
5630 css::uno::Any aLangStatus;
5631 pDispatcher->QueryState(SID_LANGUAGE_STATUS, aLangStatus);
5632
5633 OUString sCurrent;
5634 OUString sKeyboard;
5635 OUString sGuessText;
5636 SvtScriptType eScriptType = SvtScriptType::LATIN | SvtScriptType::ASIAN
5637 | SvtScriptType::COMPLEX;
5638
5639 Sequence<OUString> aSeqLang;
5640 if (aLangStatus >>= aSeqLang)
5641 {
5642 if (aSeqLang.getLength() == 4)
5643 {
5644 sCurrent = aSeqLang[0];
5645 eScriptType = static_cast<SvtScriptType>(aSeqLang[1].toInt32());
5646 sKeyboard = aSeqLang[1];
5647 sGuessText = aSeqLang[2];
5648 }
5649 }
5650 else
5651 {
5652 aLangStatus >>= sCurrent;
5653 }
5654
5655 LanguageType nLangType;
5656 std::set<LanguageType> aLangItems;
5657
5658 if (!sCurrent.isEmpty())
5659 {
5660 nLangType = SvtLanguageTable::GetLanguageType(sCurrent);
5661 if (nLangType != LANGUAGE_DONTKNOW)
5662 {
5663 aLangItems.insert(nLangType);
5664 }
5665 }
5666
5667 const AllSettings& rAllSettings = Application::GetSettings();
5668 nLangType = rAllSettings.GetLanguageTag().getLanguageType();
5669 if (nLangType != LANGUAGE_DONTKNOW &&
5670 (eScriptType & SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType)))
5671 {
5672 aLangItems.insert(nLangType);
5673 }
5674
5675 nLangType = rAllSettings.GetUILanguageTag().getLanguageType();
5676 if (nLangType != LANGUAGE_DONTKNOW &&
5677 (eScriptType & SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType)))
5678 {
5679 aLangItems.insert(nLangType);
5680 }
5681
5682 if (!sKeyboard.isEmpty())
5683 {
5684 nLangType = SvtLanguageTable::GetLanguageType(sKeyboard);
5685 if (nLangType != LANGUAGE_DONTKNOW &&
5686 (eScriptType & SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType)))
5687 {
5688 aLangItems.insert(nLangType);
5689 }
5690 }
5691
5692 if (!sGuessText.isEmpty())
5693 {
5694 Reference<linguistic2::XLanguageGuessing> xLangGuesser;
5695 try
5696 {
5698 }
5699 catch(...)
5700 {
5701 }
5702
5703 if (xLangGuesser.is())
5704 {
5705 lang::Locale aLocale = xLangGuesser->guessPrimaryLanguage(sGuessText, 0,
5706 sGuessText.getLength());
5707 LanguageTag aLanguageTag(aLocale);
5708 nLangType = aLanguageTag.getLanguageType(false);
5709 if (nLangType != LANGUAGE_DONTKNOW &&
5710 (eScriptType & SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType)))
5711 {
5712 aLangItems.insert(nLangType);
5713 }
5714 }
5715 }
5716
5717 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
5718 Reference<document::XDocumentLanguages> xDocumentLanguages(pDocument->mxComponent, UNO_QUERY);
5719 if (xDocumentLanguages.is())
5720 {
5721 const Sequence<lang::Locale> aLocales(xDocumentLanguages->getDocumentLanguages(
5722 static_cast<sal_Int16>(eScriptType), 64));
5723
5724 for (const lang::Locale& aLocale : aLocales)
5725 {
5726 nLangType = SvtLanguageTable::GetLanguageType(aLocale.Language);
5727 if (nLangType != LANGUAGE_DONTKNOW &&
5728 (eScriptType & SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType)))
5729 {
5730 aLangItems.insert(nLangType);
5731 }
5732 }
5733 }
5734
5735 int nLocale = 0;
5736 Sequence<lang::Locale> aLocales(aLangItems.size());
5737 auto pLocales = aLocales.getArray();
5738 for (const LanguageType& itLang : aLangItems)
5739 {
5740 pLocales[nLocale++] = LanguageTag::convertToLocale(itLang);
5741 }
5742
5743 rSeq = aLocales;
5744}
5745
5746static void doc_resetSelection(LibreOfficeKitDocument* pThis)
5747{
5748 comphelper::ProfileZone aZone("doc_resetSelection");
5749
5750 SolarMutexGuard aGuard;
5752
5753 ITiledRenderable* pDoc = getTiledRenderable(pThis);
5754 if (!pDoc)
5755 {
5756 SetLastExceptionMsg("Document doesn't support tiled rendering");
5757 return;
5758 }
5759
5760 pDoc->resetSelection();
5761}
5762
5763static char* getLanguages(LibreOfficeKitDocument* pThis, const char* pCommand)
5764{
5765 css::uno::Sequence< css::lang::Locale > aLocales;
5766
5767 if (xContext.is())
5768 {
5769 css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLangSrv = css::linguistic2::LinguServiceManager::create(xContext);
5770 if (xLangSrv.is())
5771 {
5772 css::uno::Reference<css::linguistic2::XSpellChecker> xSpell = xLangSrv->getSpellChecker();
5773 if (xSpell.is())
5774 aLocales = xSpell->getLocales();
5775 }
5776
5777 /* FIXME: To obtain the document languages the spell checker can be disabled,
5778 so a future re-work of the getLanguages function is needed in favor to use
5779 getDocLanguages */
5780 if (!aLocales.hasElements())
5781 {
5783 getDocLanguages(pThis, aSeq);
5784 aLocales = aSeq;
5785 }
5786 }
5787
5788 boost::property_tree::ptree aTree;
5789 aTree.put("commandName", pCommand);
5790 boost::property_tree::ptree aValues;
5791 boost::property_tree::ptree aChild;
5792 OUString sLanguage;
5793 for ( css::lang::Locale const & locale : std::as_const(aLocales) )
5794 {
5795 const LanguageTag aLanguageTag( locale );
5796 sLanguage = SvtLanguageTable::GetLanguageString(aLanguageTag.getLanguageType());
5797 if (sLanguage.startsWith("{") && sLanguage.endsWith("}"))
5798 continue;
5799
5800 sLanguage += ";" + aLanguageTag.getBcp47(false);
5801 aChild.put("", sLanguage.toUtf8());
5802 aValues.push_back(std::make_pair("", aChild));
5803 }
5804 aTree.add_child("commandValues", aValues);
5805 std::stringstream aStream;
5806 boost::property_tree::write_json(aStream, aTree);
5807 char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
5808 assert(pJson); // Don't handle OOM conditions
5809 strcpy(pJson, aStream.str().c_str());
5810 pJson[aStream.str().size()] = '\0';
5811 return pJson;
5812}
5813
5814static char* getFonts (const char* pCommand)
5815{
5817 if (!pDocSh)
5818 return nullptr;
5819 const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(
5820 pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
5821 const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
5822
5823 boost::property_tree::ptree aTree;
5824 aTree.put("commandName", pCommand);
5825 boost::property_tree::ptree aValues;
5826 if ( pList )
5827 {
5828 sal_uInt16 nFontCount = pList->GetFontNameCount();
5829 for (sal_uInt16 i = 0; i < nFontCount; ++i)
5830 {
5831 boost::property_tree::ptree aChildren;
5832 const FontMetric& rFontMetric = pList->GetFontName(i);
5833 const int* pAry = FontList::GetStdSizeAry();
5834 sal_uInt16 nSizeCount = 0;
5835 while (pAry[nSizeCount])
5836 {
5837 boost::property_tree::ptree aChild;
5838 aChild.put("", static_cast<float>(pAry[nSizeCount]) / 10);
5839 aChildren.push_back(std::make_pair("", aChild));
5840 nSizeCount++;
5841 }
5842 aValues.add_child(rFontMetric.GetFamilyName().toUtf8().getStr(), aChildren);
5843 }
5844 }
5845 aTree.add_child("commandValues", aValues);
5846 std::stringstream aStream;
5847 boost::property_tree::write_json(aStream, aTree);
5848 char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
5849 assert(pJson); // Don't handle OOM conditions
5850 strcpy(pJson, aStream.str().c_str());
5851 pJson[aStream.str().size()] = '\0';
5852 return pJson;
5853}
5854
5855static char* getFontSubset (std::string_view aFontName)
5856{
5857 OUString aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName, RTL_TEXTENCODING_UTF8), rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8));
5858
5859 boost::property_tree::ptree aTree;
5860 aTree.put("commandName", ".uno:FontSubset");
5861 boost::property_tree::ptree aValues;
5862
5863 if (const vcl::Font* pFont = FindFont(aFoundFont))
5864 {
5865 FontCharMapRef xFontCharMap (new FontCharMap());
5866 auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA));
5867
5868 aDevice->SetFont(*pFont);
5869 aDevice->GetFontCharMap(xFontCharMap);
5870 SubsetMap aSubMap(xFontCharMap);
5871
5872 for (auto const& subset : aSubMap.GetSubsetMap())
5873 {
5874 boost::property_tree::ptree aChild;
5875 aChild.put("", static_cast<int>(ublock_getCode(subset.GetRangeMin())));
5876 aValues.push_back(std::make_pair("", aChild));
5877 }
5878 }
5879
5880 aTree.add_child("commandValues", aValues);
5881 std::stringstream aStream;
5882 boost::property_tree::write_json(aStream, aTree);
5883 char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
5884 assert(pJson); // Don't handle OOM conditions
5885 strcpy(pJson, aStream.str().c_str());
5886 pJson[aStream.str().size()] = '\0';
5887 return pJson;
5888}
5889
5890static char* getStyles(LibreOfficeKitDocument* pThis, const char* pCommand)
5891{
5892 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
5893
5894 boost::property_tree::ptree aTree;
5895 aTree.put("commandName", pCommand);
5896 uno::Reference<css::style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(pDocument->mxComponent, uno::UNO_QUERY);
5897 const uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
5898 const uno::Sequence<OUString> aStyleFamilies = xStyleFamilies->getElementNames();
5899
5900 static const std::vector<OUString> aWriterStyles =
5901 {
5902 "Text body",
5903 "Quotations",
5904 "Title",
5905 "Subtitle",
5906 "Heading 1",
5907 "Heading 2",
5908 "Heading 3"
5909 };
5910
5911 // We need to keep a list of the default style names
5912 // in order to filter these out later when processing
5913 // the full list of styles.
5914 std::set<OUString> aDefaultStyleNames;
5915
5916 boost::property_tree::ptree aValues;
5917 for (OUString const & sStyleFam : aStyleFamilies)
5918 {
5919 boost::property_tree::ptree aChildren;
5920 uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName(sStyleFam), uno::UNO_QUERY);
5921
5922 // Writer provides a huge number of styles, we have a list of 7 "default" styles which
5923 // should be shown in the normal dropdown, which we should add to the start of the list
5924 // to simplify their selection.
5925 if (sStyleFam == "ParagraphStyles"
5926 && doc_getDocumentType(pThis) == LOK_DOCTYPE_TEXT)
5927 {
5928 for (const OUString& rStyle: aWriterStyles)
5929 {
5930 aDefaultStyleNames.insert( rStyle );
5931
5932 boost::property_tree::ptree aChild;
5933 aChild.put("", rStyle.toUtf8());
5934 aChildren.push_back(std::make_pair("", aChild));
5935 }
5936 }
5937
5938 const uno::Sequence<OUString> aStyles = xStyleFamily->getElementNames();
5939 for (const OUString& rStyle: aStyles )
5940 {
5941 // Filter out the default styles - they are already at the top
5942 // of the list
5943 if (aDefaultStyleNames.find(rStyle) == aDefaultStyleNames.end() ||
5944 (sStyleFam != "ParagraphStyles" || doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT) )
5945 {
5946 boost::property_tree::ptree aChild;
5947 aChild.put("", rStyle.toUtf8());
5948 aChildren.push_back(std::make_pair("", aChild));
5949 }
5950 }
5951 aValues.add_child(sStyleFam.toUtf8().getStr(), aChildren);
5952 }
5953
5954 // Header & Footer Styles
5955 {
5956 boost::property_tree::ptree aChild;
5957 boost::property_tree::ptree aChildren;
5958 static constexpr OUStringLiteral sPageStyles(u"PageStyles");
5961
5962 if (xStyleFamilies->hasByName(sPageStyles) && (xStyleFamilies->getByName(sPageStyles) >>= xContainer))
5963 {
5964 const uno::Sequence<OUString> aSeqNames = xContainer->getElementNames();
5965 for (OUString const & sName : aSeqNames)
5966 {
5967 bool bIsPhysical;
5968 xProperty.set(xContainer->getByName(sName), uno::UNO_QUERY);
5969 if (xProperty.is() && (xProperty->getPropertyValue("IsPhysical") >>= bIsPhysical) && bIsPhysical)
5970 {
5971 OUString displayName;
5972 xProperty->getPropertyValue("DisplayName") >>= displayName;
5973 aChild.put("", displayName.toUtf8());
5974 aChildren.push_back(std::make_pair("", aChild));
5975 }
5976 }
5977 aValues.add_child("HeaderFooter", aChildren);
5978 }
5979 }
5980
5981 {
5982 boost::property_tree::ptree aCommandList;
5983
5984 {
5985 boost::property_tree::ptree aChild;
5986
5987 OUString sClearFormat = SvxResId(RID_SVXSTR_CLEARFORM);
5988
5989 boost::property_tree::ptree aName;
5990 aName.put("", sClearFormat.toUtf8());
5991 aChild.push_back(std::make_pair("text", aName));
5992
5993 boost::property_tree::ptree aCommand;
5994 aCommand.put("", ".uno:ResetAttributes");
5995 aChild.push_back(std::make_pair("id", aCommand));
5996
5997 aCommandList.push_back(std::make_pair("", aChild));
5998 }
5999
6000 aValues.add_child("Commands", aCommandList);
6001 }
6002
6003 aTree.add_child("commandValues", aValues);
6004 std::stringstream aStream;
6005 boost::property_tree::write_json(aStream, aTree);
6006 char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
6007 assert(pJson); // Don't handle OOM conditions
6008 strcpy(pJson, aStream.str().c_str());
6009 pJson[aStream.str().size()] = '\0';
6010 return pJson;
6011}
6012
6013namespace {
6014
6015enum class UndoOrRedo
6016{
6017 UNDO,
6018 REDO
6019};
6020
6021}
6022
6024static char* getUndoOrRedo(LibreOfficeKitDocument* pThis, UndoOrRedo eCommand)
6025{
6026 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6027
6028 auto pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
6029 if (!pBaseModel)
6030 return nullptr;
6031
6032 SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
6033 if (!pObjectShell)
6034 return nullptr;
6035
6036 SfxUndoManager* pUndoManager = pObjectShell->GetUndoManager();
6037 if (!pUndoManager)
6038 return nullptr;
6039
6040 OUString aString;
6041 if (eCommand == UndoOrRedo::UNDO)
6042 aString = pUndoManager->GetUndoActionsInfo();
6043 else
6044 aString = pUndoManager->GetRedoActionsInfo();
6045 char* pJson = strdup(aString.toUtf8().getStr());
6046 return pJson;
6047}
6048
6050static char* getTrackedChanges(LibreOfficeKitDocument* pThis)
6051{
6052 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6053
6054 uno::Reference<document::XRedlinesSupplier> xRedlinesSupplier(pDocument->mxComponent, uno::UNO_QUERY);
6055 tools::JsonWriter aJson;
6056 // We want positions of the track changes also which is not possible from
6057 // UNO. Enable positioning information for text documents only for now, so
6058 // construct the tracked changes JSON from inside the sw/, not here using UNO
6059 if (doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT && xRedlinesSupplier.is())
6060 {
6061 auto redlinesNode = aJson.startArray("redlines");
6062 uno::Reference<container::XEnumeration> xRedlines = xRedlinesSupplier->getRedlines()->createEnumeration();
6063 for (size_t nIndex = 0; xRedlines->hasMoreElements(); ++nIndex)
6064 {
6065 uno::Reference<beans::XPropertySet> xRedline(xRedlines->nextElement(), uno::UNO_QUERY);
6066 auto redlineNode = aJson.startStruct();
6067 aJson.put("index", static_cast<sal_Int32>(nIndex));
6068
6069 OUString sAuthor;
6070 xRedline->getPropertyValue("RedlineAuthor") >>= sAuthor;
6071 aJson.put("author", sAuthor);
6072
6073 OUString sType;
6074 xRedline->getPropertyValue("RedlineType") >>= sType;
6075 aJson.put("type", sType);
6076
6077 OUString sComment;
6078 xRedline->getPropertyValue("RedlineComment") >>= sComment;
6079 aJson.put("comment", sComment);
6080
6081 OUString sDescription;
6082 xRedline->getPropertyValue("RedlineDescription") >>= sDescription;
6083 aJson.put("description", sDescription);
6084
6085 util::DateTime aDateTime;
6086 xRedline->getPropertyValue("RedlineDateTime") >>= aDateTime;
6087 OUString sDateTime = utl::toISO8601(aDateTime);
6088 aJson.put("dateTime", sDateTime);
6089 }
6090 }
6091 else
6092 {
6093 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6094 if (!pDoc)
6095 {
6096 SetLastExceptionMsg("Document doesn't support tiled rendering");
6097 return nullptr;
6098 }
6099 pDoc->getTrackedChanges(aJson);
6100 }
6101
6102 return strdup(aJson.finishAndGetAsOString().getStr());
6103}
6104
6105
6107static char* getTrackedChangeAuthors(LibreOfficeKitDocument* pThis)
6108{
6109 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6110 if (!pDoc)
6111 {
6112 SetLastExceptionMsg("Document doesn't support tiled rendering");
6113 return nullptr;
6114 }
6115 tools::JsonWriter aJsonWriter;
6116 pDoc->getTrackedChangeAuthors(aJsonWriter);
6117 return strdup(aJsonWriter.finishAndGetAsOString().getStr());
6118}
6119
6120static char* doc_getCommandValues(LibreOfficeKitDocument* pThis, const char* pCommand)
6121{
6122 comphelper::ProfileZone aZone("doc_getCommandValues");
6123
6124 SolarMutexGuard aGuard;
6126
6127 const std::string_view aCommand(pCommand);
6128 static constexpr OStringLiteral aViewRowColumnHeaders(".uno:ViewRowColumnHeaders");
6129 static constexpr OStringLiteral aSheetGeometryData(".uno:SheetGeometryData");
6130 static constexpr OStringLiteral aCellCursor(".uno:CellCursor");
6131 static constexpr OStringLiteral aFontSubset(".uno:FontSubset&name=");
6132
6133 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6134 if (!pDoc)
6135 {
6136 SetLastExceptionMsg("Document doesn't support tiled rendering");
6137 return nullptr;
6138 }
6139
6140 if (!strcmp(pCommand, ".uno:LanguageStatus"))
6141 {
6142 return getLanguages(pThis, pCommand);
6143 }
6144 else if (!strcmp(pCommand, ".uno:CharFontName"))
6145 {
6146 return getFonts(pCommand);
6147 }
6148 else if (!strcmp(pCommand, ".uno:StyleApply"))
6149 {
6150 return getStyles(pThis, pCommand);
6151 }
6152 else if (aCommand == ".uno:Undo")
6153 {
6154 return getUndoOrRedo(pThis, UndoOrRedo::UNDO);
6155 }
6156 else if (aCommand == ".uno:Redo")
6157 {
6158 return getUndoOrRedo(pThis, UndoOrRedo::REDO);
6159 }
6160 else if (aCommand == ".uno:AcceptTrackedChanges")
6161 {
6162 return getTrackedChanges(pThis);
6163 }
6164 else if (aCommand == ".uno:TrackedChangeAuthors")
6165 {
6166 return getTrackedChangeAuthors(pThis);
6167 }
6168 else if (aCommand == ".uno:ViewAnnotations")
6169 {
6170 return getPostIts(pThis);
6171 }
6172 else if (aCommand == ".uno:ViewAnnotationsPosition")
6173 {
6174 return getPostItsPos(pThis);
6175 }
6176 else if (aCommand == ".uno:RulerState")
6177 {
6178 return getRulerState(pThis);
6179 }
6180 else if (o3tl::starts_with(aCommand, aViewRowColumnHeaders))
6181 {
6182 tools::Rectangle aRectangle;
6183 if (aCommand.size() > o3tl::make_unsigned(aViewRowColumnHeaders.getLength()))
6184 {
6185 // Command has parameters.
6186 int nX = 0;
6187 int nY = 0;
6188 int nWidth = 0;
6189 int nHeight = 0;
6190 std::string_view aArguments = aCommand.substr(aViewRowColumnHeaders.getLength() + 1);
6191 sal_Int32 nParamIndex = 0;
6192 do
6193 {
6194 std::string_view aParamToken = o3tl::getToken(aArguments, 0, '&', nParamIndex);
6195 sal_Int32 nIndex = 0;
6196 std::string_view aKey;
6197 std::string_view aValue;
6198 do
6199 {
6200 std::string_view aToken = o3tl::getToken(aParamToken, 0, '=', nIndex);
6201 if (aKey.empty())
6202 aKey = aToken;
6203 else
6204 aValue = aToken;
6205 }
6206 while (nIndex >= 0);
6207 if (aKey == "x")
6208 nX = o3tl::toInt32(aValue);
6209 else if (aKey == "y")
6210 nY = o3tl::toInt32(aValue);
6211 else if (aKey == "width")
6212 nWidth = o3tl::toInt32(aValue);
6213 else if (aKey == "height")
6214 nHeight = o3tl::toInt32(aValue);
6215 }
6216 while (nParamIndex >= 0);
6217
6218 aRectangle = tools::Rectangle(nX, nY, nX + nWidth, nY + nHeight);
6219 }
6220
6221 tools::JsonWriter aJsonWriter;
6222 pDoc->getRowColumnHeaders(aRectangle, aJsonWriter);
6223 return strdup(aJsonWriter.finishAndGetAsOString().getStr());
6224 }
6225 else if (o3tl::starts_with(aCommand, aSheetGeometryData))
6226 {
6227 bool bColumns = true;
6228 bool bRows = true;
6229 bool bSizes = true;
6230 bool bHidden = true;
6231 bool bFiltered = true;
6232 bool bGroups = true;
6233 if (aCommand.size() > o3tl::make_unsigned(aSheetGeometryData.getLength()))
6234 {
6235 bColumns = bRows = bSizes = bHidden = bFiltered = bGroups = false;
6236
6237 std::string_view aArguments = aCommand.substr(aSheetGeometryData.getLength() + 1);
6238 sal_Int32 nParamIndex = 0;
6239 do
6240 {
6241 std::string_view aParamToken = o3tl::getToken(aArguments, 0, '&', nParamIndex);
6242 sal_Int32 nIndex = 0;
6243 std::string_view aKey;
6244 std::string_view aValue;
6245 do
6246 {
6247 std::string_view aToken = o3tl::getToken(aParamToken, 0, '=', nIndex);
6248 if (aKey.empty())
6249 aKey = aToken;
6250 else
6251 aValue = aToken;
6252
6253 } while (nIndex >= 0);
6254
6255 bool bEnableFlag = aValue.empty() ||
6256 o3tl::equalsIgnoreAsciiCase(aValue, "true") || o3tl::toInt32(aValue) > 0;
6257 if (!bEnableFlag)
6258 continue;
6259
6260 if (aKey == "columns")
6261 bColumns = true;
6262 else if (aKey == "rows")
6263 bRows = true;
6264 else if (aKey == "sizes")
6265 bSizes = true;
6266 else if (aKey == "hidden")
6267 bHidden = true;
6268 else if (aKey == "filtered")
6269 bFiltered = true;
6270 else if (aKey == "groups")
6271 bGroups = true;
6272
6273 } while (nParamIndex >= 0);
6274 }
6275
6276 OString aGeomDataStr
6277 = pDoc->getSheetGeometryData(bColumns, bRows, bSizes, bHidden, bFiltered, bGroups);
6278
6279 if (aGeomDataStr.isEmpty())
6280 return nullptr;
6281
6282 return convertOString(aGeomDataStr);
6283 }
6284 else if (o3tl::starts_with(aCommand, aCellCursor))
6285 {
6286 // Ignore command's deprecated parameters.
6287 tools::JsonWriter aJsonWriter;
6288 pDoc->getCellCursor(aJsonWriter);
6289 return strdup(aJsonWriter.finishAndGetAsOString().getStr());
6290 }
6291 else if (o3tl::starts_with(aCommand, aFontSubset))
6292 {
6293 return getFontSubset(aCommand.substr(aFontSubset.getLength()));
6294 }
6295 else if (pDoc->supportsCommand(INetURLObject(OUString::fromUtf8(aCommand)).GetURLPath()))
6296 {
6297 tools::JsonWriter aJsonWriter;
6298 pDoc->getCommandValues(aJsonWriter, aCommand);
6299 return strdup(aJsonWriter.finishAndGetAsOString().getStr());
6300 }
6301 else
6302 {
6303 SetLastExceptionMsg("Unknown command, no values returned");
6304 return nullptr;
6305 }
6306}
6307
6308static void doc_setClientZoom(LibreOfficeKitDocument* pThis, int nTilePixelWidth, int nTilePixelHeight,
6309 int nTileTwipWidth, int nTileTwipHeight)
6310{
6311 comphelper::ProfileZone aZone("doc_setClientZoom");
6312
6313 SolarMutexGuard aGuard;
6315
6316 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6317 if (!pDoc)
6318 {
6319 SetLastExceptionMsg("Document doesn't support tiled rendering");
6320 return;
6321 }
6322
6323 pDoc->setClientZoom(nTilePixelWidth, nTilePixelHeight, nTileTwipWidth, nTileTwipHeight);
6324}
6325
6326static void doc_setClientVisibleArea(LibreOfficeKitDocument* pThis, int nX, int nY, int nWidth, int nHeight)
6327{
6328 comphelper::ProfileZone aZone("doc_setClientVisibleArea");
6329
6330 SolarMutexGuard aGuard;
6332
6333 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6334 if (!pDoc)
6335 {
6336 SetLastExceptionMsg("Document doesn't support tiled rendering");
6337 return;
6338 }
6339
6340 tools::Rectangle aRectangle(Point(nX, nY), Size(nWidth, nHeight));
6341 pDoc->setClientVisibleArea(aRectangle);
6342}
6343
6344static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int nLevel, int nIndex, bool bHidden)
6345{
6346 comphelper::ProfileZone aZone("doc_setOutlineState");
6347
6348 SolarMutexGuard aGuard;
6350
6351 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6352 if (!pDoc)
6353 {
6354 SetLastExceptionMsg("Document doesn't support tiled rendering");
6355 return;
6356 }
6357
6358 pDoc->setOutlineState(bColumn, nLevel, nIndex, bHidden);
6359}
6360
6361static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis,
6362 const char* pOptions)
6363{
6364 comphelper::ProfileZone aZone("doc_createView");
6365
6366 SolarMutexGuard aGuard;
6368
6369 OUString aOptions = getUString(pOptions);
6370 const OUString aLanguage = extractParameter(aOptions, u"Language");
6371
6372 if (!aLanguage.isEmpty())
6373 {
6374 // Set the LOK language tag, used for dialog tunneling.
6377 }
6378
6379 const OUString aDeviceFormFactor = extractParameter(aOptions, u"DeviceFormFactor");
6380 SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor);
6381
6382 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6383 const int nId = SfxLokHelper::createView(pDocument->mnDocumentId);
6384
6386
6387#ifdef IOS
6388 (void) pThis;
6389#else
6390 forceSetClipboardForCurrentView(pThis);
6391#endif
6392
6393 return nId;
6394}
6395
6396static int doc_createView(LibreOfficeKitDocument* pThis)
6397{
6398 return doc_createViewWithOptions(pThis, nullptr); // No options.
6399}
6400
6401static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* pThis, int nId)
6402{
6403 comphelper::ProfileZone aZone("doc_destroyView");
6404
6405 SolarMutexGuard aGuard;
6407
6408#ifndef IOS
6410#endif
6411
6413
6414 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6416}
6417
6418static void doc_setView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int nId)
6419{
6420 comphelper::ProfileZone aZone("doc_setView");
6421
6422 SolarMutexGuard aGuard;
6424
6426}
6427
6428static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/)
6429{
6430 comphelper::ProfileZone aZone("doc_getView");
6431
6432 SolarMutexGuard aGuard;
6434
6435 return SfxLokHelper::getView();
6436}
6437
6438static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* pThis)
6439{
6440 comphelper::ProfileZone aZone("doc_getViewsCount");
6441
6442 SolarMutexGuard aGuard;
6444
6445 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6446 return SfxLokHelper::getViewsCount(pDocument->mnDocumentId);
6447}
6448
6449static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* pThis, int* pArray, size_t nSize)
6450{
6451 comphelper::ProfileZone aZone("doc_getViewsIds");
6452
6453 SolarMutexGuard aGuard;
6455
6456 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6457 return SfxLokHelper::getViewIds(pDocument->mnDocumentId, pArray, nSize);
6458}
6459
6460static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int nId, const char* language)
6461{
6462 comphelper::ProfileZone aZone("doc_setViewLanguage");
6463
6464 SolarMutexGuard aGuard;
6466
6467 OUString sLanguage = OStringToOUString(language, RTL_TEXTENCODING_UTF8);
6469 SfxLokHelper::setViewLocale(nId, sLanguage);
6470}
6471
6472unsigned char* doc_renderFont(LibreOfficeKitDocument* pThis,
6473 const char* pFontName,
6474 const char* pChar,
6475 int* pFontWidth,
6476 int* pFontHeight)
6477{
6478 return doc_renderFontOrientation(pThis, pFontName, pChar, pFontWidth, pFontHeight, 0);
6479}
6480
6481unsigned char* doc_renderFontOrientation(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/,
6482 const char* pFontName,
6483 const char* pChar,
6484 int* pFontWidth,
6485 int* pFontHeight,
6486 int pOrientation)
6487{
6488 comphelper::ProfileZone aZone("doc_renderFont");
6489
6490 SolarMutexGuard aGuard;
6492
6493 const int nDefaultFontSize = 25;
6494
6495 auto aFont = FindFont_FallbackToDefault(OStringToOUString(pFontName, RTL_TEXTENCODING_UTF8));
6496
6497 OUString aText(OStringToOUString(pChar, RTL_TEXTENCODING_UTF8));
6498 if (aText.isEmpty())
6499 aText = aFont.GetFamilyName();
6500
6501 auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA));
6502 ::tools::Rectangle aRect;
6503 aFont.SetFontSize(Size(0, nDefaultFontSize));
6504 aFont.SetOrientation(Degree10(pOrientation));
6505 aDevice->SetFont(aFont);
6506 aDevice->GetTextBoundRect(aRect, aText);
6507 if (aRect.IsEmpty())
6508 return nullptr;
6509
6510 int nFontWidth = aRect.Right() + 1;
6511 int nFontHeight = aRect.Bottom() + 1;
6512
6513 if (nFontWidth <= 0 || nFontHeight <= 0)
6514 return nullptr;
6515
6516 if (*pFontWidth > 0 && *pFontHeight > 0)
6517 {
6518 double fScaleX = *pFontWidth / static_cast<double>(nFontWidth) / 1.5;
6519 double fScaleY = *pFontHeight / static_cast<double>(nFontHeight) / 1.5;
6520
6521 double fScale = std::min(fScaleX, fScaleY);
6522
6523 if (fScale >= 1.0)
6524 {
6525 int nFontSize = fScale * nDefaultFontSize;
6526 aFont.SetFontSize(Size(0, nFontSize));
6527 aDevice->SetFont(aFont);
6528 }
6529
6530 aRect = tools::Rectangle(0, 0, *pFontWidth, *pFontHeight);
6531
6532 nFontWidth = *pFontWidth;
6533 nFontHeight = *pFontHeight;
6534
6535 }
6536
6537 unsigned char* pBuffer = static_cast<unsigned char*>(malloc(4 * nFontWidth * nFontHeight));
6538 if (!pBuffer)
6539 return nullptr;
6540
6541 memset(pBuffer, 0, nFontWidth * nFontHeight * 4);
6542 aDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
6543 aDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(
6544 Size(nFontWidth, nFontHeight), Fraction(1.0), Point(),
6545 pBuffer);
6546
6547 if (*pFontWidth > 0 && *pFontHeight > 0)
6548 {
6549 DrawTextFlags const nStyle =
6550 DrawTextFlags::Center
6551 | DrawTextFlags::VCenter
6552 | DrawTextFlags::MultiLine
6553 | DrawTextFlags::WordBreak;// | DrawTextFlags::WordBreakHyphenation ;
6554
6555 aDevice->DrawText(aRect, aText, nStyle);
6556 }
6557 else
6558 {
6559 *pFontWidth = nFontWidth;
6560 *pFontHeight = nFontHeight;
6561
6562 aDevice->DrawText(Point(0,0), aText);
6563 }
6564
6565
6566 return pBuffer;
6567}
6568
6569
6570static void doc_paintWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
6571 unsigned char* pBuffer,
6572 const int nX, const int nY,
6573 const int nWidth, const int nHeight)
6574{
6575 doc_paintWindowDPI(pThis, nLOKWindowId, pBuffer, nX, nY, nWidth, nHeight, 1.0);
6576}
6577
6578static void doc_paintWindowDPI(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
6579 unsigned char* pBuffer,
6580 const int nX, const int nY,
6581 const int nWidth, const int nHeight,
6582 const double fDPIScale)
6583{
6584 doc_paintWindowForView(pThis, nLOKWindowId, pBuffer, nX, nY, nWidth, nHeight, fDPIScale, -1);
6585}
6586
6587static void doc_paintWindowForView(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
6588 unsigned char* pBuffer, const int nX, const int nY,
6589 const int nWidth, const int nHeight,
6590 const double fDPIScale, int viewId)
6591{
6592 comphelper::ProfileZone aZone("doc_paintWindowDPI");
6593
6594 SolarMutexGuard aGuard;
6596
6597 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
6598 if (!pWindow)
6599 {
6600 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
6601 return;
6602 }
6603
6604 // Used to avoid work in setView if set.
6606
6607 if (viewId >= 0)
6608 doc_setView(pThis, viewId);
6609
6610 // Setup cairo (or CoreGraphics, in the iOS case) to draw with the changed DPI scale (and return
6611 // back to 1.0 when the painting finishes)
6614
6615#if defined(IOS)
6616 // Onine uses the LOK_TILEMODE_RGBA by default so flip the normal flags
6617 // to kCGImageAlphaNoneSkipLast | kCGImageByteOrder32Big
6618 CGContextRef cgc = CGBitmapContextCreate(pBuffer, nWidth, nHeight, 8, nWidth*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipLast | kCGImageByteOrder32Big);
6619
6620 CGContextTranslateCTM(cgc, 0, nHeight);
6621 CGContextScaleCTM(cgc, fDPIScale, -fDPIScale);
6622
6624 aData.rCGContext = cgc;
6625
6626 ScopedVclPtrInstance<VirtualDevice> pDevice(aData, Size(1, 1), DeviceFormat::WITHOUT_ALPHA);
6627 pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
6628
6629 pDevice->SetOutputSizePixel(Size(nWidth, nHeight));
6630
6631 MapMode aMapMode(pDevice->GetMapMode());
6632 aMapMode.SetOrigin(Point(-(nX / fDPIScale), -(nY / fDPIScale)));
6633 pDevice->SetMapMode(aMapMode);
6634
6635 pWindow->PaintToDevice(pDevice.get(), Point(0, 0));
6636
6637 CGContextRelease(cgc);
6638
6639#else
6640
6641 ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
6642 pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
6643
6644 pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nWidth, nHeight), Fraction(1.0), Point(), pBuffer);
6645
6646 MapMode aMapMode(pDevice->GetMapMode());
6647 aMapMode.SetOrigin(Point(-(nX / fDPIScale), -(nY / fDPIScale)));
6648 pDevice->SetMapMode(aMapMode);
6649
6650 pWindow->PaintToDevice(pDevice.get(), Point(0, 0));
6651#endif
6652
6654}
6655
6656static void doc_postWindow(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, int nAction, const char* pData)
6657{
6658 comphelper::ProfileZone aZone("doc_postWindow");
6659
6660 SolarMutexGuard aGuard;
6662
6663 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
6664 if (!pWindow)
6665 {
6666 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
6667 return;
6668 }
6669
6670 if (nAction == LOK_WINDOW_CLOSE)
6671 {
6672 vcl::CloseTopLevel(pWindow);
6673 }
6674 else if (nAction == LOK_WINDOW_PASTE)
6675 {
6676#ifndef IOS
6677 OUString aMimeType;
6678 css::uno::Sequence<sal_Int8> aData;
6679 std::vector<beans::PropertyValue> aArgs(jsonToPropertyValuesVector(pData));
6680 {
6681 aArgs.size() == 2 &&
6682 aArgs[0].Name == "MimeType" && (aArgs[0].Value >>= aMimeType) &&
6683 aArgs[1].Name == "Data" && (aArgs[1].Value >>= aData);
6684 }
6685
6686 if (!aMimeType.isEmpty() && aData.hasElements())
6687 {
6690 xClipboard->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
6691 pWindow->SetClipboard(xClipboard);
6692
6693 KeyEvent aEvent(0, KEY_PASTE, 0);
6694 Application::PostKeyEvent(VclEventId::WindowKeyInput, pWindow, &aEvent);
6695 }
6696 else
6697 SetLastExceptionMsg("Window command 'paste': wrong parameters.");
6698#else
6699 (void) pData;
6700 assert(!"doc_postWindow() with LOK_WINDOW_PASTE should not be called on iOS");
6701#endif
6702 }
6703}
6704
6705// CERTIFICATE AND DOCUMENT SIGNING
6706static bool doc_insertCertificate(LibreOfficeKitDocument* pThis,
6707 const unsigned char* pCertificateBinary, const int nCertificateBinarySize,
6708 const unsigned char* pPrivateKeyBinary, const int nPrivateKeySize)
6709{
6710 comphelper::ProfileZone aZone("doc_insertCertificate");
6711
6712 if (!xContext.is())
6713 return false;
6714
6715 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6716
6717 if (!pDocument->mxComponent.is())
6718 return false;
6719
6720 SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
6721 if (!pBaseModel)
6722 return false;
6723
6724 SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
6725
6726 if (!pObjectShell)
6727 return false;
6728
6730 uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
6731 if (!xSecurityContext.is())
6732 return false;
6733
6734 uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
6735 uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY);
6736
6737 if (!xCertificateCreator.is())
6738 return false;
6739
6740 uno::Sequence<sal_Int8> aCertificateSequence;
6741
6742 std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize);
6743 std::string aCertificateBase64String = extractCertificate(aCertificateString);
6744 if (!aCertificateBase64String.empty())
6745 {
6746 OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String);
6747 comphelper::Base64::decode(aCertificateSequence, aBase64OUString);
6748 }
6749 else
6750 {
6751 aCertificateSequence.realloc(nCertificateBinarySize);
6752 std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.getArray());
6753 }
6754
6755 uno::Sequence<sal_Int8> aPrivateKeySequence;
6756 std::string aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary), nPrivateKeySize);
6757 std::string aPrivateKeyBase64String = extractPrivateKey(aPrivateKeyString);
6758 if (!aPrivateKeyBase64String.empty())
6759 {
6760 OUString aBase64OUString = OUString::createFromAscii(aPrivateKeyBase64String);
6761 comphelper::Base64::decode(aPrivateKeySequence, aBase64OUString);
6762 }
6763 else
6764 {
6765 aPrivateKeySequence.realloc(nPrivateKeySize);
6766 std::copy(pPrivateKeyBinary, pPrivateKeyBinary + nPrivateKeySize, aPrivateKeySequence.getArray());
6767 }
6768
6769 uno::Reference<security::XCertificate> xCertificate = xCertificateCreator->createDERCertificateWithPrivateKey(aCertificateSequence, aPrivateKeySequence);
6770
6771 if (!xCertificate.is())
6772 return false;
6773
6774 SolarMutexGuard aGuard;
6775
6776 return pObjectShell->SignDocumentContentUsingCertificate(xCertificate);
6777}
6778
6779static bool doc_addCertificate(LibreOfficeKitDocument* pThis,
6780 const unsigned char* pCertificateBinary, const int nCertificateBinarySize)
6781{
6782 comphelper::ProfileZone aZone("doc_addCertificate");
6783
6784 if (!xContext.is())
6785 return false;
6786
6787 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6788
6789 if (!pDocument->mxComponent.is())
6790 return false;
6791
6792 SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
6793 if (!pBaseModel)
6794 return false;
6795
6796 SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
6797
6798 if (!pObjectShell)
6799 return false;
6800
6802 uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
6803 if (!xSecurityContext.is())
6804 return false;
6805
6806 uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
6807 uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY);
6808
6809 if (!xCertificateCreator.is())
6810 return false;
6811
6812 uno::Sequence<sal_Int8> aCertificateSequence;
6813
6814 std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize);
6815 std::string aCertificateBase64String = extractCertificate(aCertificateString);
6816 if (!aCertificateBase64String.empty())
6817 {
6818 OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String);
6819 comphelper::Base64::decode(aCertificateSequence, aBase64OUString);
6820 }
6821 else
6822 {
6823 aCertificateSequence.realloc(nCertificateBinarySize);
6824 std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.getArray());
6825 }
6826
6827 uno::Reference<security::XCertificate> xCertificate = xCertificateCreator->addDERCertificateToTheDatabase(aCertificateSequence, "TCu,Cu,Tu");
6828
6829 if (!xCertificate.is())
6830 return false;
6831
6832 SAL_INFO("lok", "Certificate Added = IssuerName: " << xCertificate->getIssuerName() << " SubjectName: " << xCertificate->getSubjectName());
6833
6834 return true;
6835}
6836
6837static int doc_getSignatureState(LibreOfficeKitDocument* pThis)
6838{
6839 comphelper::ProfileZone aZone("doc_getSignatureState");
6840
6841 LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
6842
6843 if (!pDocument->mxComponent.is())
6844 return int(SignatureState::UNKNOWN);
6845
6846 SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
6847 if (!pBaseModel)
6848 return int(SignatureState::UNKNOWN);
6849
6850 SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
6851 if (!pObjectShell)
6852 return int(SignatureState::UNKNOWN);
6853
6854 SolarMutexGuard aGuard;
6855
6856 pObjectShell->RecheckSignature(false);
6857
6858 return int(pObjectShell->GetDocumentSignatureState());
6859}
6860
6861static void doc_resizeWindow(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId,
6862 const int nWidth, const int nHeight)
6863{
6864 SolarMutexGuard aGuard;
6865 if (gImpl)
6866 gImpl->maLastExceptionMsg.clear();
6867
6868 VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
6869 if (!pWindow)
6870 {
6871 gImpl->maLastExceptionMsg = "Document doesn't support dialog resizing, or window not found.";
6872 return;
6873 }
6874
6875 pWindow->SetSizePixel(Size(nWidth, nHeight));
6876}
6877
6878static void doc_completeFunction(LibreOfficeKitDocument* pThis, const char* pFunctionName)
6879{
6880 SolarMutexGuard aGuard;
6882
6883 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6884 if (!pDoc)
6885 {
6886 SetLastExceptionMsg("Document doesn't support tiled rendering");
6887 return;
6888 }
6889
6890 pDoc->completeFunction(OUString::fromUtf8(pFunctionName));
6891}
6892
6893
6894static void doc_sendFormFieldEvent(LibreOfficeKitDocument* pThis, const char* pArguments)
6895{
6896 SolarMutexGuard aGuard;
6897
6898 // Supported in Writer only
6899 if (doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT)
6900 return;
6901
6903 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6904 if (!pDoc)
6905 {
6906 SetLastExceptionMsg("Document doesn't support tiled rendering!");
6907 return;
6908 }
6909
6910 // Sanity check
6911 if (aMap.find("type") == aMap.end() || aMap.find("cmd") == aMap.end())
6912 {
6913 SetLastExceptionMsg("Wrong arguments for sendFormFieldEvent!");
6914 return;
6915 }
6916
6917 pDoc->executeFromFieldEvent(aMap);
6918}
6919
6920static bool doc_renderSearchResult(LibreOfficeKitDocument* pThis,
6921 const char* pSearchResult, unsigned char** pBitmapBuffer,
6922 int* pWidth, int* pHeight, size_t* pByteSize)
6923{
6924 if (doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT)
6925 return false;
6926
6927 if (pBitmapBuffer == nullptr)
6928 return false;
6929
6930 if (!pSearchResult || pSearchResult[0] == '\0')
6931 return false;
6932
6933 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6934 if (!pDoc)
6935 {
6936 SetLastExceptionMsg("Document doesn't support tiled rendering");
6937 return false;
6938 }
6939
6940 auto aRectangleVector = pDoc->getSearchResultRectangles(pSearchResult);
6941
6942 // combine into a rectangle union
6943 basegfx::B2DRange aRangeUnion;
6944 for (basegfx::B2DRange const & rRange : aRectangleVector)
6945 {
6946 aRangeUnion.expand(rRange);
6947 }
6948
6949 int aPixelWidth = o3tl::convert(aRangeUnion.getWidth(), o3tl::Length::twip, o3tl::Length::px);
6950 int aPixelHeight = o3tl::convert(aRangeUnion.getHeight(), o3tl::Length::twip, o3tl::Length::px);
6951
6952 size_t nByteSize = aPixelWidth * aPixelHeight * 4;
6953
6954 *pWidth = aPixelWidth;
6955 *pHeight = aPixelHeight;
6956 *pByteSize = nByteSize;
6957
6958 auto* pBuffer = static_cast<unsigned char*>(std::malloc(nByteSize));
6959
6960 doc_paintTile(pThis, pBuffer,
6961 aPixelWidth, aPixelHeight,
6962 aRangeUnion.getMinX(), aRangeUnion.getMinY(),
6963 aRangeUnion.getWidth(), aRangeUnion.getHeight());
6964
6965 *pBitmapBuffer = pBuffer;
6966
6967 return true;
6968}
6969
6970static void doc_sendContentControlEvent(LibreOfficeKitDocument* pThis, const char* pArguments)
6971{
6972 SolarMutexGuard aGuard;
6973
6974 // Supported in Writer only
6975 if (doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT)
6976 {
6977 return;
6978 }
6979
6981 ITiledRenderable* pDoc = getTiledRenderable(pThis);
6982 if (!pDoc)
6983 {
6984 SetLastExceptionMsg("Document doesn't support tiled rendering");
6985 return;
6986 }
6987
6988 // Sanity check
6989 if (aMap.find("type") == aMap.end())
6990 {
6991 SetLastExceptionMsg("Missing 'type' argument for sendContentControlEvent");
6992 return;
6993 }
6994
6995 pDoc->executeContentControlEvent(aMap);
6996}
6997
6998static void doc_setViewTimezone(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int nId,
6999 const char* pTimezone)
7000{
7001 comphelper::ProfileZone aZone("doc_setViewTimezone");
7002
7003 SolarMutexGuard aGuard;
7005
7006 // Leave the default if we get a null timezone.
7007 if (pTimezone)
7008 {
7009 OUString sTimezone = OStringToOUString(pTimezone, RTL_TEXTENCODING_UTF8);
7010 SfxLokHelper::setViewTimezone(nId, true, sTimezone);
7011 }
7012}
7013
7014static void doc_setAccessibilityState(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* pThis, int nId, bool nEnabled)
7015{
7016 SolarMutexGuard aGuard;
7018
7019 int nDocType = getDocumentType(pThis);
7020 if (nDocType != LOK_DOCTYPE_TEXT)
7021 return;
7022
7024}
7025
7026static char* lo_getError (LibreOfficeKit *pThis)
7027{
7028 comphelper::ProfileZone aZone("lo_getError");
7029
7030 SolarMutexGuard aGuard;
7031
7032 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
7033 return convertOUString(pLib->maLastExceptionMsg);
7034}
7035
7036static void lo_freeError(char* pFree)
7037{
7038 free(pFree);
7039}
7040
7041static char* lo_getFilterTypes(LibreOfficeKit* pThis)
7042{
7043 SolarMutexGuard aGuard;
7045
7046 LibLibreOffice_Impl* pImpl = static_cast<LibLibreOffice_Impl*>(pThis);
7047
7048 if (!xSFactory.is())
7050
7051 if (!xSFactory.is())
7052 {
7053 pImpl->maLastExceptionMsg = "Service factory is not available";
7054 return nullptr;
7055 }
7056
7057 uno::Reference<container::XNameAccess> xTypeDetection(xSFactory->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
7058 const uno::Sequence<OUString> aTypes = xTypeDetection->getElementNames();
7059 tools::JsonWriter aJson;
7060 for (const OUString& rType : aTypes)
7061 {
7063 if (xTypeDetection->getByName(rType) >>= aValues)
7064 {
7065 auto it = std::find_if(std::cbegin(aValues), std::cend(aValues), [](const beans::PropertyValue& rValue) { return rValue.Name == "MediaType"; });
7066 OUString aValue;
7067 if (it != std::cend(aValues) && (it->Value >>= aValue) && !aValue.isEmpty())
7068 {
7069 auto typeNode = aJson.startNode(rType.toUtf8());
7070 aJson.put("MediaType", aValue.toUtf8());
7071 }
7072 }
7073 }
7074
7075 return strdup(aJson.finishAndGetAsOString().getStr());
7076}
7077
7078static void lo_setOptionalFeatures(LibreOfficeKit* pThis, unsigned long long const features)
7079{
7080 comphelper::ProfileZone aZone("lo_setOptionalFeatures");
7081
7082 SolarMutexGuard aGuard;
7084
7085 LibLibreOffice_Impl *const pLib = static_cast<LibLibreOffice_Impl*>(pThis);
7086 pLib->mOptionalFeatures = features;
7087 if (features & LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK)
7089 if (features & LOK_FEATURE_NO_TILED_ANNOTATIONS)
7091 if (features & LOK_FEATURE_RANGE_HEADERS)
7093 if (features & LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK)
7095}
7096
7097static void lo_setDocumentPassword(LibreOfficeKit* pThis,
7098 const char* pURL, const char* pPassword)
7099{
7100 comphelper::ProfileZone aZone("lo_setDocumentPassword");
7101
7102 SolarMutexGuard aGuard;
7104
7105 assert(pThis);
7106 assert(pURL);
7107 LibLibreOffice_Impl *const pLib = static_cast<LibLibreOffice_Impl*>(pThis);
7108 assert(pLib->mInteractionMap.find(OString(pURL)) != pLib->mInteractionMap.end());
7109 pLib->mInteractionMap.find(OString(pURL))->second->SetPassword(pPassword);
7110}
7111
7112static char* lo_getVersionInfo(SAL_UNUSED_PARAMETER LibreOfficeKit* /*pThis*/)
7113{
7116 "{ "
7117 "\"ProductName\": \"%PRODUCTNAME\", "
7118 "\"ProductVersion\": \"%PRODUCTVERSION\", "
7119 "\"ProductExtension\": \"%PRODUCTEXTENSION\", "
7120 "\"BuildId\": \"%BUILDID\", "
7121 "\"BuildConfig\": \"" BUILDCONFIG "\" "
7122 "}"));
7123}
7124
7125static void aBasicErrorFunc(const OUString& rError, const OUString& rAction)
7126{
7127 OString aBuffer = "Unexpected dialog: " +
7128 OUStringToOString(rAction, RTL_TEXTENCODING_ASCII_US) +
7129 " Error: " +
7130 OUStringToOString(rError, RTL_TEXTENCODING_ASCII_US);
7131
7132 fprintf(stderr, "Unexpected basic error dialog '%s'\n", aBuffer.getStr());
7133}
7134
7135static bool initialize_uno(const OUString& aAppProgramURL)
7136{
7137#ifdef IOS
7138 // For iOS we already hardcode the inifile as "rc" in the .app directory.
7139 rtl::Bootstrap::setIniFilename(aAppProgramURL + "/" SAL_CONFIGFILE("fundamental"));
7141#elif defined MACOSX
7142 rtl::Bootstrap::setIniFilename(aAppProgramURL + "/../Resources/" SAL_CONFIGFILE("soffice"));
7144#else
7145 rtl::Bootstrap::setIniFilename(aAppProgramURL + "/" SAL_CONFIGFILE("soffice"));
7147#endif
7148
7149 if (!xContext.is())
7150 {
7151 SetLastExceptionMsg("XComponentContext could not be created");
7152 SAL_INFO("lok", "XComponentContext could not be created");
7153 return false;
7154 }
7155
7156 xFactory = xContext->getServiceManager();
7157 if (!xFactory.is())
7158 {
7159 SetLastExceptionMsg("XMultiComponentFactory could not be created");
7160 SAL_INFO("lok", "XMultiComponentFactory could not be created");
7161 return false;
7162 }
7163
7164 xSFactory.set(xFactory, uno::UNO_QUERY_THROW);
7166
7167 SAL_INFO("lok", "Uno initialized - " << xContext.is());
7168
7169 // set UserInstallation to user profile dir in test/user-template
7170// rtl::Bootstrap aDefaultVars;
7171// aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
7172 // configmgr setup ?
7173
7174 return true;
7175}
7176
7177// pre-unipoll version.
7178static void lo_startmain(void*)
7179{
7180 osl_setThreadName("lo_startmain");
7181
7184
7186
7187 soffice_main();
7188
7190}
7191
7192// unipoll version.
7193static void lo_runLoop(LibreOfficeKit* /*pThis*/,
7194 LibreOfficeKitPollCallback pPollCallback,
7195 LibreOfficeKitWakeCallback pWakeCallback,
7196 void* pData)
7197{
7198#if defined(IOS) || defined(ANDROID) || defined(__EMSCRIPTEN__)
7200#endif
7201
7202 {
7203 SolarMutexGuard aGuard;
7204
7205 vcl::lok::registerPollCallbacks(pPollCallback, pWakeCallback, pData);
7207 soffice_main();
7208 }
7209#if defined(IOS) || defined(ANDROID) || defined(__EMSCRIPTEN__)
7212#endif
7213}
7214
7215static bool bInitialized = false;
7216
7217static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent, const char* pText)
7218{
7219 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(data);
7220
7221 if (!pLib->mpCallback)
7222 return;
7223
7224 switch (type)
7225 {
7227 pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START, pText, pLib->mpCallbackData);
7228 break;
7230 pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE,
7231 OUString(OUString::number(percent)).toUtf8().getStr(), pLib->mpCallbackData);
7232 break;
7234 pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH, nullptr, pLib->mpCallbackData);
7235 break;
7236 }
7237}
7238
7241{
7242 std::unordered_map<OUString, css::uno::Reference<com::sun::star::ui::XAcceleratorConfiguration>>& acceleratorConfs = SfxLokHelper::getAcceleratorConfs();
7243 css::uno::Sequence<OUString> installedLocales(officecfg::Setup::Office::InstalledLocales::get()->getElementNames());
7244 OUString actualLang = officecfg::Setup::L10N::ooLocale::get();
7245
7246 for (sal_Int32 i = 0; i < installedLocales.getLength(); i++)
7247 {
7248 OUString language = LanguageTag(installedLocales[i]).getLocale().Language;
7249
7251 {
7252 // Language is listed by COOL and also installed in core. We can create the short cut accelerator.
7253
7254 // Set the UI language to current one, before creating the accelerator.
7255 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
7256 officecfg::Setup::L10N::ooLocale::set(installedLocales[i], batch);
7257 batch->commit();
7258
7259 // Supported module names: Writer, Calc, Draw, Impress
7260 std::vector<OUString> supportedModuleNames = { "com.sun.star.text.TextDocument", "com.sun.star.sheet.SpreadsheetDocument", "com.sun.star.drawing.DrawingDocument", "com.sun.star.presentation.PresentationDocument" };
7261 // Create the accelerators.
7262 for (std::size_t j = 0; j < supportedModuleNames.size(); j++)
7263 {
7264 OUString key = supportedModuleNames[j] + installedLocales[i];
7265 acceleratorConfs[key] = svt::AcceleratorExecute::lok_createNewAcceleratorConfiguration(::comphelper::getProcessComponentContext(), supportedModuleNames[j]);
7266 }
7267 }
7268 else
7269 {
7270 std::cerr << "Language is installed in core but not in the list of COOL languages: " << language << "\n";
7271 }
7272 }
7273
7274 // Set the UI language back to default one.
7275 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
7276 officecfg::Setup::L10N::ooLocale::set(actualLang, batch);
7277 batch->commit();
7278}
7279
7281static void preloadData()
7282{
7283 comphelper::ProfileZone aZone("preload data");
7284
7285 // Create user profile in the temp directory for loading the dictionaries
7286 OUString sUserPath;
7287 rtl::Bootstrap::get("UserInstallation", sUserPath);
7288 utl::TempFileNamed aTempDir(nullptr, true);
7289 aTempDir.EnableKillingFile();
7290 rtl::Bootstrap::set("UserInstallation", aTempDir.GetURL());
7291
7292 // Register the bundled extensions
7295 if(bAbort)
7296 std::cerr << "CheckExtensionDependencies failed" << std::endl;
7297
7298 // preload all available dictionaries
7299 css::uno::Reference<css::linguistic2::XLinguServiceManager> xLngSvcMgr =
7301 css::uno::Reference<linguistic2::XSpellChecker> xSpellChecker(xLngSvcMgr->getSpellChecker());
7302
7303 std::cerr << "Preloading dictionaries: ";
7304 css::uno::Reference<linguistic2::XSupportedLocales> xSpellLocales(xSpellChecker, css::uno::UNO_QUERY_THROW);
7305 uno::Sequence< css::lang::Locale > aLocales = xSpellLocales->getLocales();
7306 for (auto &it : std::as_const(aLocales))
7307 {
7308 std::cerr << LanguageTag::convertToBcp47(it) << " ";
7309 css::beans::PropertyValues aNone;
7310 xSpellChecker->isValid("forcefed", it, aNone);
7311 }
7312 std::cerr << "\n";
7313
7314 // Hack to load and cache the module liblocaledata_others.so which is not loaded normally
7315 // (when loading dictionaries of just non-Asian locales). Creating a XCalendar4 of one Asian locale
7316 // will cheaply load this missing "others" locale library. Appending an Asian locale in
7317 // LOK_ALLOWLIST_LANGUAGES env-var also works but at the cost of loading that dictionary.
7318 css::uno::Reference< css::i18n::XCalendar4 > xCal = css::i18n::LocaleCalendar2::create(comphelper::getProcessComponentContext());
7319 css::lang::Locale aAsianLocale = {"hi", "IN", ""};
7320 xCal->loadDefaultCalendar(aAsianLocale);
7321
7322 // preload all available thesauri
7323 css::uno::Reference<linguistic2::XThesaurus> xThesaurus(xLngSvcMgr->getThesaurus());
7324 css::uno::Reference<linguistic2::XSupportedLocales> xThesLocales(xSpellChecker, css::uno::UNO_QUERY_THROW);
7325 aLocales = xThesLocales->getLocales();
7326 std::cerr << "Preloading thesauri: ";
7327 for (auto &it : std::as_const(aLocales))
7328 {
7329 std::cerr << LanguageTag::convertToBcp47(it) << " ";
7330 css::beans::PropertyValues aNone;
7331 xThesaurus->queryMeanings("forcefed", it, aNone);
7332 }
7333 std::cerr << "\n";
7334
7335 css::uno::Reference< css::ui::XAcceleratorConfiguration > xGlobalCfg = css::ui::GlobalAcceleratorConfiguration::create(
7337 xGlobalCfg->getAllKeyEvents();
7338
7339 std::cerr << "Preload icons\n";
7340 ImageTree &images = ImageTree::get();
7341 images.getImageUrl("forcefed.png", "style", "FO_oo");
7342
7343 std::cerr << "Preload short cut accelerators\n";
7345
7346 std::cerr << "Preload languages\n";
7347
7348 // force load language singleton
7350 (void)LanguageTag::isValidBcp47("foo", nullptr);
7351
7352 std::cerr << "Preload fonts\n";
7353
7354 // Initialize fonts.
7355 css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLangSrv = css::linguistic2::LinguServiceManager::create(xContext);
7356 if (xLangSrv.is())
7357 {
7358 css::uno::Reference<css::linguistic2::XSpellChecker> xSpell = xLangSrv->getSpellChecker();
7359 if (xSpell.is())
7360 aLocales = xSpell->getLocales();
7361 }
7362
7363 for (const auto& aLocale : std::as_const(aLocales))
7364 {
7365 //TODO: Add more types and cache more aggressively. For now this initializes the fontcache.
7366 using namespace ::com::sun::star::i18n::ScriptType;
7367 LanguageType nLang;
7369 OutputDevice::GetDefaultFont(DefaultFontType::LATIN_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne);
7371 OutputDevice::GetDefaultFont(DefaultFontType::CJK_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne);
7373 OutputDevice::GetDefaultFont(DefaultFontType::CTL_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne);
7374 }
7375
7376 std::cerr << "Preload config\n";
7377#if defined __GNUC__ || defined __clang__
7378#pragma GCC diagnostic push
7379#pragma GCC diagnostic ignored "-Wunused-variable"
7380#endif
7381 static SvtOptionsDialogOptions aDialogOptions;
7382 static SvtCTLOptions aSvtCTLOptions;
7383 static SvtAccessibilityOptions aSvtAccessibilityOptions;
7384 static svtools::ColorConfig aColorConfig;
7385 static SvtMiscOptions aSvtMiscOptions;
7386 static SvtSlideSorterBarOptions aSvtSlideSorterBarOptions;
7387 static SvtCommandOptions aSvtCommandOptions;
7388 static SvtCompatibilityOptions aSvtCompatibilityOptions;
7389 static SvtFilterOptions aSvtFilterOptions;
7390 static SvtLinguConfig aSvtLinguConfig;
7391 static SvtModuleOptions aSvtModuleOptions;
7392 static SvtPathOptions aSvtPathOptions;
7393 static SvtSearchOptions aSvtSearchOptions;
7394 static SvtSysLocaleOptions aSvtSysLocaleOptions;
7395 static SvtUserOptions aSvtUserOptions;
7396 //static SvtViewOptions aSvtViewOptions;
7397 static MouseSettings aMouseSettings;
7398 static StyleSettings aStyleSettings;
7399 static MiscSettings aMiscSettings;
7400 static HelpSettings aHelpSettings;
7401 static AllSettings aAllSettings;
7402#if defined __GNUC__ || defined __clang__
7403#pragma GCC diagnostic pop
7404#endif
7405
7406 // Set user profile's path back to the original one
7407 rtl::Bootstrap::set("UserInstallation", sUserPath);
7408}
7409
7410namespace {
7411
7412static void activateNotebookbar(std::u16string_view rApp)
7413{
7414 OUString aPath = OUString::Concat("org.openoffice.Office.UI.ToolbarMode/Applications/") + rApp;
7415
7416 const utl::OConfigurationTreeRoot aAppNode(xContext, aPath, true);
7417
7418 if (aAppNode.isValid())
7419 {
7420 aAppNode.setNodeValue("Active", Any(OUString("notebookbar_online.ui")));
7421 aAppNode.commit();
7422 }
7423}
7424
7425void setCertificateDir()
7426{
7427 const char* pEnvVarString = ::getenv("LO_CERTIFICATE_DATABASE_PATH");
7428 if (pEnvVarString)
7429 {
7430 OUString aCertificateDatabasePath = OStringToOUString(pEnvVarString, RTL_TEXTENCODING_UTF8);
7431 try
7432 {
7433 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(comphelper::ConfigurationChanges::create());
7434 officecfg::Office::Common::Security::Scripting::CertDir::set(aCertificateDatabasePath, pBatch);
7435 officecfg::Office::Common::Security::Scripting::ManualCertDir::set(aCertificateDatabasePath, pBatch);
7436 pBatch->commit();
7437 }
7438 catch (uno::Exception const& rException)
7439 {
7440 SAL_WARN("lok", "Failed to set the NSS certificate database directory: " << rException.Message);
7441 }
7442 }
7443}
7444
7445void setDeeplConfig()
7446{
7447 const char* pAPIUrlString = ::getenv("DEEPL_API_URL");
7448 const char* pAuthKeyString = ::getenv("DEEPL_AUTH_KEY");
7449 if (pAPIUrlString && pAuthKeyString)
7450 {
7451 OUString aAPIUrl = OStringToOUString(pAPIUrlString, RTL_TEXTENCODING_UTF8);
7452 OUString aAuthKey = OStringToOUString(pAuthKeyString, RTL_TEXTENCODING_UTF8);
7453 try
7454 {
7455 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
7456 officecfg::Office::Linguistic::Translation::Deepl::ApiURL::set(aAPIUrl, batch);
7457 officecfg::Office::Linguistic::Translation::Deepl::AuthKey::set(aAuthKey, batch);
7458 batch->commit();
7459 }
7460 catch(uno::Exception const& rException)
7461 {
7462 SAL_WARN("lok", "Failed to set Deepl API settings: " << rException.Message);
7463 }
7464 }
7465}
7466
7467void setLanguageToolConfig()
7468{
7469 const char* pEnabled = ::getenv("LANGUAGETOOL_ENABLED");
7470 const char* pBaseUrlString = ::getenv("LANGUAGETOOL_BASEURL");
7471
7472 if (pEnabled && pBaseUrlString)
7473 {
7474 const char* pUsername = ::getenv("LANGUAGETOOL_USERNAME");
7475 const char* pApikey = ::getenv("LANGUAGETOOL_APIKEY");
7476 const char* pSSLVerification = ::getenv("LANGUAGETOOL_SSL_VERIFICATION");
7477 const char* pRestProtocol = ::getenv("LANGUAGETOOL_RESTPROTOCOL");
7478
7479 OUString aEnabled = OStringToOUString(pEnabled, RTL_TEXTENCODING_UTF8);
7480 if (aEnabled != "true")
7481 return;
7482 OUString aBaseUrl = OStringToOUString(pBaseUrlString, RTL_TEXTENCODING_UTF8);
7483 try
7484 {
7485 using LanguageToolCfg = officecfg::Office::Linguistic::GrammarChecking::LanguageTool;
7487
7488 LanguageToolCfg::BaseURL::set(aBaseUrl, batch);
7489 LanguageToolCfg::IsEnabled::set(true, batch);
7490 if (pSSLVerification)
7491 {
7492 OUString aSSLVerification = OStringToOUString(pSSLVerification, RTL_TEXTENCODING_UTF8);
7493 LanguageToolCfg::SSLCertVerify::set(aSSLVerification == "true", batch);
7494 }
7495 if (pRestProtocol)
7496 {
7497 OUString aRestProtocol = OStringToOUString(pRestProtocol, RTL_TEXTENCODING_UTF8);
7498 LanguageToolCfg::RestProtocol::set(aRestProtocol, batch);
7499 }
7500 if (pUsername && pApikey)
7501 {
7502 OUString aUsername = OStringToOUString(pUsername, RTL_TEXTENCODING_UTF8);
7503 OUString aApiKey = OStringToOUString(pApikey, RTL_TEXTENCODING_UTF8);
7504 LanguageToolCfg::Username::set(aUsername, batch);
7505 LanguageToolCfg::ApiKey::set(aApiKey, batch);
7506 }
7507 batch->commit();
7508
7509 css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLangSrv =
7511 if (xLangSrv.is())
7512 {
7513 css::uno::Reference<css::linguistic2::XSpellChecker> xSpell = xLangSrv->getSpellChecker();
7514 if (xSpell.is())
7515 {
7516 Sequence<OUString> aEmpty;
7517 Sequence<css::lang::Locale> aLocales = xSpell->getLocales();
7518
7519 for (int itLocale = 0; itLocale < aLocales.getLength(); itLocale++)
7520 {
7521 xLangSrv->setConfiguredServices(SN_SPELLCHECKER, aLocales[itLocale], aEmpty);
7522 }
7523 }
7524 }
7525 }
7526 catch(uno::Exception const& rException)
7527 {
7528 SAL_WARN("lok", "Failed to set LanguageTool API settings: " << rException.Message);
7529 }
7530 }
7531}
7532
7533}
7534
7535static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char* pUserProfileUrl)
7536{
7537 enum {
7538 PRE_INIT, // setup shared data in master process
7539 SECOND_INIT, // complete init. after fork
7540 FULL_INIT // do a standard complete init.
7541 } eStage;
7542
7543 // Did we do a pre-initialize
7544 static bool bPreInited = false;
7545 static bool bUnipoll = false;
7546 static bool bProfileZones = false;
7547 static bool bNotebookbar = false;
7548
7549 { // cf. string lifetime for preinit
7550 std::vector<OUString> aOpts;
7551
7552 // ':' delimited options - avoiding ABI change for new parameters
7553 const char *pOptions = getenv("SAL_LOK_OPTIONS");
7554 if (pOptions)
7555 aOpts = comphelper::string::split(OUString(pOptions, strlen(pOptions), RTL_TEXTENCODING_UTF8), ':');
7556 for (const auto &it : aOpts)
7557 {
7558 if (it == "unipoll")
7559 bUnipoll = true;
7560 else if (it == "profile_events")
7561 bProfileZones = true;
7562 else if (it == "sc_no_grid_bg")
7564 comphelper::LibreOfficeKit::Compat::scNoGridBackground);
7565 else if (it == "sc_print_twips_msgs")
7567 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
7568 else if (it == "notebookbar")
7569 bNotebookbar = true;
7570 }
7571 }
7572
7573 // What stage are we at ?
7574 if (pThis == nullptr)
7575 {
7576 eStage = PRE_INIT;
7578 {
7579 SAL_INFO("lok", "Create libreoffice object");
7580 gImpl = new LibLibreOffice_Impl();
7581 }
7582 }
7583 else if (bPreInited)
7584 eStage = SECOND_INIT;
7585 else
7586 eStage = FULL_INIT;
7587
7588 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
7589
7590 if (bInitialized)
7591 return 1;
7592
7593 // Turn profile zones on early
7594 if (bProfileZones && eStage == SECOND_INIT)
7595 {
7597 traceEventDumper = new TraceEventDumper();
7598 }
7599
7600 comphelper::ProfileZone aZone("lok-init");
7601
7602 if (eStage == PRE_INIT)
7603 {
7604 rtl_alloc_preInit(true);
7605
7606 // Set the default timezone to the TZ envar, if set.
7607 const char* tz = ::getenv("TZ");
7608 SfxLokHelper::setDefaultTimezone(!!tz, tz ? OStringToOUString(tz, RTL_TEXTENCODING_UTF8)
7609 : OUString());
7610 }
7611
7612 if (eStage != SECOND_INIT)
7614
7615 if (eStage != PRE_INIT)
7617
7618 if (pUserProfileUrl && eStage != PRE_INIT)
7619 {
7620 OUString url(
7621 pUserProfileUrl, strlen(pUserProfileUrl), RTL_TEXTENCODING_UTF8);
7622 OUString path;
7623 if (url.startsWithIgnoreAsciiCase("vnd.sun.star.pathname:", &path))
7624 {
7625 OUString url2;
7626 osl::FileBase::RC e = osl::FileBase::getFileURLFromSystemPath(
7627 path, url2);
7628 if (e == osl::FileBase::E_None)
7629 url = url2;
7630 else
7631 SAL_WARN("lok", "resolving <" << url << "> failed with " << +e);
7632 }
7633 rtl::Bootstrap::set("UserInstallation", url);
7634 if (eStage == SECOND_INIT)
7636 }
7637
7638 OUString aAppPath;
7639 if (pAppPath)
7640 {
7641 aAppPath = OUString(pAppPath, strlen(pAppPath), RTL_TEXTENCODING_UTF8);
7642 }
7643 else
7644 {
7645#if defined ANDROID || defined EMSCRIPTEN
7646 aAppPath = OUString::fromUtf8(lo_get_app_data_dir()) + "/program";
7647#else
7648 // Fun conversion dance back and forth between URLs and system paths...
7649 OUString aAppURL;
7650 ::osl::Module::getUrlFromAddress( reinterpret_cast< oslGenericFunction >(lo_initialize),
7651 aAppURL);
7652 osl::FileBase::getSystemPathFromFileURL( aAppURL, aAppPath );
7653#endif
7654
7655#ifdef IOS
7656 // The above gives something like
7657 // "/private/var/containers/Bundle/Application/953AA851-CC15-4C60-A2CB-C2C6F24E6F71/Foo.app/Foo",
7658 // and we want to drop the final component (the binary name).
7659 sal_Int32 lastSlash = aAppPath.lastIndexOf('/');
7660 assert(lastSlash > 0);
7661 aAppPath = aAppPath.copy(0, lastSlash);
7662#endif
7663 }
7664
7665 OUString aAppURL;
7666 if (osl::FileBase::getFileURLFromSystemPath(aAppPath, aAppURL) != osl::FileBase::E_None)
7667 return 0;
7668
7669#ifdef IOS
7670 // A LibreOffice-using iOS app should have the ICU data file in the app bundle. Initialize ICU
7671 // to use that.
7672 NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
7673
7674 int fd = open([[bundlePath stringByAppendingPathComponent:@"ICU.dat"] UTF8String], O_RDONLY);
7675 if (fd == -1)
7676 NSLog(@"Could not open ICU data file %s", [[bundlePath stringByAppendingPathComponent:@"ICU.dat"] UTF8String]);
7677 else
7678 {
7679 struct stat st;
7680 if (fstat(fd, &st) == -1)
7681 NSLog(@"fstat on ICU data file failed: %s", strerror(errno));
7682 else
7683 {
7684 void *icudata = mmap(0, (size_t) st.st_size, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
7685 if (icudata == MAP_FAILED)
7686 NSLog(@"mmap failed: %s", strerror(errno));
7687 else
7688 {
7689 UErrorCode icuStatus = U_ZERO_ERROR;
7690 udata_setCommonData(icudata, &icuStatus);
7691 if (U_FAILURE(icuStatus))
7692 NSLog(@"udata_setCommonData failed");
7693 else
7694 {
7695 // Quick test that ICU works...
7696 UConverter *cnv = ucnv_open("iso-8859-3", &icuStatus);
7697 if (U_SUCCESS(icuStatus))
7698 ucnv_close(cnv);
7699 else
7700 NSLog(@"ucnv_open() failed: %s", u_errorName(icuStatus));
7701 }
7702 }
7703 }
7704 close(fd);
7705 }
7706#endif
7707
7708 try
7709 {
7710 if (eStage != SECOND_INIT)
7711 {
7712 SAL_INFO("lok", "Attempting to initialize UNO");
7713
7714 if (!initialize_uno(aAppURL))
7715 return false;
7716
7717 // Force headless -- this is only for bitmap rendering.
7718 rtl::Bootstrap::set("SAL_USE_VCLPLUGIN", "svp");
7719
7720 // We specifically need to make sure we have the "headless"
7721 // command arg set (various code specifically checks via
7722 // CommandLineArgs):
7724
7725#ifdef IOS
7726 if (InitVCL() && [NSThread isMainThread])
7727 {
7728 static bool bFirstTime = true;
7729 if (bFirstTime)
7730 {
7732 bFirstTime = false;
7733 }
7734 }
7736#endif
7737
7738#if HAVE_FEATURE_ANDROID_LOK
7739 // Register the bundled extensions - so that the dictionaries work
7742 if (bFailed)
7743 SAL_INFO("lok", "CheckExtensionDependencies failed");
7744#endif
7745
7746 if (eStage == PRE_INIT)
7747 {
7748 {
7749 comphelper::ProfileZone aInit("Init vcl");
7750 std::cerr << "Init vcl\n";
7751 InitVCL();
7752 }
7753
7754 // pre-load all component libraries.
7755 if (!xContext.is())
7756 throw css::uno::DeploymentException("preInit: XComponentContext is not created");
7757
7758 css::uno::Reference< css::uno::XInterface > xService;
7759 xContext->getValueByName("/singletons/com.sun.star.lang.theServiceManager") >>= xService;
7760 if (!xService.is())
7761 throw css::uno::DeploymentException("preInit: XMultiComponentFactory is not created");
7762
7763 css::uno::Reference<css::lang::XInitialization> aService(
7764 xService, css::uno::UNO_QUERY_THROW);
7765
7766 // pre-requisites:
7767 // In order to load implementations and invoke
7768 // component factory it is required:
7769 // 1) defaultBootstrap_InitialComponentContext()
7770 // 2) comphelper::setProcessServiceFactory(xSFactory);
7771 // 3) InitVCL()
7772 {
7773 comphelper::ProfileZone aInit("preload");
7774 aService->initialize({css::uno::Any(OUString("preload"))});
7775 }
7776 { // Force load some modules
7777 comphelper::ProfileZone aInit("preload modules");
7780 }
7781
7782 preloadData();
7783
7784 // Release Solar Mutex, lo_startmain thread should acquire it.
7786 }
7787
7788 setLanguageAndLocale("en-US");
7789 }
7790
7791 if (eStage != PRE_INIT)
7792 {
7793 SAL_INFO("lok", "Re-initialize temp paths");
7794 SvtPathOptions aOptions;
7795 OUString aNewTemp;
7796 osl::FileBase::getTempDirURL(aNewTemp);
7797 aOptions.SetTempPath(aNewTemp);
7799
7800 // The RequestHandler is specifically set to be ready when all the other
7801 // init in Desktop::Main (run from soffice_main) is done. We can enable
7802 // the RequestHandler here (without starting any IPC thread;
7803 // shortcutting the invocation in Desktop::Main that would start the IPC
7804 // thread), and can then use it to wait until we're definitely ready to
7805 // continue.
7806
7807 SAL_INFO("lok", "Enabling RequestHandler");
7809 SAL_INFO("lok", "Starting soffice_main");
7811 if (!bUnipoll)
7812 {
7813 // Start the main thread only in non-unipoll mode (i.e. multithreaded).
7814 pLib->maThread = osl_createThread(lo_startmain, nullptr);
7815 SAL_INFO("lok", "Waiting for RequestHandler");
7817 SAL_INFO("lok", "RequestHandler ready -- continuing");
7818 }
7819 else
7820 InitVCL();
7821 }
7822
7823 if (eStage != SECOND_INIT)
7825
7826 SAL_INFO("lok", "LOK Initialized");
7827 if (eStage == PRE_INIT)
7828 bPreInited = true;
7829 else
7830 bInitialized = true;
7831 }
7832 catch (css::uno::Exception& exception)
7833 {
7834 fprintf(stderr, "Bootstrapping exception '%s'\n",
7835 OUStringToOString(exception.Message, RTL_TEXTENCODING_UTF8).getStr());
7836 }
7837
7838 if (eStage == PRE_INIT)
7839 {
7841 }
7842
7843// Turn off quick editing on iOS, Android and Emscripten
7844#if defined IOS || defined ANDROID || defined __EMSCRIPTEN__
7845 if (officecfg::Office::Impress::Misc::TextObject::QuickEditing::get())
7846 {
7847 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
7848 officecfg::Office::Impress::Misc::TextObject::QuickEditing::set(false, batch);
7849 batch->commit();
7850 }
7851#endif
7852
7853 setCertificateDir();
7854 setDeeplConfig();
7855 setLanguageToolConfig();
7856
7857 if (bNotebookbar)
7858 {
7859 activateNotebookbar(u"Writer");
7860 activateNotebookbar(u"Calc");
7861 activateNotebookbar(u"Impress");
7862 activateNotebookbar(u"Draw");
7863 }
7864
7865 // staticize all strings.
7866 if (eStage == PRE_INIT)
7867 rtl_alloc_preInit(false);
7868
7869 return bInitialized;
7870}
7871
7872SAL_JNI_EXPORT
7873LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user_profile_url)
7874{
7875 static bool alreadyCalled = false;
7876
7877 if ((!lok_preinit_2_called && !gImpl) || (lok_preinit_2_called && !alreadyCalled))
7878 {
7879 alreadyCalled = true;
7880
7882 {
7883 SAL_INFO("lok", "Create libreoffice object");
7884 gImpl = new LibLibreOffice_Impl();
7885 }
7886
7887 if (!lo_initialize(gImpl, install_path, user_profile_url))
7888 {
7890 }
7891 }
7892 return static_cast<LibreOfficeKit*>(gImpl);
7893}
7894
7895SAL_JNI_EXPORT
7896LibreOfficeKit *libreofficekit_hook(const char* install_path)
7897{
7898 return libreofficekit_hook_2(install_path, nullptr);
7899}
7900
7901SAL_JNI_EXPORT
7902int lok_preinit(const char* install_path, const char* user_profile_url)
7903{
7904 return lo_initialize(nullptr, install_path, user_profile_url);
7905}
7906
7907SAL_JNI_EXPORT
7908int lok_preinit_2(const char* install_path, const char* user_profile_url, LibreOfficeKit** kit)
7909{
7910 lok_preinit_2_called = true;
7911 int result = lo_initialize(nullptr, install_path, user_profile_url);
7912 if (kit != nullptr)
7913 *kit = gImpl;
7914 return result;
7915}
7916
7917static void lo_destroy(LibreOfficeKit* pThis)
7918{
7920
7921 LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
7922 gImpl = nullptr;
7923
7924 SAL_INFO("lok", "LO Destroy");
7925
7927 uno::Reference <frame::XDesktop2> xDesktop = frame::Desktop::create ( ::comphelper::getProcessComponentContext() );
7928 // FIXME: the terminate() call here is a no-op because it detects
7929 // that LibreOfficeKit::isActive() and then returns early!
7930 bool bSuccess = xDesktop.is() && xDesktop->terminate();
7931
7932 if (!bSuccess)
7933 {
7934 bSuccess = GetpApp() && GetpApp()->QueryExit();
7935 }
7936
7937 if (!bSuccess)
7938 {
7940 }
7941
7942 aGuard.clear();
7943
7944 osl_joinWithThread(pLib->maThread);
7945 osl_destroyThread(pLib->maThread);
7946
7947 delete pLib;
7948 bInitialized = false;
7949 SAL_INFO("lok", "LO Destroy Done");
7950}
7951
7952} // extern "C"
7953
7954/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const short REDO
const short UNDO
DrawTextFlags
OptionalString sType
GestureEventPanType
constexpr sal_Int8 header[]
constexpr tools::Long MINBODY
sal_uInt8 * Scanline
PropertyValueVector_t aPropertyValues
#define COMPLEX
#define ASIAN
const char * pName
AnyEventRef aEvent
const LanguageTag & GetLanguageTag() const
const LanguageTag & GetUILanguageTag() const
static void SetDialogCancelMode(DialogCancelMode mode)
LibreOfficeKitCallback m_pCallback
static ImplSVEvent * PostKeyEvent(VclEventId nEvent, vcl::Window *pWin, KeyEvent const *pKeyEvent)
static OutputDevice * GetDefaultDevice()
static ImplSVEvent * PostGestureEvent(VclEventId nEvent, vcl::Window *pWin, GestureEventPan const *pGestureEvent)
static void UpdateMainThread()
virtual bool QueryExit()
static const AllSettings & GetSettings()
static comphelper::SolarMutex & GetSolarMutex()
static sal_uInt32 ReleaseSolarMutex()
static void Quit()
static ImplSVEvent * PostMouseEvent(VclEventId nEvent, vcl::Window *pWin, MouseEvent const *pMouseEvent)
void * m_pCallbackData
const AlphaMask & GetAlphaMask() const
Bitmap GetBitmap(Color aTransparentReplaceColor) const
static void RegisterDisplay(BasicDisplayErrorFunc *)
size_t GetFontNameCount() const
static const FontMetric & GetFontMetric(sal_Handle hFontMetric)
static const int * GetStdSizeAry()
sal_Handle GetFirstFontMetric(std::u16string_view rName) const
const FontMetric & GetFontName(size_t nFont) const
virtual void Start(bool bStartTimer=true) override
VCL_DLLPUBLIC OUString getImageUrl(OUString const &name, OUString const &style, OUString const &lang)
static VCL_DLLPUBLIC ImageTree & get()
static rtl::Reference< LOKClipboard > getClipboardForCurView()
Fetch clipboard from the global pool.
static void releaseClipboardForView(int nViewId)
Release a clipboard before its document dies, nViewId of -1 clears all.
A clipboard implementation for LibreOfficeKit.
InteractionHandler is an interface that provides the user with various dialogs / error messages.
Represents the contents of LOKClipboard.
LanguageType getLanguageType(bool bResolveSystem=true) const
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
const OUString & getBcp47(bool bResolveSystem=true) const
bool isValidBcp47() const
static OUString convertToBcp47(LanguageType nLangID)
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
vcl::Window * GetWindow()
vcl::Window * GetGraphicWindow()
void SetOrigin(const Point &rOrigin)
static LanguageType resolveSystemLanguageByScriptType(LanguageType nLang, sal_Int16 nType)
static FontMappingUseData FinishTrackingFontMappingUse()
static void ImplClearAllFontData(bool bNewFontLists)
bool AddTempDevFont(const OUString &rFileURL, const OUString &rFontName)
static void ImplRefreshAllFontData(bool bNewFontLists)
static void StartTrackingFontMappingUse()
static vcl::Font GetDefaultFont(DefaultFontType nType, LanguageType eLang, GetDefaultFontFlags nFlags, const OutputDevice *pOutDev=nullptr)
void Move(tools::Long nHorzMove, tools::Long nVertMove)
const SdrOutliner * GetTextEditOutliner() const
static SfxApplication * GetOrCreate()
SfxObjectShell * GetObjectShell() const
css::uno::Reference< css::frame::XDispatch > GetDispatch(const SfxSlot *, const css::util::URL &aURL, bool bMasterCommand)
SfxDispatcher * GetDispatcher() const
vcl::Window * GetWindow() const
const SfxPoolItem * ExecuteList(sal_uInt16 nSlot, SfxCallMode nCall, std::initializer_list< SfxPoolItem const * > args, std::initializer_list< SfxPoolItem const * > internalargs=std::initializer_list< SfxPoolItem const * >())
SfxItemState QueryState(sal_uInt16 nSID, const SfxPoolItem *&rpState)
const css::uno::Reference< css::frame::XFrame > & GetFrameInterface() const
static void setBlockedCommandList(int nViewId, const char *blockedCommandList)
static void setView(int nId)
static std::size_t getViewsCount(int nDocId)
static void postKeyEventAsync(const VclPtr< vcl::Window > &xWindow, int nType, int nCharCode, int nKeyCode, int nRepeat=0)
static int createView()
static void setViewTimezone(int nId, bool isSet, const OUString &rTimezone)
static void destroyView(int nId)
static const tools::Long MaxTwips
static void setDefaultTimezone(bool isSet, const OUString &rTimezone)
static void setViewLocale(int nId, const OUString &rBcp47LanguageTag)
static void setDeviceFormFactor(std::u16string_view rDeviceFormFactor)
static bool getViewIds(int nDocId, int *pArray, size_t nSize)
static void postExtTextEventAsync(const VclPtr< vcl::Window > &xWindow, int nType, const OUString &rText)
static void setDefaultLanguage(const OUString &rBcp47LanguageTag)
static std::unordered_map< OUString, css::uno::Reference< com::sun::star::ui::XAcceleratorConfiguration > > & getAcceleratorConfs()
static void setLoadLanguage(const OUString &rBcp47LanguageTag)
static void setAccessibilityState(int nId, bool nEnabled)
static int getView(const SfxViewShell *pViewShell=nullptr)
static void setViewLanguage(int nId, const OUString &rBcp47LanguageTag)
static void setEditMode(int nMode, vcl::ITiledRenderable *pDoc)
static void dumpState(rtl::OStringBuffer &rState)
const std::shared_ptr< const SfxFilter > & GetFilter() const
void RecheckSignature(bool bAlsoRecheckScriptingSignature)
bool SignDocumentContentUsingCertificate(const css::uno::Reference< css::security::XCertificate > &xCertificate)
bool IsModified() const
SfxMedium * GetMedium() const
SignatureState GetDocumentSignatureState()
static SAL_WARN_UNUSED_RESULT SfxObjectShell * Current()
const SfxPoolItem * GetItem(sal_uInt16 nSlotId) const
virtual SfxUndoManager * GetUndoManager()
SfxDispatcher * GetDispatcher() const
static SfxSlotPool & GetSlotPool(SfxViewFrame *pFrame=nullptr)
const SfxSlot * GetUnoSlot(const OUString &rUnoName) const
OUString GetUndoActionsInfo() const
OUString GetRedoActionsInfo() const
static SAL_WARN_UNUSED_RESULT SfxViewFrame * Current()
SfxBindings & GetBindings()
void SetChildWindow(sal_uInt16 nId, bool bVisible, bool bSetFocus=true)
SfxChildWindow * GetChildWindow(sal_uInt16)
SfxFrame & GetFrame() const
void ShowChildWindow(sal_uInt16, bool bVisible=true)
ViewShellId GetViewShellId() const override
SfxViewFrame & GetViewFrame() const
static SAL_WARN_UNUSED_RESULT SfxViewShell * GetNext(const SfxViewShell &rPrev, bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
virtual int getEditMode() const
static SAL_WARN_UNUSED_RESULT SfxViewShell * GetFirst(bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
int getA11yCaretPosition() const
void setLibreOfficeKitViewCallback(SfxLokCallbackInterface *pCallback)
virtual std::optional< OString > getLOKPayload(int nType, int nViewId) const
static SAL_WARN_UNUSED_RESULT SfxViewShell * Current()
virtual SdrView * GetDrawView() const
static void SetCurrentDocId(ViewShellDocId nId)
OUString getA11yFocusedParagraph() const
virtual int getPart() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
const SubsetVec & GetSubsetMap() const
const void * GetData()
std::size_t GetEndOfData() const
static void resetTheCurrencyTable()
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
static OUString GetLanguageString(const LanguageType eType)
static bool HasLanguageType(const LanguageType eType)
static LanguageType GetLanguageType(std::u16string_view rStr)
void SetTempPath(const OUString &rPath)
void SetLocaleConfigString(const OUString &rStr)
void SetUILocaleConfigString(const OUString &rStr)
const FontList * GetFontList() const
virtual SvxLongLRSpaceItem * Clone(SfxItemPool *pPool=nullptr) const override
tools::Long GetRight() const
void SetLeft(tools::Long lArgLeft)
tools::Long GetLeft() const
void SetRight(tools::Long lArgRight)
tools::Long GetLower() const
void SetLower(tools::Long lArgRight)
tools::Long GetUpper() const
virtual SvxLongULSpaceItem * Clone(SfxItemPool *pPool=nullptr) const override
void SetUpper(tools::Long lArgLeft)
virtual SvxSizeItem * Clone(SfxItemPool *pPool=nullptr) const override
bool IsActive() const
void SetPriority(TaskPriority ePriority)
void Stop()
void SetTimeout(sal_uInt64 nTimeoutMs)
virtual void Start(bool bStartTimer=true) override
virtual void Invoke() override
static VclAbstractDialogFactory * Create()
reference_type * get() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
void expand(const Tuple2D< TYPE > &rTuple)
TYPE getHeight() const
static void encode(OUStringBuffer &aStrBuffer, const css::uno::Sequence< sal_Int8 > &aPass)
static void decode(css::uno::Sequence< sal_Int8 > &aPass, std::u16string_view sBuffer)
static std::shared_ptr< ConfigurationChanges > create()
css::uno::Sequence< css::beans::PropertyValue > getAsConstPropertyValueList() const
static SolarMutex * get()
sal_uInt32 release(bool bUnlockAll=false)
void acquire(sal_uInt32 nLockCount=1)
virtual bool tryToAcquire()
static ThreadPool & getSharedOptimalPool()
static void setBufferSizeAndCallback(std::size_t bufferSize, void(*bufferFullCallback)())
static void stopRecording()
static css::uno::Sequence< OUString > getRecordingAndClear()
static void startRecording()
css::uno::Type const & get()
TimeoutIdle(CallbackFlushHandler *handler)
Definition: init.cxx:1524
virtual void Invoke() override
Definition: init.cxx:1534
One instance of this per view, handles flushing callbacks.
Definition: init.hxx:97
LibreOfficeKitDocument * m_pDocument
Definition: init.hxx:230
virtual void libreOfficeKitViewAddPendingInvalidateTiles() override
Definition: init.cxx:1682
bool removeAll(int type)
Definition: init.cxx:2468
virtual void dumpState(rtl::OStringBuffer &rState) override
Definition: init.cxx:1665
void resetUpdatedTypePerViewId(int nType, int nViewId)
Definition: init.cxx:1611
std::unordered_map< OString, OString > m_lastStateChange
Definition: init.hxx:208
std::unordered_map< int, std::unordered_map< int, OString > > m_viewStates
Definition: init.hxx:209
void resetUpdatedType(int nType)
Definition: init.cxx:1595
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle *pRect, int nPart, int nMode) override
Definition: init.cxx:1643
virtual void Invoke() override
Definition: init.cxx:2348
std::map< int, OString > m_states
Definition: init.hxx:207
void setUpdatedType(int nType, bool value)
Definition: init.cxx:1585
std::vector< bool > m_updatedTypes
Definition: init.hxx:221
virtual void libreOfficeKitViewCallbackWithViewId(int nType, const OString &pPayload, int nViewId) override
Definition: init.cxx:1637
virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) override
Definition: init.cxx:1657
void removeViewStates(int viewId)
Definition: init.cxx:2515
bool callbacksDisabled() const
Returns true iff callbacks are disabled.
Definition: init.hxx:112
CallbackFlushHandler(LibreOfficeKitDocument *pDocument, LibreOfficeKitCallback pCallback, void *pData)
Definition: init.cxx:1540
queue_type2::iterator toQueue2(queue_type1::iterator)
void enqueueUpdatedType(int type, const SfxViewShell *sourceViewShell, int viewId)
Definition: init.cxx:2331
boost::container::flat_map< int, std::vector< PerViewIdData > > m_updatedTypesPerViewId
Definition: init.hxx:228
virtual void libreOfficeKitViewUpdatedCallback(int nType) override
Definition: init.cxx:1649
virtual ~CallbackFlushHandler() override
Definition: init.cxx:1568
LibreOfficeKitCallback m_pCallback
Definition: init.hxx:232
bool processInvalidateTilesEvent(int type, CallbackData &aCallbackData)
Definition: init.cxx:1973
std::recursive_mutex m_mutex
Definition: init.hxx:235
queue_type1 m_queue1
we frequently want to scan the queue, and mostly when we do so, we only care about the element type s...
Definition: init.hxx:205
void addViewStates(int viewId)
Definition: init.cxx:2506
void setUpdatedTypePerViewId(int nType, int nViewId, int nSourceViewId, bool value)
Definition: init.cxx:1600
bool processWindowEvent(int type, CallbackData &aCallbackData)
Definition: init.cxx:2095
void queue(const int type, const OString &data)
Definition: init.cxx:1688
virtual void libreOfficeKitViewCallback(int nType, const OString &pPayload) override
Definition: init.cxx:1631
static bool CheckExtensionDependencies()
static void SynchronizeExtensionRepositories(bool bCleanedExtensionCache, Desktop *pDesktop=nullptr)
static CommandLineArgs & GetCommandLineArgs()
Definition: app.cxx:393
static void CreateTemporaryDirectory()
Definition: appinit.cxx:227
static Status Enable(bool ipc)
static void SetReady(bool bIsReady)
bool signDocument(css::uno::Reference< css::security::XCertificate > const &rxCertificate)
static css::uno::Reference< css::ui::XAcceleratorConfiguration > lok_createNewAcceleratorConfiguration(const css::uno::Reference< css::uno::XComponentContext > &rxContext, OUString sModule)
void put(std::u16string_view pPropName, const OUString &rPropValue)
ScopedJsonWriterStruct startStruct()
OString finishAndGetAsOString()
ScopedJsonWriterNode startNode(std::string_view)
ScopedJsonWriterArray startArray(std::string_view)
bool Contains(const Point &rPOINT) const
tools::Rectangle GetIntersection(const tools::Rectangle &rRect) const
constexpr tools::Long Top() const
tools::Long getOpenHeight() const
constexpr tools::Long Right() const
tools::Rectangle & Union(const tools::Rectangle &rRect)
tools::Long getOpenWidth() const
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr bool IsEmpty() const
rtl::OString toString() const
static void reloadData()
void EnableKillingFile(bool bEnable=true)
OUString const & GetURL() const
const OUString & GetFamilyName() const
static VclPtr< vcl::Window > FindLOKWindow(vcl::LOKWindowId nWindowId)
constexpr ::Color COL_LIGHTRED(0xFF, 0x00, 0x00)
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
Any value
#define SAL_CONFIGFILE(name)
int nCount
OString exceptionToString(const css::uno::Any &caught)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define TOOLS_INFO_EXCEPTION(area, stream)
SVXCORE_DLLPUBLIC OUString SvxResId(TranslateId aId)
URL aURL
bool close
float u
float y
float x
sal_Int32 nState
Reference< XInterface > xTarget
std::deque< AttacherIndex_Impl > aIndex
OUString sName
const char * name
const sal_uInt16 idx[]
static int doc_getSignatureState(LibreOfficeKitDocument *pThis)
Definition: init.cxx:6837
static char * lo_extractRequest(LibreOfficeKit *pThis, const char *pFilePath)
Definition: init.cxx:3089
SAL_JNI_EXPORT LibreOfficeKit * libreofficekit_hook_2(const char *install_path, const char *user_profile_url)
Definition: init.cxx:7873
static void lo_destroy(LibreOfficeKit *pThis)
Definition: init.cxx:7917
static void doc_destroyView(LibreOfficeKitDocument *pThis, int nId)
static char * getPostIts(LibreOfficeKitDocument *pThis)
Returns the JSON representation of all the comments in the document.
Definition: init.cxx:4387
static bool lo_signDocument(LibreOfficeKit *pThis, const char *pUrl, const unsigned char *pCertificateBinary, const int nCertificateBinarySize, const unsigned char *pPrivateKeyBinary, const int nPrivateKeyBinarySize)
Definition: init.cxx:3020
static OUString getUString(const char *pString)
Definition: init.cxx:356
static int doc_getViewsCount(LibreOfficeKitDocument *pThis)
static int lo_initialize(LibreOfficeKit *pThis, const char *pInstallPath, const char *pUserProfilePath)
Definition: init.cxx:7535
static int doc_getA11yCaretPosition(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3821
static void doc_paintWindowForView(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, unsigned char *pBuffer, const int nX, const int nY, const int nWidth, const int nHeight, const double fDPIScale, int viewId)
Definition: init.cxx:6587
static int doc_getPart(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3698
static void lo_setOption(LibreOfficeKit *pThis, const char *pOption, const char *pValue)
Definition: init.cxx:4744
static char * getLanguages(LibreOfficeKitDocument *pThis, const char *pCommand)
Definition: init.cxx:5763
static LibLibreOffice_Impl * gImpl
Definition: init.cxx:230
static LibreOfficeKitDocument * lo_documentLoadWithOptions(LibreOfficeKit *pThis, const char *pURL, const char *pOptions)
Definition: init.cxx:2651
const ExtensionMap aWriterExtensionMap[]
Definition: init.cxx:289
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2642
static bool isUpdatedType(int type)
Definition: init.cxx:733
static void doc_postWindowMouseEvent(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
Definition: init.cxx:5062
static bool encodeImageAsHTML(const css::uno::Reference< css::datatransfer::XTransferable > &xTransferable, const OString &aMimeType, OString &aRet)
Definition: init.cxx:5180
static void doc_setView(LibreOfficeKitDocument *pThis, int nId)
SAL_JNI_EXPORT int lok_preinit(const char *install_path, const char *user_profile_url)
Definition: init.cxx:7902
static void doc_resizeWindow(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, const int nWidth, const int nHeight)
Definition: init.cxx:6861
SAL_JNI_EXPORT LibreOfficeKit * libreofficekit_hook(const char *install_path)
Definition: init.cxx:7896
static int doc_getTileMode(LibreOfficeKitDocument *pThis)
static void doc_sendFormFieldEvent(LibreOfficeKitDocument *pThis, const char *pArguments)
Definition: init.cxx:6894
static char * convertOUString(std::u16string_view aStr)
Definition: init.cxx:374
static void doc_registerCallback(LibreOfficeKitDocument *pThis, LibreOfficeKitCallback pCallback, void *pData)
Definition: init.cxx:4306
static void doc_setViewLanguage(LibreOfficeKitDocument *pThis, int nId, const char *language)
static void doc_sendContentControlEvent(LibreOfficeKitDocument *pThis, const char *pArguments)
Definition: init.cxx:6970
static void doc_postWindowKeyEvent(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, int nType, int nCharCode, int nKeyCode)
Definition: init.cxx:4546
static void aBasicErrorFunc(const OUString &rError, const OUString &rAction)
Definition: init.cxx:7125
static int doc_getSelectionType(LibreOfficeKitDocument *pThis)
Definition: init.cxx:5342
static void doc_setGraphicSelection(LibreOfficeKitDocument *pThis, int nType, int nX, int nY)
Definition: init.cxx:5603
static void doc_setPartImpl(LibreOfficeKitDocument *pThis, int nPart, bool bAllowChangeFocus=true)
Definition: init.cxx:3715
static int lo_runMacro(LibreOfficeKit *pThis, const char *pURL)
Definition: init.cxx:2933
static void lo_sendDialogEvent(LibreOfficeKit *pThis, unsigned long long int nLOKWindowId, const char *pArguments)
Definition: init.cxx:4739
static void doc_postUnoCommand(LibreOfficeKitDocument *pThis, const char *pCommand, const char *pArguments, bool bNotifyWhenFinished)
Definition: init.cxx:4832
static char * getRulerState(LibreOfficeKitDocument *pThis)
Definition: init.cxx:4416
static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent, const char *pText)
Definition: init.cxx:7217
static char * doc_getPartName(LibreOfficeKitDocument *pThis, int nPart)
Definition: init.cxx:3841
static int doc_getEditMode(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3914
const ExtensionMap aDrawExtensionMap[]
Definition: init.cxx:344
static void lo_registerCallback(LibreOfficeKit *pThis, LibreOfficeKitCallback pCallback, void *pData)
Definition: init.cxx:3159
static std::weak_ptr< LibreOfficeKitClass > gOfficeClass
Definition: init.cxx:232
static void lo_runLoop(LibreOfficeKit *pThis, LibreOfficeKitPollCallback pPollCallback, LibreOfficeKitWakeCallback pWakeCallback, void *pData)
Definition: init.cxx:7193
static void doc_setPart(LibreOfficeKitDocument *pThis, int nPart)
Definition: init.cxx:3732
static int doc_getDocumentType(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3674
static bool doc_insertCertificate(LibreOfficeKitDocument *pThis, const unsigned char *pCertificateBinary, const int nCertificateBinarySize, const unsigned char *pPrivateKeyBinary, const int nPrivateKeyBinarySize)
Definition: init.cxx:6706
static void getDocLanguages(LibreOfficeKitDocument *pThis, uno::Sequence< lang::Locale > &rSeq)
Definition: init.cxx:5620
static char * lo_getFilterTypes(LibreOfficeKit *pThis)
Definition: init.cxx:7041
static bool encodeTextAsHTML(const css::uno::Reference< css::datatransfer::XTransferable > &xTransferable, const OString &aMimeType, OString &aRet)
Definition: init.cxx:5206
static void doc_selectPart(LibreOfficeKitDocument *pThis, int nPart, int nSelect)
Definition: init.cxx:3752
static char * doc_getA11yFocusedParagraph(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3801
static uno::Reference< css::lang::XMultiServiceFactory > xSFactory
Definition: init.cxx:2643
static TraceEventDumper * traceEventDumper
Definition: init.cxx:287
static bool lok_preinit_2_called
Definition: init.cxx:231
static char * getStyles(LibreOfficeKitDocument *pThis, const char *pCommand)
Definition: init.cxx:5890
static unsigned char * doc_renderFont(LibreOfficeKitDocument *pThis, const char *pFontName, const char *pChar, int *pFontWidth, int *pFontHeight)
Definition: init.cxx:6472
static void doc_setBlockedCommandList(LibreOfficeKitDocument *pThis, int nViewId, const char *blockedCommandList)
Definition: init.cxx:4455
static char * getTrackedChangeAuthors(LibreOfficeKitDocument *pThis)
Returns the JSON representation of the redline author table.
Definition: init.cxx:6107
static void doc_destroy(LibreOfficeKitDocument *pThis)
Definition: init.cxx:2521
static void doc_paintWindowDPI(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, unsigned char *pBuffer, const int nX, const int nY, const int nWidth, const int nHeight, const double fDPIScale)
Definition: init.cxx:6578
static void lo_setDocumentPassword(LibreOfficeKit *pThis, const char *pURL, const char *pPassword)
Definition: init.cxx:7097
static void doc_postKeyEvent(LibreOfficeKitDocument *pThis, int nType, int nCharCode, int nKeyCode)
Definition: init.cxx:4430
static void doc_setWindowTextSelection(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, bool swap, int nX, int nY)
Definition: init.cxx:5151
static int doc_getSelectionTypeAndText(LibreOfficeKitDocument *pThis, const char *pMimeType, char **pText, char **pUsedMimeType)
Definition: init.cxx:5378
static char * doc_getPartHash(LibreOfficeKitDocument *pThis, int nPart)
Definition: init.cxx:3858
static void doc_paintTile(LibreOfficeKitDocument *pThis, unsigned char *pBuffer, const int nCanvasWidth, const int nCanvasHeight, const int nTilePosX, const int nTilePosY, const int nTileWidth, const int nTileHeight)
Definition: init.cxx:3931
static void doc_resetSelection(LibreOfficeKitDocument *pThis)
Definition: init.cxx:5746
static int doc_getParts(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3682
static int doc_createView(LibreOfficeKitDocument *pThis)
Definition: init.cxx:6396
static void extractLinks(const uno::Reference< container::XNameAccess > &xLinks, bool subcontent, tools::JsonWriter &aJson)
Definition: init.cxx:413
static char * lo_getVersionInfo(LibreOfficeKit *pThis)
static char * doc_getTextSelection(LibreOfficeKitDocument *pThis, const char *pMimeType, char **pUsedMimeType)
Definition: init.cxx:5301
static void doc_postMouseEvent(LibreOfficeKitDocument *pThis, int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
Definition: init.cxx:5038
SAL_JNI_EXPORT int lok_preinit_2(const char *install_path, const char *user_profile_url, LibreOfficeKit **kit)
Definition: init.cxx:7908
static void doc_getDataArea(LibreOfficeKitDocument *pThis, long nTab, long *pCol, long *pRow)
Definition: init.cxx:4266
const ExtensionMap aImpressExtensionMap[]
Definition: init.cxx:324
static void doc_setClientZoom(LibreOfficeKitDocument *pThis, int nTilePixelWidth, int nTilePixelHeight, int nTileTwipWidth, int nTileTwipHeight)
Definition: init.cxx:6308
static void doc_postWindow(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, int nAction, const char *pData)
Definition: init.cxx:6656
static bool bInitialized
Definition: init.cxx:7215
static char * lo_getError(LibreOfficeKit *pThis)
Definition: init.cxx:7026
static void doc_setTextSelection(LibreOfficeKitDocument *pThis, int nType, int nX, int nY)
Definition: init.cxx:5134
static void lo_freeError(char *pFree)
Definition: init.cxx:7036
static int doc_createViewWithOptions(LibreOfficeKitDocument *pThis, const char *pOptions)
Definition: init.cxx:6361
static void preLoadShortCutAccelerators()
Used by preloadData (LibreOfficeKit) for providing different shortcuts for different languages.
Definition: init.cxx:7240
static char * convertOString(const OString &rStr)
Definition: init.cxx:366
static void doc_setPartMode(LibreOfficeKitDocument *pThis, int nPartMode)
Definition: init.cxx:3875
static std::weak_ptr< LibreOfficeKitDocumentClass > gDocumentClass
Definition: init.cxx:233
static int doc_setClipboard(LibreOfficeKitDocument *pThis, const size_t nInCount, const char **pInMimeTypes, const size_t *pInSizes, const char **pInStreams)
Definition: init.cxx:5532
static void doc_setClientVisibleArea(LibreOfficeKitDocument *pThis, int nX, int nY, int nWidth, int nHeight)
Definition: init.cxx:6326
static bool doc_getViewIds(LibreOfficeKitDocument *pThis, int *pArray, size_t nSize)
static void lo_startmain(void *)
Definition: init.cxx:7178
static void doc_setAccessibilityState(LibreOfficeKitDocument *pThis, int nId, bool bEnabled)
static void doc_completeFunction(LibreOfficeKitDocument *pThis, const char *)
Definition: init.cxx:6878
static void lo_setOptionalFeatures(LibreOfficeKit *pThis, unsigned long long features)
Definition: init.cxx:7078
static uno::Reference< css::lang::XMultiComponentFactory > xFactory
Definition: init.cxx:2644
static void lo_trimMemory(LibreOfficeKit *pThis, int nTarget)
Definition: init.cxx:3148
static int lcl_getViewId(std::string_view payload)
Definition: init.cxx:759
static OUString getAbsoluteURL(const char *pURL)
Try to convert a relative URL to an absolute one, unless it already looks like a URL.
Definition: init.cxx:380
const ExtensionMap aCalcExtensionMap[]
Definition: init.cxx:308
static char * getPostItsPos(LibreOfficeKitDocument *pThis)
Returns the JSON representation of the positions of all the comments in the document.
Definition: init.cxx:4402
static void lo_dumpState(LibreOfficeKit *pThis, const char *pOptions, char **pState)
Definition: init.cxx:4797
static LibreOfficeKitDocument * lo_documentLoad(LibreOfficeKit *pThis, const char *pURL)
Definition: init.cxx:2646
static void doc_moveSelectedParts(LibreOfficeKitDocument *pThis, int nPosition, bool bDuplicate)
Definition: init.cxx:3768
static char * doc_getPartPageRectangles(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3784
static OUString getGenerator()
Definition: init.cxx:1513
static bool lcl_isViewCallbackType(const int type)
Definition: init.cxx:717
static int doc_getView(LibreOfficeKitDocument *pThis)
static char * doc_getCommandValues(LibreOfficeKitDocument *pThis, const char *pCommand)
Definition: init.cxx:6120
static int doc_getClipboard(LibreOfficeKitDocument *pThis, const char **pMimeTypes, size_t *pOutCount, char ***pOutMimeTypes, size_t **pOutSizes, char ***pOutStreams)
Definition: init.cxx:5434
static bool isUpdatedTypePerViewId(int type)
Definition: init.cxx:746
static bool initialize_uno(const OUString &aAppProgramURL)
Definition: init.cxx:7135
static void doc_setViewTimezone(LibreOfficeKitDocument *pThis, int nId, const char *timezone)
static void SetLastExceptionMsg(const OUString &s=OUString())
Definition: init.cxx:235
static void doc_setOutlineState(LibreOfficeKitDocument *pThis, bool bColumn, int nLevel, int nIndex, bool bHidden)
Definition: init.cxx:6344
static void doc_postWindowGestureEvent(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, const char *pType, int nX, int nY, int nOffset)
Definition: init.cxx:5099
static char * getTrackedChanges(LibreOfficeKitDocument *pThis)
Returns the JSON representation of the redline stack.
Definition: init.cxx:6050
static char * getFontSubset(std::string_view aFontName)
Definition: init.cxx:5855
static size_t doc_renderShapeSelection(LibreOfficeKitDocument *pThis, char **pOutput)
Definition: init.cxx:4576
static bool doc_paste(LibreOfficeKitDocument *pThis, const char *pMimeType, const char *pData, size_t nSize)
Definition: init.cxx:5573
static void doc_getDocumentSize(LibreOfficeKitDocument *pThis, long *pWidth, long *pHeight)
Definition: init.cxx:4244
static char * getUndoOrRedo(LibreOfficeKitDocument *pThis, UndoOrRedo eCommand)
Returns the JSON representation of either an undo or a redo stack.
Definition: init.cxx:6024
static char * getFonts(const char *pCommand)
Definition: init.cxx:5814
static void doc_iniUnoCommands()
Initialize UNO commands, in the sense that from now on, the LOK client gets updates for status change...
Definition: init.cxx:3401
static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument *pThis, unsigned nWindowId, int nType, const char *pText)
Definition: init.cxx:4461
static void doc_initializeForRendering(LibreOfficeKitDocument *pThis, const char *pArguments)
Definition: init.cxx:4289
static int doc_saveAs(LibreOfficeKitDocument *pThis, const char *pUrl, const char *pFormat, const char *pFilterOptions)
Definition: init.cxx:3175
static void preloadData()
Used only by LibreOfficeKit when used by Online to pre-initialize.
Definition: init.cxx:7281
static void doc_paintWindow(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, unsigned char *pBuffer, const int nX, const int nY, const int nWidth, const int nHeight)
Definition: init.cxx:6570
static unsigned char * doc_renderFontOrientation(LibreOfficeKitDocument *pThis, const char *pFontName, const char *pChar, int *pFontWidth, int *pFontHeight, int pOrientation)
static void lcl_sendDialogEvent(unsigned long long int nWindowId, const char *pArguments)
Definition: init.cxx:4697
static char * doc_getPartInfo(LibreOfficeKitDocument *pThis, int nPart)
Definition: init.cxx:3737
static bool doc_addCertificate(LibreOfficeKitDocument *pThis, const unsigned char *pCertificateBinary, const int nCertificateBinarySize)
Definition: init.cxx:6779
static bool doc_renderSearchResult(LibreOfficeKitDocument *pThis, const char *pSearchResult, unsigned char **pBitmapBuffer, int *pWidth, int *pHeight, size_t *pByteSize)
Definition: init.cxx:6920
static void doc_removeTextContext(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, int nCharBefore, int nCharAfter)
Definition: init.cxx:4491
static void unoAnyToJson(tools::JsonWriter &rJson, std::string_view pNodeName, const uno::Any &anyItem)
Definition: init.cxx:485
static bool getFromTransferable(const css::uno::Reference< css::datatransfer::XTransferable > &xTransferable, const OString &aInMimeType, OString &aRet)
Definition: init.cxx:5224
static void doc_paintPartTile(LibreOfficeKitDocument *pThis, unsigned char *pBuffer, const int nPart, const int nMode, const int nCanvasWidth, const int nCanvasHeight, const int nTilePosX, const int nTilePosY, const int nTileWidth, const int nTileHeight)
Definition: init.cxx:4052
static void doc_sendDialogEvent(LibreOfficeKitDocument *pThis, unsigned long long int nLOKWindowId, const char *pArguments)
Definition: init.cxx:4734
Sequence< PropertyValue > aArguments
sal_Int32 nIndex
OUString aName
void * p
constexpr sal_uInt16 KEY_MOD2
constexpr sal_uInt16 KEY_MOD1
constexpr sal_uInt16 KEY_PASTE
constexpr sal_uInt16 KEY_SHIFT
#define LANGUAGE_SYSTEM
#define LANGUAGE_DONTKNOW
#define LANGUAGE_ENGLISH_US
SvtScriptType
Sequence< sal_Int8 > aSeq
const char * pLib
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
DateTime now
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
aStr
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
SvtScriptType GetScriptTypeOfLanguage(LanguageType nLang)
void SetMacroSecurityLevel(sal_Int32 _nLevel)
OUString ExpandVariables(const OUString &rString)
void setCompatFlag(Compat flag)
void setDialogPainting(bool bDialogPainting)
bool isAllowlistedLanguage(const OUString &lang)
void setRangeHeaders(bool bTiledAnnotations)
void setPartInInvalidation(bool bPartInInvalidation)
void setLocale(const LanguageTag &languageTag)
void setTiledAnnotations(bool bTiledAnnotations)
void setLanguageTag(const LanguageTag &languageTag)
void setStatusIndicatorCallback(void(*callback)(void *data, statusIndicatorCallbackType type, int percent, const char *pText), void *data)
void setActive(bool bActive)
void setViewIdForVisCursorInvalidation(bool bViewIdForVisCursorInvalidation)
void setDPIScale(double fDPIScale)
OUString convertCommaSeparated(uno::Sequence< OUString > const &i_rSeq)
std::vector< OUString > split(std::u16string_view rStr, sal_Unicode cSeparator)
void setProcessServiceFactory(const Reference< XMultiServiceFactory > &xSMgr)
bool dispatchCommand(const OUString &rCommand, const uno::Reference< css::frame::XFrame > &rFrame, const css::uno::Sequence< css::beans::PropertyValue > &rArguments, const uno::Reference< css::frame::XDispatchResultListener > &rListener)
Reference< XMultiServiceFactory > getProcessServiceFactory()
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
std::vector< css::beans::PropertyValue > JsonToPropertyValues(const OString &rJson)
Reference< XComponentContext > getProcessComponentContext()
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
std::shared_ptr< osl::Mutex > const & lock()
Any SAL_CALL getCaughtException()
CPPUHELPER_DLLPUBLIC css::uno::Reference< css::uno::XComponentContext > SAL_CALL defaultBootstrap_InitialComponentContext()
Definition: app.cxx:167
DESKTOP_DLLPUBLIC OUString extractParameter(OUString &aOptions, std::u16string_view rName)
Helper function to extract the value from parameters delimited by comma, like: Name1=Value1,...
Definition: init.cxx:1046
OUString ReplaceStringHookProc(const OUString &rStr)
Definition: app.cxx:399
DESKTOP_DLLPUBLIC std::vector< com::sun::star::beans::PropertyValue > jsonToPropertyValuesVector(const char *pJSON)
Helper function to convert JSON to a vector of PropertyValues.
Definition: init.cxx:403
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
constexpr double alpha[nDetails]
Value
int i
VCL_DLLPUBLIC bool ExecuteAction(const OUString &nWindowId, const OUString &rWidget, StringMap &rData)
VCL_DLLPUBLIC StringMap jsonToStringMap(const char *pJSON)
VCL_DLLPUBLIC void SendFullUpdate(const OUString &nWindowId, const OUString &rWidget)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
constexpr auto toTwips(N number, Length from)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
end
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
long Long
OUString toISO8601(const css::util::DateTime &rDateTime)
void registerPollCallbacks(LibreOfficeKitPollCallback pPollCallback, LibreOfficeKitWakeCallback pWakeCallback, void *pData)
void numberOfViewsChanged(int count)
bool isUnipoll()
void unregisterPollCallbacks()
void trimMemory(int nTarget)
void dumpState(rtl::OStringBuffer &rState)
void VclBuilderPreload()
void CloseTopLevel(vcl::Window *pWindow)
void EnableDialogInput(vcl::Window *pWindow)
HashMap_OWString_Interface aMap
sal_Int16 nId
officecfg::Office::Linguistic::GrammarChecking::LanguageTool LanguageToolCfg
QPRO_FUNC_TYPE nType
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
const sal_Unicode *const aMimeType[]
int DESKTOP_DLLPUBLIC soffice_main()
Definition: sofficemain.cxx:53
sal_uIntPtr sal_uLong
boost::property_tree::ptree & setJson(const std::string &payload)
Parse and set the JSON object and return it. Clobbers PayloadString.
Definition: init.cxx:644
const boost::property_tree::ptree & getJson() const
Return the parsed JSON instance.
Definition: init.cxx:667
bool validate() const
Validate that the payload and parsed object match.
Definition: init.cxx:683
void updateRectangleAndPart(const RectangleAndPart &rRectAndPart)
Update a RectangleAndPart object and update PayloadString if necessary.
Definition: init.cxx:629
boost::variant< boost::blank, RectangleAndPart, boost::property_tree::ptree, int > PayloadObject
The parsed payload cache. Update validate() when changing this.
Definition: init.hxx:186
const OString & getPayload() const
Definition: init.cxx:617
const RectangleAndPart & getRectangleAndPart() const
Return the parsed RectangleAndPart instance.
Definition: init.cxx:635
LibLODocument_Impl(css::uno::Reference< css::lang::XComponent > xComponent, int nDocumentId)
Definition: init.cxx:1392
std::map< size_t, std::shared_ptr< CallbackFlushHandler > > mpCallbackFlushHandlers
Definition: init.hxx:251
std::set< OUString > maFontsMissing
Definition: init.hxx:253
std::shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass
Definition: init.hxx:250
css::uno::Reference< css::lang::XComponent > mxComponent
Definition: init.hxx:249
LibreOfficeKitCallback mpCallback
Definition: init.hxx:265
std::shared_ptr< LibreOfficeKitClass > m_pOfficeClass
Definition: init.hxx:263
void dumpState(rtl::OStringBuffer &aState)
Definition: init.cxx:4816
Represents an invalidated rectangle inside a given document part.
Definition: init.hxx:43
tools::Rectangle m_aRectangle
Definition: init.hxx:44
static tools::Rectangle SanitizedRectangle(tools::Long nLeft, tools::Long nTop, tools::Long nWidth, tools::Long nHeight)
Makes sure a rectangle is valid (apparently some code does not like negative coordinates for example)...
Definition: init.cxx:587
static RectangleAndPart Create(const OString &rPayload)
Definition: init.cxx:516
OString toString() const
Definition: init.hxx:66
bool isInfinite() const
Infinite Rectangle is both sides are equal or longer than SfxLokHelper::MaxTwips.
Definition: init.hxx:77
bool isEmpty() const
Empty Rectangle is when it has zero dimensions.
Definition: init.hxx:84
UNDERLYING_TYPE get() const
Object Value
Reference< XController > xController
Reference< XModel > xModel
VCL_DLLPUBLIC bool InitVCL()
VCL_DLLPUBLIC Application * GetpApp()
OUString aCommand
OUString Name
unsigned char sal_uInt8
sal_uInt16 sal_Unicode
void * sal_Handle
signed char sal_Int8
Any result
ResultType type
size_t pos
std::unique_ptr< char[]> aBuffer
std::map< OUString, OUString > StringMap
const SvXMLTokenMapEntry aTypes[]
const char * pChar