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 <config_folders.h>
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 
16 #ifdef IOS
17 #include <sys/mman.h>
18 #include <sys/stat.h>
19 #include <unicode/udata.h>
20 #include <unicode/ucnv.h>
21 #include <premac.h>
22 #import <Foundation/Foundation.h>
23 #import <CoreGraphics/CoreGraphics.h>
24 #include <postmac.h>
25 #endif
26 
27 #ifdef ANDROID
28 #include <osl/detail/android-bootstrap.h>
29 #endif
30 
31 #include <algorithm>
32 #include <memory>
33 #include <iostream>
34 #include <boost/property_tree/json_parser.hpp>
35 #include <boost/algorithm/string.hpp>
36 
37 #include <LibreOfficeKit/LibreOfficeKit.h>
38 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
39 
40 #include <sal/log.hxx>
41 #include <vcl/errinf.hxx>
42 #include <vcl/lok.hxx>
43 #include <osl/file.hxx>
44 #include <osl/process.h>
45 #include <osl/thread.h>
46 #include <rtl/bootstrap.hxx>
47 #include <rtl/strbuf.hxx>
48 #include <rtl/uri.hxx>
49 #include <cppuhelper/bootstrap.hxx>
51 #include <comphelper/lok.hxx>
53 #include <comphelper/string.hxx>
58 #include <comphelper/base64.hxx>
59 
60 #include <com/sun/star/beans/XPropertySet.hpp>
61 #include <com/sun/star/container/XNameAccess.hpp>
62 #include <com/sun/star/frame/Desktop.hpp>
63 #include <com/sun/star/frame/DispatchResultEvent.hpp>
64 #include <com/sun/star/frame/DispatchResultState.hpp>
65 #include <com/sun/star/frame/XDispatchProvider.hpp>
66 #include <com/sun/star/frame/XDispatchResultListener.hpp>
67 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
68 #include <com/sun/star/frame/XStorable.hpp>
69 #include <com/sun/star/lang/Locale.hpp>
70 #include <com/sun/star/lang/XComponent.hpp>
71 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
72 #include <com/sun/star/reflection/theCoreReflection.hpp>
73 #include <com/sun/star/reflection/XIdlClass.hpp>
74 #include <com/sun/star/reflection/XIdlReflection.hpp>
75 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
76 #include <com/sun/star/ucb/XContentProvider.hpp>
77 #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
78 #include <com/sun/star/util/URLTransformer.hpp>
79 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
80 #include <com/sun/star/text/TextContentAnchorType.hpp>
81 #include <com/sun/star/document/XRedlinesSupplier.hpp>
82 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
83 
84 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
85 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
86 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
87 #include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
88 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
89 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
90 #include <com/sun/star/security/XCertificate.hpp>
91 
92 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
93 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
94 #include <com/sun/star/i18n/ScriptType.hpp>
95 #include <com/sun/star/lang/DisposedException.hpp>
96 
97 #include <editeng/fontitem.hxx>
98 #include <editeng/flstitem.hxx>
99 #include <sfx2/app.hxx>
100 #include <sfx2/objsh.hxx>
101 #include <sfx2/viewsh.hxx>
102 #include <sfx2/viewfrm.hxx>
103 #include <sfx2/msgpool.hxx>
104 #include <sfx2/dispatch.hxx>
105 #include <sfx2/lokcharthelper.hxx>
106 #include <sfx2/DocumentSigner.hxx>
107 #include <svx/dialmgr.hxx>
108 #include <svx/dialogs.hrc>
109 #include <svx/strings.hrc>
110 #include <svx/ruler.hxx>
111 #include <svx/svdview.hxx>
112 #include <svx/svxids.hrc>
113 #include <svx/ucsubset.hxx>
114 #include <vcl/vclevent.hxx>
115 #include <vcl/GestureEvent.hxx>
116 #include <vcl/svapp.hxx>
117 #include <unotools/resmgr.hxx>
118 #include <tools/fract.hxx>
119 #include <svtools/ctrltool.hxx>
120 #include <svtools/langtab.hxx>
121 #include <vcl/floatwin.hxx>
122 #include <vcl/fontcharmap.hxx>
123 #include <vcl/graphicfilter.hxx>
124 #include <vcl/ptrstyle.hxx>
125 #include <vcl/sysdata.hxx>
126 #include <vcl/virdev.hxx>
127 #include <vcl/ImageTree.hxx>
128 #include <vcl/ITiledRenderable.hxx>
129 #include <vcl/IDialogRenderable.hxx>
130 #include <vcl/dialog.hxx>
131 #include <unicode/uchar.h>
132 #include <unotools/configmgr.hxx>
135 #include <unotools/pathoptions.hxx>
136 #include <unotools/tempfile.hxx>
137 #include <unotools/streamwrap.hxx>
138 #include <osl/module.hxx>
139 #include <comphelper/sequence.hxx>
140 #include <sfx2/sfxbasemodel.hxx>
141 #include <svl/undo.hxx>
142 #include <unotools/datetime.hxx>
143 #include <i18nlangtag/mslangid.hxx>
145 #include <vcl/builder.hxx>
146 #include <vcl/abstdlg.hxx>
147 #include <tools/diagnose_ex.h>
148 
149 #include <app.hxx>
150 
151 #include "../app/cmdlineargs.hxx"
152 // We also need to hackily be able to start the main libreoffice thread:
153 #include "../app/sofficemain.h"
154 #include "../app/officeipcthread.hxx"
155 #include <lib/init.hxx>
156 
157 #include "lokinteractionhandler.hxx"
158 #include "lokclipboard.hxx"
159 
160 using namespace css;
161 using namespace vcl;
162 using namespace desktop;
163 using namespace utl;
164 
165 static LibLibreOffice_Impl *gImpl = nullptr;
166 static std::weak_ptr< LibreOfficeKitClass > gOfficeClass;
167 static std::weak_ptr< LibreOfficeKitDocumentClass > gDocumentClass;
168 
169 static void SetLastExceptionMsg(const OUString& s = OUString())
170 {
171  if (gImpl)
172  gImpl->maLastExceptionMsg = s;
173 }
174 
176 {
177  const char *extn;
178  const char *filterName;
179 };
180 
182 {
183  { "doc", "MS Word 97" },
184  { "docm", "MS Word 2007 XML VBA" },
185  { "docx", "MS Word 2007 XML" },
186  { "fodt", "OpenDocument Text Flat XML" },
187  { "html", "HTML (StarWriter)" },
188  { "odt", "writer8" },
189  { "ott", "writer8_template" },
190  { "pdf", "writer_pdf_Export" },
191  { "epub", "EPUB" },
192  { "rtf", "Rich Text Format" },
193  { "txt", "Text" },
194  { "xhtml", "XHTML Writer File" },
195  { "png", "writer_png_Export" },
196  { nullptr, nullptr }
197 };
198 
200 {
201  { "csv", "Text - txt - csv (StarCalc)" },
202  { "fods", "OpenDocument Spreadsheet Flat XML" },
203  { "html", "HTML (StarCalc)" },
204  { "ods", "calc8" },
205  { "ots", "calc8_template" },
206  { "pdf", "calc_pdf_Export" },
207  { "xhtml", "XHTML Calc File" },
208  { "xls", "MS Excel 97" },
209  { "xlsm", "Calc MS Excel 2007 VBA XML" },
210  { "xlsx", "Calc MS Excel 2007 XML" },
211  { "png", "calc_png_Export" },
212  { nullptr, nullptr }
213 };
214 
216 {
217  { "fodp", "OpenDocument Presentation Flat XML" },
218  { "html", "impress_html_Export" },
219  { "odg", "impress8_draw" },
220  { "odp", "impress8" },
221  { "otp", "impress8_template" },
222  { "pdf", "impress_pdf_Export" },
223  { "potm", "Impress MS PowerPoint 2007 XML Template" },
224  { "pot", "MS PowerPoint 97 Vorlage" },
225  { "pptm", "Impress MS PowerPoint 2007 XML VBA" },
226  { "pptx", "Impress MS PowerPoint 2007 XML" },
227  { "pps", "MS PowerPoint 97 Autoplay" },
228  { "ppt", "MS PowerPoint 97" },
229  { "svg", "impress_svg_Export" },
230  { "swf", "impress_flash_Export" },
231  { "xhtml", "XHTML Impress File" },
232  { "png", "impress_png_Export"},
233  { nullptr, nullptr }
234 };
235 
237 {
238  { "fodg", "draw_ODG_FlatXML" },
239  { "html", "draw_html_Export" },
240  { "odg", "draw8" },
241  { "pdf", "draw_pdf_Export" },
242  { "svg", "draw_svg_Export" },
243  { "swf", "draw_flash_Export" },
244  { "xhtml", "XHTML Draw File" },
245  { "png", "draw_png_Export"},
246  { nullptr, nullptr }
247 };
248 
249 static OUString getUString(const char* pString)
250 {
251  if (pString == nullptr)
252  return OUString();
253 
254  OString sString(pString, strlen(pString));
255  return OStringToOUString(sString, RTL_TEXTENCODING_UTF8);
256 }
257 
259 static OUString getAbsoluteURL(const char* pURL)
260 {
261  OUString aURL(getUString(pURL));
262  if (aURL.isEmpty())
263  return aURL;
264 
265  // convert relative paths to absolute ones
266  OUString aWorkingDir;
267  osl_getProcessWorkingDir(&aWorkingDir.pData);
268  if (!aWorkingDir.endsWith("/"))
269  aWorkingDir += "/";
270 
271  try
272  {
273  return rtl::Uri::convertRelToAbs(aWorkingDir, aURL);
274  }
275  catch (const rtl::MalformedUriException &)
276  {
277  }
278 
279  return OUString();
280 }
281 
282 static uno::Any jsonToUnoAny(const boost::property_tree::ptree& aTree)
283 {
284  uno::Any aAny;
285  uno::Any aValue;
286  sal_Int32 nFields;
287  uno::TypeClass aTypeClass;
288  uno::Reference< reflection::XIdlField > aField;
289  boost::property_tree::ptree aNodeNull, aNodeValue, aNodeField;
290  const std::string& rType = aTree.get<std::string>("type", "");
291  const std::string& rValue = aTree.get<std::string>("value", "");
292  uno::Sequence< uno::Reference< reflection::XIdlField > > aFields;
293  uno::Reference< reflection:: XIdlClass > xIdlClass =
294  css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())->forName(OUString::fromUtf8(rType.c_str()));
295  if (xIdlClass.is())
296  {
297  aTypeClass = xIdlClass->getTypeClass();
298  xIdlClass->createObject(aAny);
299  aFields = xIdlClass->getFields();
300  nFields = aFields.getLength();
301  aNodeValue = aTree.get_child("value", aNodeNull);
302  if (nFields > 0 && aNodeValue != aNodeNull)
303  {
304  for (sal_Int32 itField = 0; itField < nFields; ++itField)
305  {
306  aField = aFields[itField];
307  aNodeField = aNodeValue.get_child(aField->getName().toUtf8().getStr(), aNodeNull);
308  if (aNodeField != aNodeNull)
309  {
310  aValue = jsonToUnoAny(aNodeField);
311  aField->set(aAny, aValue);
312  }
313  }
314  }
315  else if (!rValue.empty())
316  {
317  if (aTypeClass == uno::TypeClass_VOID)
318  aAny.clear();
319  else if (aTypeClass == uno::TypeClass_BYTE)
320  aAny <<= static_cast<sal_Int8>(OString(rValue.c_str()).toInt32());
321  else if (aTypeClass == uno::TypeClass_BOOLEAN)
322  aAny <<= OString(rValue.c_str()).toBoolean();
323  else if (aTypeClass == uno::TypeClass_SHORT)
324  aAny <<= static_cast<sal_Int16>(OString(rValue.c_str()).toInt32());
325  else if (aTypeClass == uno::TypeClass_UNSIGNED_SHORT)
326  aAny <<= static_cast<sal_uInt16>(OString(rValue.c_str()).toUInt32());
327  else if (aTypeClass == uno::TypeClass_LONG)
328  aAny <<= OString(rValue.c_str()).toInt32();
329  else if (aTypeClass == uno::TypeClass_UNSIGNED_LONG)
330  aAny <<= static_cast<sal_uInt32>(OString(rValue.c_str()).toInt32());
331  else if (aTypeClass == uno::TypeClass_FLOAT)
332  aAny <<= OString(rValue.c_str()).toFloat();
333  else if (aTypeClass == uno::TypeClass_DOUBLE)
334  aAny <<= OString(rValue.c_str()).toDouble();
335  else if (aTypeClass == uno::TypeClass_STRING)
336  aAny <<= OUString::fromUtf8(rValue.c_str());
337  }
338  }
339  return aAny;
340 }
341 
342 std::vector<beans::PropertyValue> desktop::jsonToPropertyValuesVector(const char* pJSON)
343 {
344  std::vector<beans::PropertyValue> aArguments;
345  if (pJSON && pJSON[0] != '\0')
346  {
347  boost::property_tree::ptree aTree, aNodeNull, aNodeValue;
348  std::stringstream aStream(pJSON);
349  boost::property_tree::read_json(aStream, aTree);
350 
351  for (const auto& rPair : aTree)
352  {
353  const std::string& rType = rPair.second.get<std::string>("type", "");
354  const std::string& rValue = rPair.second.get<std::string>("value", "");
355 
356  beans::PropertyValue aValue;
357  aValue.Name = OUString::fromUtf8(rPair.first.c_str());
358  if (rType == "string")
359  aValue.Value <<= OUString::fromUtf8(rValue.c_str());
360  else if (rType == "boolean")
361  aValue.Value <<= OString(rValue.c_str()).toBoolean();
362  else if (rType == "float")
363  aValue.Value <<= OString(rValue.c_str()).toFloat();
364  else if (rType == "long")
365  aValue.Value <<= OString(rValue.c_str()).toInt32();
366  else if (rType == "short")
367  aValue.Value <<= static_cast<sal_Int16>(OString(rValue.c_str()).toInt32());
368  else if (rType == "unsigned short")
369  aValue.Value <<= static_cast<sal_uInt16>(OString(rValue.c_str()).toUInt32());
370  else if (rType == "[]byte")
371  {
372  aNodeValue = rPair.second.get_child("value", aNodeNull);
373  if (aNodeValue != aNodeNull && aNodeValue.size() == 0)
374  {
375  uno::Sequence< sal_Int8 > aSeqByte(reinterpret_cast<const sal_Int8*>(rValue.c_str()), rValue.size());
376  aValue.Value <<= aSeqByte;
377  }
378  }
379  else if (rType == "[]any")
380  {
381  aNodeValue = rPair.second.get_child("value", aNodeNull);
382  if (aNodeValue != aNodeNull && !aNodeValue.empty())
383  {
384  sal_Int32 itSeq = 0;
385  uno::Sequence< uno::Any > aSeq(aNodeValue.size());
386  for (const auto& rSeqPair : aNodeValue)
387  aSeq[itSeq++] = jsonToUnoAny(rSeqPair.second);
388  aValue.Value <<= aSeq;
389  }
390  }
391  else
392  SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled type '"<<rType<<"'");
393  aArguments.push_back(aValue);
394  }
395  }
396  return aArguments;
397 }
398 
399 static boost::property_tree::ptree unoAnyToPropertyTree(const uno::Any& anyItem)
400 {
401  boost::property_tree::ptree aTree;
402  OUString aType = anyItem.getValueTypeName();
403  aTree.put("type", aType.toUtf8().getStr());
404 
405  if (aType == "string")
406  aTree.put("value", anyItem.get<OUString>().toUtf8().getStr());
407  else if (aType == "unsigned long")
408  aTree.put("value", OString::number(anyItem.get<sal_uInt32>()).getStr());
409  else if (aType == "long")
410  aTree.put("value", OString::number(anyItem.get<sal_Int32>()).getStr());
411  else if (aType == "[]any")
412  {
413  uno::Sequence<uno::Any> aSeq;
414  if (anyItem >>= aSeq)
415  {
416  boost::property_tree::ptree aSubTree;
417 
418  for (auto i = 0; i < aSeq.getLength(); ++i)
419  {
420  aSubTree.add_child(OString::number(i).getStr(), unoAnyToPropertyTree(aSeq[i]));
421  }
422  aTree.add_child("value", aSubTree);
423  }
424  }
425 
426  // TODO: Add more as required
427 
428  return aTree;
429 }
430 
431 namespace desktop {
432 
433 RectangleAndPart RectangleAndPart::Create(const std::string& rPayload)
434 {
435  RectangleAndPart aRet;
436  if (rPayload.compare(0, 5, "EMPTY") == 0) // payload starts with "EMPTY"
437  {
440  aRet.m_nPart = std::stol(rPayload.substr(6));
441 
442  return aRet;
443  }
444 
445  std::istringstream aStream(rPayload);
446  long nLeft, nTop, nWidth, nHeight;
447  long nPart = INT_MIN;
448  char nComma;
450  {
451  aStream >> nLeft >> nComma >> nTop >> nComma >> nWidth >> nComma >> nHeight >> nComma >> nPart;
452  }
453  else
454  {
455  aStream >> nLeft >> nComma >> nTop >> nComma >> nWidth >> nComma >> nHeight;
456  }
457 
458  if (nWidth > 0 && nHeight > 0)
459  {
460  // The top-left corner starts at (0, 0).
461  // Anything negative is invalid.
462  if (nLeft < 0)
463  {
464  nWidth += nLeft;
465  nLeft = 0;
466  }
467 
468  if (nTop < 0)
469  {
470  nHeight += nTop;
471  nTop = 0;
472  }
473 
474  if (nWidth > 0 && nHeight > 0)
475  {
476  aRet.m_aRectangle = tools::Rectangle(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
477  }
478  }
479  // else leave empty rect.
480 
481  aRet.m_nPart = nPart;
482  return aRet;
483 }
484 
485 RectangleAndPart& CallbackFlushHandler::CallbackData::setRectangleAndPart(const std::string& payload)
486 {
487  setRectangleAndPart(RectangleAndPart::Create(payload));
488 
489  // Return reference to the cached object.
490  return boost::get<RectangleAndPart>(PayloadObject);
491 }
492 
493 void CallbackFlushHandler::CallbackData::setRectangleAndPart(const RectangleAndPart& rRectAndPart)
494 {
495  PayloadString = rRectAndPart.toString().getStr();
496  PayloadObject = rRectAndPart;
497 }
498 
499 const RectangleAndPart& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
500 {
501  assert(PayloadObject.which() == 1);
502  return boost::get<RectangleAndPart>(PayloadObject);
503 }
504 
505 boost::property_tree::ptree& CallbackFlushHandler::CallbackData::setJson(const std::string& payload)
506 {
507  boost::property_tree::ptree aTree;
508  std::stringstream aStream(payload);
509  boost::property_tree::read_json(aStream, aTree);
510 
511  // Let boost normalize the payload so it always matches the cache.
512  setJson(aTree);
513 
514  // Return reference to the cached object.
515  return boost::get<boost::property_tree::ptree>(PayloadObject);
516 }
517 
518 void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree& rTree)
519 {
520  std::stringstream aJSONStream;
521  constexpr bool bPretty = false; // Don't waste time and bloat logs.
522  boost::property_tree::write_json(aJSONStream, rTree, bPretty);
523  PayloadString = boost::trim_copy(aJSONStream.str());
524 
525  PayloadObject = rTree;
526 }
527 
528 const boost::property_tree::ptree& CallbackFlushHandler::CallbackData::getJson() const
529 {
530  assert(PayloadObject.which() == 2);
531  return boost::get<boost::property_tree::ptree>(PayloadObject);
532 }
533 
534 bool CallbackFlushHandler::CallbackData::validate() const
535 {
536  switch (PayloadObject.which())
537  {
538  // Not cached.
539  case 0:
540  return true;
541 
542  // RectangleAndPart.
543  case 1:
544  return getRectangleAndPart().toString().getStr() == PayloadString;
545 
546  // Json.
547  case 2:
548  {
549  std::stringstream aJSONStream;
550  boost::property_tree::write_json(aJSONStream, getJson(), false);
551  const std::string aExpected = boost::trim_copy(aJSONStream.str());
552  return aExpected == PayloadString;
553  }
554 
555  default:
556  assert(!"Unknown variant type; please add an entry to validate.");
557  }
558 
559  return false;
560 }
561 
562 }
563 
564 namespace {
565 
566 bool lcl_isViewCallbackType(const int type)
567 {
568  switch (type)
569  {
570  case LOK_CALLBACK_CELL_VIEW_CURSOR:
571  case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
572  case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
573  case LOK_CALLBACK_TEXT_VIEW_SELECTION:
574  case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
575  return true;
576 
577  default:
578  return false;
579  }
580 }
581 
582 int lcl_getViewId(const std::string& payload)
583 {
584  // this is a cheap way how to get the viewId from a JSON message; proper
585  // parsing is terribly expensive, and we just need the viewId here
586  size_t viewIdPos = payload.find("viewId");
587  if (viewIdPos == std::string::npos)
588  return 0;
589 
590  size_t numberPos = payload.find(":", viewIdPos + 6);
591  if (numberPos == std::string::npos)
592  return 0;
593 
594  for (++numberPos; numberPos < payload.length(); ++numberPos)
595  {
596  if (payload[numberPos] == ',' || payload[numberPos] == '}' || (payload[numberPos] >= '0' && payload[numberPos] <= '9'))
597  break;
598  }
599 
600  if (numberPos < payload.length() && payload[numberPos] >= '0' && payload[numberPos] <= '9')
601  return strtol(payload.substr(numberPos).c_str(), nullptr, 10);
602 
603  return 0;
604 }
605 
606 int lcl_getViewId(const desktop::CallbackFlushHandler::CallbackData& rCallbackData)
607 {
608  if (rCallbackData.isCached())
609  return rCallbackData.getJson().get<int>("viewId");
610  return lcl_getViewId(rCallbackData.PayloadString);
611 }
612 
613 std::string extractCertificate(const std::string & certificate)
614 {
615  const std::string header("-----BEGIN CERTIFICATE-----");
616  const std::string footer("-----END CERTIFICATE-----");
617 
618  std::string result;
619 
620  size_t pos1 = certificate.find(header);
621  if (pos1 == std::string::npos)
622  return result;
623 
624  size_t pos2 = certificate.find(footer, pos1 + 1);
625  if (pos2 == std::string::npos)
626  return result;
627 
628  pos1 = pos1 + header.length();
629  pos2 = pos2 - pos1;
630 
631  return certificate.substr(pos1, pos2);
632 }
633 
634 std::string extractPrivateKey(const std::string & privateKey)
635 {
636  const std::string header("-----BEGIN PRIVATE KEY-----");
637  const std::string footer("-----END PRIVATE KEY-----");
638 
639  std::string result;
640 
641  size_t pos1 = privateKey.find(header);
642  if (pos1 == std::string::npos)
643  return result;
644 
645  size_t pos2 = privateKey.find(footer, pos1 + 1);
646  if (pos2 == std::string::npos)
647  return result;
648 
649  pos1 = pos1 + header.length();
650  pos2 = pos2 - pos1;
651 
652  return privateKey.substr(pos1, pos2);
653 }
654 
655 } // end anonymous namespace
656 
657 // Could be anonymous in principle, but for the unit testing purposes, we
658 // declare it in init.hxx.
659 OUString desktop::extractParameter(OUString& rOptions, const OUString& rName)
660 {
661  OUString aValue;
662 
663  OUString aNameEquals(rName + "=");
664  OUString aCommaNameEquals("," + rName + "=");
665 
666  int nIndex = -1;
667  if (rOptions.startsWith(aNameEquals))
668  {
669  size_t nLen = aNameEquals.getLength();
670  int nComma = rOptions.indexOf(",", nLen);
671  if (nComma >= 0)
672  {
673  aValue = rOptions.copy(nLen, nComma - nLen);
674  rOptions = rOptions.copy(nComma + 1);
675  }
676  else
677  {
678  aValue = rOptions.copy(nLen);
679  rOptions.clear();
680  }
681  }
682  else if ((nIndex = rOptions.indexOf(aCommaNameEquals)) >= 0)
683  {
684  size_t nLen = aCommaNameEquals.getLength();
685  int nComma = rOptions.indexOf(",", nIndex + nLen);
686  if (nComma >= 0)
687  {
688  aValue = rOptions.copy(nIndex + nLen, nComma - nIndex - nLen);
689  rOptions = rOptions.copy(0, nIndex) + rOptions.copy(nComma);
690  }
691  else
692  {
693  aValue = rOptions.copy(nIndex + nLen);
694  rOptions = rOptions.copy(0, nIndex);
695  }
696  }
697 
698  return aValue;
699 }
700 
701 extern "C"
702 {
703 
704 static void doc_destroy(LibreOfficeKitDocument* pThis);
705 static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* pUrl, const char* pFormat, const char* pFilterOptions);
706 static int doc_getDocumentType(LibreOfficeKitDocument* pThis);
707 static int doc_getParts(LibreOfficeKitDocument* pThis);
708 static char* doc_getPartPageRectangles(LibreOfficeKitDocument* pThis);
709 static int doc_getPart(LibreOfficeKitDocument* pThis);
710 static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart);
711 static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart);
712 static void doc_setPartMode(LibreOfficeKitDocument* pThis, int nPartMode);
713 static void doc_paintTile(LibreOfficeKitDocument* pThis,
714  unsigned char* pBuffer,
715  const int nCanvasWidth, const int nCanvasHeight,
716  const int nTilePosX, const int nTilePosY,
717  const int nTileWidth, const int nTileHeight);
718 #ifdef IOS
719 static void doc_paintTileToCGContext(LibreOfficeKitDocument* pThis,
720  void* rCGContext,
721  const int nCanvasWidth, const int nCanvasHeight,
722  const int nTilePosX, const int nTilePosY,
723  const int nTileWidth, const int nTileHeight);
724 #endif
725 static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
726  unsigned char* pBuffer,
727  const int nPart,
728  const int nCanvasWidth, const int nCanvasHeight,
729  const int nTilePosX, const int nTilePosY,
730  const int nTileWidth, const int nTileHeight);
731 static int doc_getTileMode(LibreOfficeKitDocument* pThis);
732 static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
733  long* pWidth,
734  long* pHeight);
735 static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
736  const char* pArguments);
737 
738 static void doc_registerCallback(LibreOfficeKitDocument* pThis,
739  LibreOfficeKitCallback pCallback,
740  void* pData);
741 static void doc_postKeyEvent(LibreOfficeKitDocument* pThis,
742  int nType,
743  int nCharCode,
744  int nKeyCode);
745 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis,
746  unsigned nWindowId,
747  int nType,
748  const char* pText);
749 static void doc_postWindowKeyEvent(LibreOfficeKitDocument* pThis,
750  unsigned nLOKWindowId,
751  int nType,
752  int nCharCode,
753  int nKeyCode);
754 static void doc_postMouseEvent (LibreOfficeKitDocument* pThis,
755  int nType,
756  int nX,
757  int nY,
758  int nCount,
759  int nButtons,
760  int nModifier);
761 static void doc_postWindowMouseEvent (LibreOfficeKitDocument* pThis,
762  unsigned nLOKWindowId,
763  int nType,
764  int nX,
765  int nY,
766  int nCount,
767  int nButtons,
768  int nModifier);
769 static void doc_postWindowGestureEvent(LibreOfficeKitDocument* pThis,
770  unsigned nLOKWindowId,
771  const char* pType,
772  int nX,
773  int nY,
774  int nOffset);
775 static void doc_postUnoCommand(LibreOfficeKitDocument* pThis,
776  const char* pCommand,
777  const char* pArguments,
778  bool bNotifyWhenFinished);
779 static void doc_setTextSelection (LibreOfficeKitDocument* pThis,
780  int nType,
781  int nX,
782  int nY);
783 static char* doc_getTextSelection(LibreOfficeKitDocument* pThis,
784  const char* pMimeType,
785  char** pUsedMimeType);
786 static bool doc_paste(LibreOfficeKitDocument* pThis,
787  const char* pMimeType,
788  const char* pData,
789  size_t nSize);
790 static void doc_setGraphicSelection (LibreOfficeKitDocument* pThis,
791  int nType,
792  int nX,
793  int nY);
794 static void doc_resetSelection (LibreOfficeKitDocument* pThis);
795 static char* doc_getCommandValues(LibreOfficeKitDocument* pThis, const char* pCommand);
796 static void doc_setClientZoom(LibreOfficeKitDocument* pThis,
797  int nTilePixelWidth,
798  int nTilePixelHeight,
799  int nTileTwipWidth,
800  int nTileTwipHeight);
801 static void doc_setClientVisibleArea(LibreOfficeKitDocument* pThis, int nX, int nY, int nWidth, int nHeight);
802 static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int nLevel, int nIndex, bool bHidden);
803 static int doc_createView(LibreOfficeKitDocument* pThis);
804 static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis, const char* pOptions);
805 static void doc_destroyView(LibreOfficeKitDocument* pThis, int nId);
806 static void doc_setView(LibreOfficeKitDocument* pThis, int nId);
807 static int doc_getView(LibreOfficeKitDocument* pThis);
808 static int doc_getViewsCount(LibreOfficeKitDocument* pThis);
809 static bool doc_getViewIds(LibreOfficeKitDocument* pThis, int* pArray, size_t nSize);
810 static void doc_setViewLanguage(LibreOfficeKitDocument* pThis, int nId, const char* language);
811 static unsigned char* doc_renderFont(LibreOfficeKitDocument* pThis,
812  const char *pFontName,
813  const char *pChar,
814  int* pFontWidth,
815  int* pFontHeight);
816 static char* doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart);
817 
818 static void doc_paintWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
819  const int nX, const int nY,
820  const int nWidth, const int nHeight);
821 
822 static void doc_paintWindowDPI(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
823  const int nX, const int nY,
824  const int nWidth, const int nHeight,
825  const double fDPIScale);
826 
827 static void doc_postWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, int nAction, const char* pData);
828 
829 static char* doc_getPartInfo(LibreOfficeKitDocument* pThis, int nPart);
830 
831 static bool doc_insertCertificate(LibreOfficeKitDocument* pThis,
832  const unsigned char* pCertificateBinary,
833  const int nCertificateBinarySize,
834  const unsigned char* pPrivateKeyBinary,
835  const int nPrivateKeyBinarySize);
836 
837 static bool doc_addCertificate(LibreOfficeKitDocument* pThis,
838  const unsigned char* pCertificateBinary,
839  const int nCertificateBinarySize);
840 
841 static int doc_getSignatureState(LibreOfficeKitDocument* pThis);
842 
843 static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOutput);
844 
845 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent)
846  : mxComponent(xComponent)
847 {
848  if (!(m_pDocumentClass = gDocumentClass.lock()))
849  {
850  m_pDocumentClass.reset(new LibreOfficeKitDocumentClass);
851 
852  m_pDocumentClass->nSize = sizeof(LibreOfficeKitDocumentClass);
853 
854  m_pDocumentClass->destroy = doc_destroy;
855  m_pDocumentClass->saveAs = doc_saveAs;
856  m_pDocumentClass->getDocumentType = doc_getDocumentType;
857  m_pDocumentClass->getParts = doc_getParts;
858  m_pDocumentClass->getPartPageRectangles = doc_getPartPageRectangles;
859  m_pDocumentClass->getPart = doc_getPart;
860  m_pDocumentClass->setPart = doc_setPart;
861  m_pDocumentClass->getPartName = doc_getPartName;
862  m_pDocumentClass->setPartMode = doc_setPartMode;
863  m_pDocumentClass->paintTile = doc_paintTile;
864 #ifdef IOS
865  m_pDocumentClass->paintTileToCGContext = doc_paintTileToCGContext;
866 #endif
867  m_pDocumentClass->paintPartTile = doc_paintPartTile;
868  m_pDocumentClass->getTileMode = doc_getTileMode;
869  m_pDocumentClass->getDocumentSize = doc_getDocumentSize;
870  m_pDocumentClass->initializeForRendering = doc_initializeForRendering;
871  m_pDocumentClass->registerCallback = doc_registerCallback;
872  m_pDocumentClass->postKeyEvent = doc_postKeyEvent;
873  m_pDocumentClass->postWindowExtTextInputEvent = doc_postWindowExtTextInputEvent;
874  m_pDocumentClass->postWindowKeyEvent = doc_postWindowKeyEvent;
875  m_pDocumentClass->postMouseEvent = doc_postMouseEvent;
876  m_pDocumentClass->postWindowMouseEvent = doc_postWindowMouseEvent;
877  m_pDocumentClass->postUnoCommand = doc_postUnoCommand;
878  m_pDocumentClass->setTextSelection = doc_setTextSelection;
879  m_pDocumentClass->getTextSelection = doc_getTextSelection;
880  m_pDocumentClass->paste = doc_paste;
881  m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection;
882  m_pDocumentClass->resetSelection = doc_resetSelection;
883  m_pDocumentClass->getCommandValues = doc_getCommandValues;
884  m_pDocumentClass->setClientZoom = doc_setClientZoom;
885  m_pDocumentClass->setClientVisibleArea = doc_setClientVisibleArea;
886  m_pDocumentClass->setOutlineState = doc_setOutlineState;
887 
888  m_pDocumentClass->createView = doc_createView;
889  m_pDocumentClass->destroyView = doc_destroyView;
890  m_pDocumentClass->setView = doc_setView;
891  m_pDocumentClass->getView = doc_getView;
892  m_pDocumentClass->getViewsCount = doc_getViewsCount;
893  m_pDocumentClass->getViewIds = doc_getViewIds;
894 
895  m_pDocumentClass->renderFont = doc_renderFont;
896  m_pDocumentClass->getPartHash = doc_getPartHash;
897 
898  m_pDocumentClass->paintWindow = doc_paintWindow;
899  m_pDocumentClass->paintWindowDPI = doc_paintWindowDPI;
900  m_pDocumentClass->postWindow = doc_postWindow;
901 
902  m_pDocumentClass->setViewLanguage = doc_setViewLanguage;
903 
904  m_pDocumentClass->getPartInfo = doc_getPartInfo;
905 
906  m_pDocumentClass->insertCertificate = doc_insertCertificate;
907  m_pDocumentClass->addCertificate = doc_addCertificate;
908  m_pDocumentClass->getSignatureState = doc_getSignatureState;
909 
910  m_pDocumentClass->renderShapeSelection = doc_renderShapeSelection;
911  m_pDocumentClass->postWindowGestureEvent = doc_postWindowGestureEvent;
912 
913  m_pDocumentClass->createViewWithOptions = doc_createViewWithOptions;
914 
916  }
917  pClass = m_pDocumentClass.get();
918 }
919 
921 {
922  try
923  {
924  mxComponent->dispose();
925  }
926  catch (const css::lang::DisposedException& rException)
927  {
928  SAL_WARN("lok", "failed to dispose document:" << rException.Message);
929  }
930 }
931 
932 CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, LibreOfficeKitCallback pCallback, void* pData)
933  : Idle( "lokit timer callback" ),
934  m_pDocument(pDocument),
935  m_pCallback(pCallback),
936  m_pData(pData),
937  m_bPartTilePainting(false),
938  m_bEventLatch(false)
939 {
940  SetPriority(TaskPriority::POST_PAINT);
941 
942  // Add the states that are safe to skip duplicates on,
943  // even when not consequent.
944  m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL");
945  m_states.emplace(LOK_CALLBACK_GRAPHIC_SELECTION, "NIL");
946  m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL");
947  m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL");
948  m_states.emplace(LOK_CALLBACK_MOUSE_POINTER, "NIL");
949  m_states.emplace(LOK_CALLBACK_CELL_CURSOR, "NIL");
950  m_states.emplace(LOK_CALLBACK_CELL_FORMULA, "NIL");
951  m_states.emplace(LOK_CALLBACK_CELL_ADDRESS, "NIL");
952  m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL");
953  m_states.emplace(LOK_CALLBACK_SET_PART, "NIL");
954 
955  Start();
956 }
957 
959 {
960  Stop();
961 }
962 
963 void CallbackFlushHandler::callback(const int type, const char* payload, void* data)
964 {
965  CallbackFlushHandler* self = static_cast<CallbackFlushHandler*>(data);
966  if (self)
967  {
968  self->queue(type, payload);
969  }
970 }
971 
972 void CallbackFlushHandler::queue(const int type, const char* data)
973 {
974  comphelper::ProfileZone aZone("CallbackFlushHander::queue");
975 
976  CallbackData aCallbackData(type, (data ? data : "(nil)"));
977  const std::string& payload = aCallbackData.PayloadString;
978  SAL_INFO("lok", "Queue: " << type << " : " << payload);
979 
980 #ifdef DBG_UTIL
981  {
982  // Dump the queue state and validate cached data.
983  int i = 1;
984  std::ostringstream oss;
985  oss << '\n';
986  for (const CallbackData& c : m_queue)
987  oss << i++ << ": [" << c.Type << "] [" << c.PayloadString << "].\n";
988  const std::string aQueued = oss.str();
989  SAL_INFO("lok", "Current Queue: " << (aQueued.empty() ? "Empty" : aQueued));
990  for (const CallbackData& c : m_queue)
991  assert(c.validate());
992  }
993 #endif
994 
995  bool bIsChartActive = false;
996  if (type == LOK_CALLBACK_GRAPHIC_SELECTION)
997  {
998  LokChartHelper aChartHelper(SfxViewShell::Current());
999  bIsChartActive = aChartHelper.GetWindow() != nullptr;
1000  }
1001 
1002  if (m_bPartTilePainting && !bIsChartActive)
1003  {
1004  // We drop notifications when this is set, except for important ones.
1005  // When we issue a complex command (such as .uno:InsertAnnotation)
1006  // there will be multiple notifications. On the first invalidation
1007  // we will start painting, but other events will get fired
1008  // while the complex command in question executes.
1009  // We don't want to suppress everything here on the wrong assumption
1010  // that no new events are fired during painting.
1011  if (type != LOK_CALLBACK_STATE_CHANGED &&
1012  type != LOK_CALLBACK_INVALIDATE_TILES &&
1013  type != LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR &&
1014  type != LOK_CALLBACK_CURSOR_VISIBLE &&
1015  type != LOK_CALLBACK_VIEW_CURSOR_VISIBLE &&
1016  type != LOK_CALLBACK_TEXT_SELECTION)
1017  {
1018  SAL_INFO("lok", "Skipping while painting [" << type << "]: [" << payload << "].");
1019  return;
1020  }
1021 
1022  // In Writer we drop all notifications during painting.
1023  if (doc_getDocumentType(m_pDocument) == LOK_DOCTYPE_TEXT)
1024  return;
1025  }
1026 
1027  // Suppress invalid payloads.
1028  if (type == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR &&
1029  payload.find(", 0, 0, ") != std::string::npos)
1030  {
1031  // The cursor position is often the relative coordinates of the widget
1032  // issuing it, instead of the absolute one that we expect.
1033  // This is temporary however, and, once the control is created and initialized
1034  // correctly, it eventually emits the correct absolute coordinates.
1035  SAL_INFO("lok", "Skipping invalid event [" << type << "]: [" << payload << "].");
1036  return;
1037  }
1038 
1039  std::unique_lock<std::mutex> lock(m_mutex);
1040 
1041  // drop duplicate callbacks for the listed types
1042  switch (type)
1043  {
1044  case LOK_CALLBACK_TEXT_SELECTION_START:
1045  case LOK_CALLBACK_TEXT_SELECTION_END:
1046  case LOK_CALLBACK_TEXT_SELECTION:
1047  case LOK_CALLBACK_GRAPHIC_SELECTION:
1048  case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
1049  case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
1050  case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR :
1051  case LOK_CALLBACK_STATE_CHANGED:
1052  case LOK_CALLBACK_MOUSE_POINTER:
1053  case LOK_CALLBACK_CELL_CURSOR:
1054  case LOK_CALLBACK_CELL_VIEW_CURSOR:
1055  case LOK_CALLBACK_CELL_FORMULA:
1056  case LOK_CALLBACK_CELL_ADDRESS:
1057  case LOK_CALLBACK_CURSOR_VISIBLE:
1058  case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
1059  case LOK_CALLBACK_SET_PART:
1060  case LOK_CALLBACK_TEXT_VIEW_SELECTION:
1061  case LOK_CALLBACK_INVALIDATE_HEADER:
1062  case LOK_CALLBACK_WINDOW:
1063  {
1064  const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(),
1065  [type] (const queue_type::value_type& elem) { return (elem.Type == type); });
1066 
1067  if (pos != m_queue.rend() && pos->PayloadString == payload)
1068  {
1069  SAL_INFO("lok", "Skipping queue duplicate [" << type << + "]: [" << payload << "].");
1070  return;
1071  }
1072  }
1073  break;
1074  }
1075 
1076  if (type == LOK_CALLBACK_TEXT_SELECTION && payload.empty())
1077  {
1078  const auto& posStart = std::find_if(m_queue.rbegin(), m_queue.rend(),
1079  [] (const queue_type::value_type& elem) { return (elem.Type == LOK_CALLBACK_TEXT_SELECTION_START); });
1080  if (posStart != m_queue.rend())
1081  posStart->PayloadString.clear();
1082 
1083  const auto& posEnd = std::find_if(m_queue.rbegin(), m_queue.rend(),
1084  [] (const queue_type::value_type& elem) { return (elem.Type == LOK_CALLBACK_TEXT_SELECTION_END); });
1085  if (posEnd != m_queue.rend())
1086  posEnd->PayloadString.clear();
1087  }
1088 
1089  // When payload is empty discards any previous state.
1090  if (payload.empty())
1091  {
1092  switch (type)
1093  {
1094  case LOK_CALLBACK_TEXT_SELECTION_START:
1095  case LOK_CALLBACK_TEXT_SELECTION_END:
1096  case LOK_CALLBACK_TEXT_SELECTION:
1097  case LOK_CALLBACK_GRAPHIC_SELECTION:
1098  case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
1099  case LOK_CALLBACK_INVALIDATE_TILES:
1100  SAL_INFO("lok", "Removing dups of [" << type << "]: [" << payload << "].");
1101  removeAll([type] (const queue_type::value_type& elem) { return (elem.Type == type); });
1102  break;
1103  }
1104  }
1105  else
1106  {
1107  switch (type)
1108  {
1109  // These are safe to use the latest state and ignore previous
1110  // ones (if any) since the last overrides previous ones.
1111  case LOK_CALLBACK_TEXT_SELECTION_START:
1112  case LOK_CALLBACK_TEXT_SELECTION_END:
1113  case LOK_CALLBACK_TEXT_SELECTION:
1114  case LOK_CALLBACK_GRAPHIC_SELECTION:
1115  case LOK_CALLBACK_MOUSE_POINTER:
1116  case LOK_CALLBACK_CELL_CURSOR:
1117  case LOK_CALLBACK_CELL_FORMULA:
1118  case LOK_CALLBACK_CELL_ADDRESS:
1119  case LOK_CALLBACK_CURSOR_VISIBLE:
1120  case LOK_CALLBACK_SET_PART:
1121  case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
1122  case LOK_CALLBACK_RULER_UPDATE:
1123  {
1124  removeAll([type] (const queue_type::value_type& elem) { return (elem.Type == type); });
1125  }
1126  break;
1127 
1128  // These are safe to use the latest state and ignore previous
1129  // ones (if any) since the last overrides previous ones,
1130  // but only if the view is the same.
1131  case LOK_CALLBACK_CELL_VIEW_CURSOR:
1132  case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
1133  case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
1134  case LOK_CALLBACK_TEXT_VIEW_SELECTION:
1135  case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
1136  {
1137  const int nViewId = lcl_getViewId(payload);
1138  removeAll(
1139  [type, nViewId] (const queue_type::value_type& elem) {
1140  return (elem.Type == type && nViewId == lcl_getViewId(elem));
1141  }
1142  );
1143  }
1144  break;
1145 
1146  case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
1147  {
1148  removeAll(
1149  [type, &payload] (const queue_type::value_type& elem) {
1150  return (elem.Type == type && elem.PayloadString == payload);
1151  }
1152  );
1153  }
1154  break;
1155 
1156  case LOK_CALLBACK_INVALIDATE_TILES:
1157  {
1158  RectangleAndPart& rcNew = aCallbackData.setRectangleAndPart(payload);
1159  if (rcNew.isEmpty())
1160  {
1161  SAL_INFO("lok", "Skipping invalid event [" << type << "]: [" << payload << "].");
1162  return;
1163  }
1164 
1165  // If we have to invalidate all tiles, we can skip any new tile invalidation.
1166  // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
1167  const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(),
1168  [] (const queue_type::value_type& elem) { return (elem.Type == LOK_CALLBACK_INVALIDATE_TILES); });
1169  if (pos != m_queue.rend())
1170  {
1171  const RectangleAndPart& rcOld = pos->getRectangleAndPart();
1172  if (rcOld.isInfinite() && (rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart))
1173  {
1174  SAL_INFO("lok", "Skipping queue [" << type << "]: [" << payload << "] since all tiles need to be invalidated.");
1175  return;
1176  }
1177 
1178  if (rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart)
1179  {
1180  // If fully overlapping.
1181  if (rcOld.m_aRectangle.IsInside(rcNew.m_aRectangle))
1182  {
1183  SAL_INFO("lok", "Skipping queue [" << type << "]: [" << payload << "] since overlaps existing all-parts.");
1184  return;
1185  }
1186  }
1187  }
1188 
1189  if (rcNew.isInfinite())
1190  {
1191  SAL_INFO("lok", "Have Empty [" << type << "]: [" << payload << "] so removing all with part " << rcNew.m_nPart << ".");
1192  removeAll(
1193  [&rcNew] (const queue_type::value_type& elem) {
1194  if (elem.Type == LOK_CALLBACK_INVALIDATE_TILES)
1195  {
1196  // Remove exiting if new is all-encompassing, or if of the same part.
1197  const RectangleAndPart rcOld = RectangleAndPart::Create(elem.PayloadString);
1198  return (rcNew.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart);
1199  }
1200 
1201  // Keep others.
1202  return false;
1203  }
1204  );
1205  }
1206  else
1207  {
1208  const auto rcOrig = rcNew;
1209 
1210  SAL_INFO("lok", "Have [" << type << "]: [" << payload << "] so merging overlapping.");
1211  removeAll(
1212  [&rcNew] (const queue_type::value_type& elem) {
1213  if (elem.Type == LOK_CALLBACK_INVALIDATE_TILES)
1214  {
1215  const RectangleAndPart& rcOld = elem.getRectangleAndPart();
1216  if (rcNew.m_nPart != -1 && rcOld.m_nPart != -1 && rcOld.m_nPart != rcNew.m_nPart)
1217  {
1218  SAL_INFO("lok", "Nothing to merge between new: " << rcNew.toString() << ", and old: " << rcOld.toString());
1219  return false;
1220  }
1221 
1222  if (rcNew.m_nPart == -1)
1223  {
1224  // Don't merge unless fully overlapped.
1225  SAL_INFO("lok", "New " << rcNew.toString() << " has " << rcOld.toString() << "?");
1226  if (rcNew.m_aRectangle.IsInside(rcOld.m_aRectangle))
1227  {
1228  SAL_INFO("lok", "New " << rcNew.toString() << " engulfs old " << rcOld.toString() << ".");
1229  return true;
1230  }
1231  }
1232  else if (rcOld.m_nPart == -1)
1233  {
1234  // Don't merge unless fully overlapped.
1235  SAL_INFO("lok", "Old " << rcOld.toString() << " has " << rcNew.toString() << "?");
1236  if (rcOld.m_aRectangle.IsInside(rcNew.m_aRectangle))
1237  {
1238  SAL_INFO("lok", "New " << rcNew.toString() << " engulfs old " << rcOld.toString() << ".");
1239  return true;
1240  }
1241  }
1242  else
1243  {
1244  const tools::Rectangle rcOverlap = rcNew.m_aRectangle.GetIntersection(rcOld.m_aRectangle);
1245  const bool bOverlap = !rcOverlap.IsEmpty();
1246  SAL_INFO("lok", "Merging " << rcNew.toString() << " & " << rcOld.toString() << " => " <<
1247  rcOverlap.toString() << " Overlap: " << bOverlap);
1248  if (bOverlap)
1249  {
1250  rcNew.m_aRectangle.Union(rcOld.m_aRectangle);
1251  SAL_INFO("lok", "Merged: " << rcNew.toString());
1252  return true;
1253  }
1254  }
1255  }
1256 
1257  // Keep others.
1258  return false;
1259  }
1260  );
1261 
1262  if (rcNew.m_aRectangle != rcOrig.m_aRectangle)
1263  {
1264  SAL_INFO("lok", "Replacing: " << rcOrig.toString() << " by " << rcNew.toString());
1265  if (rcNew.m_aRectangle.GetWidth() < rcOrig.m_aRectangle.GetWidth() ||
1266  rcNew.m_aRectangle.GetHeight() < rcOrig.m_aRectangle.GetHeight())
1267  {
1268  SAL_WARN("lok", "Error: merged rect smaller.");
1269  }
1270  }
1271  }
1272 
1273  aCallbackData.setRectangleAndPart(rcNew);
1274  }
1275  break;
1276 
1277  // State changes with same name override previous ones with a different value.
1278  // Ex. ".uno:PageStatus=Slide 20 of 83" overwrites any previous PageStatus.
1279  case LOK_CALLBACK_STATE_CHANGED:
1280  {
1281  // Compare the state name=value and overwrite earlier entries with same name.
1282  const auto pos = payload.find('=');
1283  if (pos != std::string::npos)
1284  {
1285  const std::string name = payload.substr(0, pos + 1);
1286  removeAll(
1287  [type, &name] (const queue_type::value_type& elem) {
1288  return (elem.Type == type) && (elem.PayloadString.compare(0, name.size(), name) == 0);
1289  }
1290  );
1291  }
1292  }
1293  break;
1294 
1295  case LOK_CALLBACK_WINDOW:
1296  {
1297  // reading JSON by boost might be slow?
1298  boost::property_tree::ptree& aTree = aCallbackData.setJson(payload);
1299  const unsigned nLOKWindowId = aTree.get<unsigned>("id", 0);
1300  if (aTree.get<std::string>("action", "") == "invalidate")
1301  {
1302  std::string aRectStr = aTree.get<std::string>("rectangle", "");
1303  // no 'rectangle' field => invalidate all of the window =>
1304  // remove all previous window part invalidations
1305  if (aRectStr.empty())
1306  {
1307  removeAll([&nLOKWindowId] (const queue_type::value_type& elem) {
1308  if (elem.Type == LOK_CALLBACK_WINDOW)
1309  {
1310  const boost::property_tree::ptree& aOldTree = elem.getJson();
1311  const unsigned nOldDialogId = aOldTree.get<unsigned>("id", 0);
1312  if (aOldTree.get<std::string>("action", "") == "invalidate" &&
1313  nLOKWindowId == nOldDialogId)
1314  {
1315  return true;
1316  }
1317  }
1318  return false;
1319  });
1320  }
1321  else
1322  {
1323  // if we have to invalidate all of the window, ignore
1324  // any part invalidation message
1325  const auto invAllExist = std::any_of(m_queue.rbegin(), m_queue.rend(),
1326  [&nLOKWindowId] (const queue_type::value_type& elem)
1327  {
1328  if (elem.Type != LOK_CALLBACK_WINDOW)
1329  return false;
1330 
1331  const boost::property_tree::ptree& aOldTree = elem.getJson();
1332  const unsigned nOldDialogId = aOldTree.get<unsigned>("id", 0);
1333  return aOldTree.get<std::string>("action", "") == "invalidate" &&
1334  nLOKWindowId == nOldDialogId &&
1335  aOldTree.get<std::string>("rectangle", "").empty();
1336  });
1337 
1338  // we found an invalidate-all window callback
1339  if (invAllExist)
1340  {
1341  SAL_INFO("lok.dialog", "Skipping queue [" << type << "]: [" << payload << "] since whole window needs to be invalidated.");
1342  return;
1343  }
1344 
1345  std::istringstream aRectStream(aRectStr);
1346  long nLeft, nTop, nWidth, nHeight;
1347  char nComma;
1348  aRectStream >> nLeft >> nComma >> nTop >> nComma >> nWidth >> nComma >> nHeight;
1349  tools::Rectangle aNewRect = tools::Rectangle(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
1350  bool currentIsRedundant = false;
1351  removeAll([&aNewRect, &nLOKWindowId, &currentIsRedundant] (const queue_type::value_type& elem) {
1352  if (elem.Type != LOK_CALLBACK_WINDOW)
1353  return false;
1354 
1355  const boost::property_tree::ptree& aOldTree = elem.getJson();
1356  if (aOldTree.get<std::string>("action", "") == "invalidate")
1357  {
1358  const unsigned nOldDialogId = aOldTree.get<unsigned>("id", 0);
1359  std::string aOldRectStr = aOldTree.get<std::string>("rectangle", "");
1360  // not possible that we encounter an empty
1361  // rectangle here; we already handled this
1362  // case before
1363  std::istringstream aOldRectStream(aOldRectStr);
1364  long nOldLeft, nOldTop, nOldWidth, nOldHeight;
1365  char nOldComma;
1366  aOldRectStream >> nOldLeft >> nOldComma >> nOldTop >> nOldComma >> nOldWidth >> nOldComma >> nOldHeight;
1367  tools::Rectangle aOldRect = tools::Rectangle(nOldLeft, nOldTop, nOldLeft + nOldWidth, nOldTop + nOldHeight);
1368 
1369  if (nLOKWindowId == nOldDialogId)
1370  {
1371  // new one engulfs the old one?
1372  if (aNewRect.IsInside(aOldRect))
1373  {
1374  SAL_INFO("lok.dialog", "New " << aNewRect.toString() << " engulfs old " << aOldRect.toString() << ".");
1375  return true;
1376  }
1377  // old one engulfs the new one?
1378  else if (aOldRect.IsInside(aNewRect))
1379  {
1380  SAL_INFO("lok.dialog", "Old " << aOldRect.toString() << " engulfs new " << aNewRect.toString() << ".");
1381  // we have a rectangle in the queue
1382  // already that makes the current
1383  // Callback useless
1384  currentIsRedundant = true;
1385  return false;
1386  }
1387  else
1388  {
1389  SAL_INFO("lok.dialog", "Merging " << aNewRect.toString() << " & " << aOldRect.toString());
1390  aNewRect.Union(aOldRect);
1391  SAL_INFO("lok.dialog", "Merged: " << aNewRect.toString());
1392  return true;
1393  }
1394  }
1395  }
1396 
1397  // keep rest
1398  return false;
1399  });
1400 
1401  if (currentIsRedundant)
1402  {
1403  SAL_INFO("lok.dialog", "Current payload is engulfed by one already in the queue. Skipping redundant payload: " << aNewRect.toString());
1404  return;
1405  }
1406 
1407  aTree.put("rectangle", aNewRect.toString().getStr());
1408  aCallbackData.setJson(aTree);
1409  assert(aCallbackData.validate() && "Validation after setJson failed!");
1410  }
1411  }
1412  }
1413  break;
1414  }
1415  }
1416 
1417  // Validate that the cached data and the payload string are identical.
1418  assert(aCallbackData.validate() && "Cached callback payload object and string mismatch!");
1419  m_queue.emplace_back(aCallbackData);
1420  SAL_INFO("lok", "Queued #" << (m_queue.size() - 1) <<
1421  " [" << type << "]: [" << payload << "] to have " << m_queue.size() << " entries.");
1422 
1423  lock.unlock();
1424  if (!IsActive())
1425  {
1426  Start();
1427  }
1428 }
1429 
1430 void CallbackFlushHandler::Invoke()
1431 {
1432  comphelper::ProfileZone aZone("CallbackFlushHander::Invoke");
1433 
1434  if (m_pCallback && !m_bEventLatch)
1435  {
1436  std::unique_lock<std::mutex> lock(m_mutex);
1437 
1438  SAL_INFO("lok", "Flushing " << m_queue.size() << " elements.");
1439  for (const auto& rCallbackData : m_queue)
1440  {
1441  const int type = rCallbackData.Type;
1442  const auto& payload = rCallbackData.PayloadString;
1443  const int viewId = lcl_isViewCallbackType(type) ? lcl_getViewId(rCallbackData) : -1;
1444 
1445  if (viewId == -1)
1446  {
1447  const auto stateIt = m_states.find(type);
1448  if (stateIt != m_states.end())
1449  {
1450  // If the state didn't change, it's safe to ignore.
1451  if (stateIt->second == payload)
1452  {
1453  SAL_INFO("lok", "Skipping duplicate [" << type << "]: [" << payload << "].");
1454  continue;
1455  }
1456 
1457  stateIt->second = payload;
1458  }
1459  }
1460  else
1461  {
1462  const auto statesIt = m_viewStates.find(viewId);
1463  if (statesIt != m_viewStates.end())
1464  {
1465  auto& states = statesIt->second;
1466  const auto stateIt = states.find(type);
1467  if (stateIt != states.end())
1468  {
1469  // If the state didn't change, it's safe to ignore.
1470  if (stateIt->second == payload)
1471  {
1472  SAL_INFO("lok", "Skipping view duplicate [" << type << ',' << viewId << "]: [" << payload << "].");
1473  continue;
1474  }
1475 
1476  SAL_INFO("lok", "Replacing an element in view states [" << type << ',' << viewId << "]: [" << payload << "].");
1477  stateIt->second = payload;
1478  }
1479  else
1480  {
1481  SAL_INFO("lok", "Inserted a new element in view states: [" << type << ',' << viewId << "]: [" << payload << "]");
1482  states.emplace(type, payload);
1483 
1484  }
1485  }
1486  }
1487 
1488  m_pCallback(type, payload.c_str(), m_pData);
1489  }
1490 
1491  m_queue.clear();
1492  }
1493 }
1494 
1495 void CallbackFlushHandler::removeAll(const std::function<bool (const CallbackFlushHandler::queue_type::value_type&)>& rTestFunc)
1496 {
1497  auto newEnd = std::remove_if(m_queue.begin(), m_queue.end(), rTestFunc);
1498  m_queue.erase(newEnd, m_queue.end());
1499 }
1500 
1502 {
1503  const auto& result = m_viewStates.emplace(viewId, decltype(m_viewStates)::mapped_type());
1504  if (!result.second && result.first != m_viewStates.end())
1505  {
1506  result.first->second.clear();
1507  }
1508 }
1509 
1511 {
1512  m_viewStates.erase(viewId);
1513 }
1514 
1515 
1516 static void doc_destroy(LibreOfficeKitDocument *pThis)
1517 {
1518  comphelper::ProfileZone aZone("doc_destroy");
1519 
1520  SolarMutexGuard aGuard;
1521 
1522  LibLODocument_Impl *pDocument = static_cast<LibLODocument_Impl*>(pThis);
1523  delete pDocument;
1524 }
1525 
1526 static void lo_destroy (LibreOfficeKit* pThis);
1527 static int lo_initialize (LibreOfficeKit* pThis, const char* pInstallPath, const char* pUserProfilePath);
1528 static LibreOfficeKitDocument* lo_documentLoad (LibreOfficeKit* pThis, const char* pURL);
1529 static char * lo_getError (LibreOfficeKit* pThis);
1530 static void lo_freeError (char* pFree);
1531 static LibreOfficeKitDocument* lo_documentLoadWithOptions (LibreOfficeKit* pThis,
1532  const char* pURL,
1533  const char* pOptions);
1534 static void lo_registerCallback (LibreOfficeKit* pThis,
1535  LibreOfficeKitCallback pCallback,
1536  void* pData);
1537 static char* lo_getFilterTypes(LibreOfficeKit* pThis);
1538 static void lo_setOptionalFeatures(LibreOfficeKit* pThis, unsigned long long features);
1539 static void lo_setDocumentPassword(LibreOfficeKit* pThis,
1540  const char* pURL,
1541  const char* pPassword);
1542 static char* lo_getVersionInfo(LibreOfficeKit* pThis);
1543 static int lo_runMacro (LibreOfficeKit* pThis, const char* pURL);
1544 
1545 static bool lo_signDocument(LibreOfficeKit* pThis,
1546  const char* pUrl,
1547  const unsigned char* pCertificateBinary,
1548  const int nCertificateBinarySize,
1549  const unsigned char* pPrivateKeyBinary,
1550  const int nPrivateKeyBinarySize);
1551 
1552 static void lo_runLoop(LibreOfficeKit* pThis,
1553  LibreOfficeKitPollCallback pPollCallback,
1554  LibreOfficeKitWakeCallback pWakeCallback,
1555  void* pData);
1556 
1558  : m_pOfficeClass( gOfficeClass.lock() )
1559  , maThread(nullptr)
1560  , mpCallback(nullptr)
1561  , mpCallbackData(nullptr)
1562  , mOptionalFeatures(0)
1563 {
1564  if(!m_pOfficeClass) {
1565  m_pOfficeClass.reset(new LibreOfficeKitClass);
1566  m_pOfficeClass->nSize = sizeof(LibreOfficeKitClass);
1567 
1568  m_pOfficeClass->destroy = lo_destroy;
1569  m_pOfficeClass->documentLoad = lo_documentLoad;
1570  m_pOfficeClass->getError = lo_getError;
1571  m_pOfficeClass->freeError = lo_freeError;
1572  m_pOfficeClass->documentLoadWithOptions = lo_documentLoadWithOptions;
1573  m_pOfficeClass->registerCallback = lo_registerCallback;
1574  m_pOfficeClass->getFilterTypes = lo_getFilterTypes;
1575  m_pOfficeClass->setOptionalFeatures = lo_setOptionalFeatures;
1576  m_pOfficeClass->setDocumentPassword = lo_setDocumentPassword;
1577  m_pOfficeClass->getVersionInfo = lo_getVersionInfo;
1578  m_pOfficeClass->runMacro = lo_runMacro;
1579  m_pOfficeClass->signDocument = lo_signDocument;
1580  m_pOfficeClass->runLoop = lo_runLoop;
1581 
1583  }
1584 
1585  pClass = m_pOfficeClass.get();
1586 }
1587 
1589 {
1590 }
1591 
1592 namespace
1593 {
1594 
1595 ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
1596 {
1597  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
1598  return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get());
1599 }
1600 
1601 } // anonymous namespace
1602 
1603 // Wonder global state ...
1604 static uno::Reference<css::uno::XComponentContext> xContext;
1605 static uno::Reference<css::lang::XMultiServiceFactory> xSFactory;
1606 static uno::Reference<css::lang::XMultiComponentFactory> xFactory;
1607 
1608 static LibreOfficeKitDocument* lo_documentLoad(LibreOfficeKit* pThis, const char* pURL)
1609 {
1610  return lo_documentLoadWithOptions(pThis, pURL, nullptr);
1611 }
1612 
1613 static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis, const char* pURL, const char* pOptions)
1614 {
1615  comphelper::ProfileZone aZone("lo_documentLoadWithOptions");
1616 
1617  SolarMutexGuard aGuard;
1618 
1619  LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
1620  pLib->maLastExceptionMsg.clear();
1621 
1622  OUString aURL(getAbsoluteURL(pURL));
1623  if (aURL.isEmpty())
1624  {
1625  pLib->maLastExceptionMsg = "Filename to load was not provided.";
1626  SAL_INFO("lok", "URL for load is empty");
1627  return nullptr;
1628  }
1629 
1630  pLib->maLastExceptionMsg.clear();
1631 
1632  if (!xContext.is())
1633  {
1634  pLib->maLastExceptionMsg = "ComponentContext is not available";
1635  SAL_INFO("lok", "ComponentContext is not available");
1636  return nullptr;
1637  }
1638 
1639  uno::Reference<frame::XDesktop2> xComponentLoader = frame::Desktop::create(xContext);
1640 
1641  if (!xComponentLoader.is())
1642  {
1643  pLib->maLastExceptionMsg = "ComponentLoader is not available";
1644  SAL_INFO("lok", "ComponentLoader is not available");
1645  return nullptr;
1646  }
1647 
1648  try
1649  {
1650  // 'Language=...' is an option that LOK consumes by itself, and does
1651  // not pass it as a parameter to the filter
1652  OUString aOptions = getUString(pOptions);
1653  const OUString aLanguage = extractParameter(aOptions, "Language");
1654 
1655  if (!aLanguage.isEmpty())
1656  {
1657  // use with care - it sets it for the entire core, not just the
1658  // document
1659  SvtSysLocaleOptions aSysLocaleOptions;
1660  aSysLocaleOptions.SetLocaleConfigString(aLanguage);
1661  aSysLocaleOptions.SetUILocaleConfigString(aLanguage);
1662  }
1663 
1664  uno::Sequence<css::beans::PropertyValue> aFilterOptions(2);
1665  aFilterOptions[0] = css::beans::PropertyValue( "FilterOptions",
1666  0,
1667  uno::makeAny(aOptions),
1668  beans::PropertyState_DIRECT_VALUE);
1669 
1670  rtl::Reference<LOKInteractionHandler> const pInteraction(
1671  new LOKInteractionHandler("load", pLib));
1672  auto const pair(pLib->mInteractionMap.insert(std::make_pair(aURL.toUtf8(), pInteraction)));
1673  comphelper::ScopeGuard const g([&] () {
1674  if (pair.second)
1675  {
1676  pLib->mInteractionMap.erase(aURL.toUtf8());
1677  }
1678  });
1679  uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction.get());
1680  aFilterOptions[1].Name = "InteractionHandler";
1681  aFilterOptions[1].Value <<= xInteraction;
1682 
1683  /* TODO
1684  sal_Int16 nMacroExecMode = document::MacroExecMode::USE_CONFIG;
1685  aFilterOptions[2].Name = "MacroExecutionMode";
1686  aFilterOptions[2].Value <<= nMacroExecMode;
1687 
1688  sal_Int16 nUpdateDoc = document::UpdateDocMode::ACCORDING_TO_CONFIG;
1689  aFilterOptions[3].Name = "UpdateDocMode";
1690  aFilterOptions[3].Value <<= nUpdateDoc;
1691  */
1692 
1693  uno::Reference<lang::XComponent> xComponent = xComponentLoader->loadComponentFromURL(
1694  aURL, "_blank", 0,
1695  aFilterOptions);
1696 
1697  assert(!xComponent.is() || pair.second); // concurrent loading of same URL ought to fail
1698 
1699  if (!xComponent.is())
1700  {
1701  pLib->maLastExceptionMsg = "loadComponentFromURL returned an empty reference";
1702  SAL_INFO("lok", "Document can't be loaded - " << pLib->maLastExceptionMsg);
1703  return nullptr;
1704  }
1705 
1706  LibLODocument_Impl* pDocument = new LibLODocument_Impl(xComponent);
1707  if (pLib->mpCallback)
1708  {
1709  int nState = doc_getSignatureState(pDocument);
1710  pLib->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS, OString::number(nState).getStr(), pLib->mpCallbackData);
1711  }
1712  return pDocument;
1713  }
1714  catch (const uno::Exception& exception)
1715  {
1716  pLib->maLastExceptionMsg = exception.Message;
1717  SAL_INFO("lok", "Document can't be loaded: " << exception);
1718  }
1719 
1720  return nullptr;
1721 }
1722 
1723 static int lo_runMacro(LibreOfficeKit* pThis, const char *pURL)
1724 {
1725  comphelper::ProfileZone aZone("lo_runMacro");
1726 
1727  SolarMutexGuard aGuard;
1728 
1729  LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
1730  pLib->maLastExceptionMsg.clear();
1731 
1732  OUString sURL( pURL, strlen(pURL), RTL_TEXTENCODING_UTF8 );
1733  if (sURL.isEmpty())
1734  {
1735  pLib->maLastExceptionMsg = "Macro to run was not provided.";
1736  SAL_INFO("lok", "Macro URL is empty");
1737  return false;
1738  }
1739 
1740  if (!sURL.startsWith("macro://"))
1741  {
1742  pLib->maLastExceptionMsg = "This doesn't look like macro URL";
1743  SAL_INFO("lok", "Macro URL is invalid");
1744  return false;
1745  }
1746 
1747  pLib->maLastExceptionMsg.clear();
1748 
1749  if (!xContext.is())
1750  {
1751  pLib->maLastExceptionMsg = "ComponentContext is not available";
1752  SAL_INFO("lok", "ComponentContext is not available");
1753  return false;
1754  }
1755 
1756  util::URL aURL;
1757  aURL.Complete = sURL;
1758 
1759  uno::Reference < util::XURLTransformer > xParser( util::URLTransformer::create( xContext ) );
1760 
1761  if( xParser.is() )
1762  xParser->parseStrict( aURL );
1763 
1764  uno::Reference<frame::XDesktop2> xComponentLoader = frame::Desktop::create(xContext);
1765 
1766  if (!xComponentLoader.is())
1767  {
1768  pLib->maLastExceptionMsg = "ComponentLoader is not available";
1769  SAL_INFO("lok", "ComponentLoader is not available");
1770  return false;
1771  }
1772 
1773  xFactory = xContext->getServiceManager();
1774 
1775  if (xFactory.is())
1776  {
1777  uno::Reference<frame::XDispatchProvider> xDP;
1778  xSFactory.set(xFactory, uno::UNO_QUERY_THROW);
1779  xDP.set( xSFactory->createInstance("com.sun.star.comp.sfx2.SfxMacroLoader"), uno::UNO_QUERY );
1780  uno::Reference<frame::XDispatch> xD = xDP->queryDispatch( aURL, OUString(), 0);
1781 
1782  if (!xD.is())
1783  {
1784  pLib->maLastExceptionMsg = "Macro loader is not available";
1785  SAL_INFO("lok", "Macro loader is not available");
1786  return false;
1787  }
1788 
1789  uno::Reference < frame::XSynchronousDispatch > xSyncDisp( xD, uno::UNO_QUERY_THROW );
1790  uno::Sequence<css::beans::PropertyValue> aEmpty;
1791  css::beans::PropertyValue aErr;
1792  uno::Any aRet = xSyncDisp->dispatchWithReturnValue( aURL, aEmpty );
1793  aRet >>= aErr;
1794 
1795  if (aErr.Name == "ErrorCode")
1796  {
1797  sal_uInt32 nErrCode = 0; // ERRCODE_NONE
1798  aErr.Value >>= nErrCode;
1799 
1800  pLib->maLastExceptionMsg = "An error occurred running macro (error code: " + OUString::number( nErrCode ) + ")";
1801  SAL_INFO("lok", "Macro execution terminated with error code " << nErrCode);
1802 
1803  return false;
1804  }
1805 
1806  return true;
1807  }
1808 
1809  return false;
1810 }
1811 
1812 static bool lo_signDocument(LibreOfficeKit* /*pThis*/,
1813  const char* pURL,
1814  const unsigned char* pCertificateBinary,
1815  const int nCertificateBinarySize,
1816  const unsigned char* pPrivateKeyBinary,
1817  const int nPrivateKeyBinarySize)
1818 {
1819  comphelper::ProfileZone aZone("lo_signDocument");
1820 
1821  OUString aURL(getAbsoluteURL(pURL));
1822  if (aURL.isEmpty())
1823  return false;
1824 
1825  if (!xContext.is())
1826  return false;
1827 
1828  uno::Sequence<sal_Int8> aCertificateSequence;
1829 
1830  std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize);
1831  std::string aCertificateBase64String = extractCertificate(aCertificateString);
1832  if (!aCertificateBase64String.empty())
1833  {
1834  OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String.c_str());
1835  comphelper::Base64::decode(aCertificateSequence, aBase64OUString);
1836  }
1837  else
1838  {
1839  aCertificateSequence.realloc(nCertificateBinarySize);
1840  std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.begin());
1841  }
1842 
1843  uno::Sequence<sal_Int8> aPrivateKeySequence;
1844  std::string aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary), nPrivateKeyBinarySize);
1845  std::string aPrivateKeyBase64String = extractPrivateKey(aPrivateKeyString);
1846  if (!aPrivateKeyBase64String.empty())
1847  {
1848  OUString aBase64OUString = OUString::createFromAscii(aPrivateKeyBase64String.c_str());
1849  comphelper::Base64::decode(aPrivateKeySequence, aBase64OUString);
1850  }
1851  else
1852  {
1853  aPrivateKeySequence.realloc(nPrivateKeyBinarySize);
1854  std::copy(pPrivateKeyBinary, pPrivateKeyBinary + nPrivateKeyBinarySize, aPrivateKeySequence.begin());
1855  }
1856 
1857  uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xContext);
1858  uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
1859  if (!xSecurityContext.is())
1860  return false;
1861 
1862  uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
1863  uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY);
1864 
1865  if (!xCertificateCreator.is())
1866  return false;
1867 
1868  uno::Reference<security::XCertificate> xCertificate = xCertificateCreator->createDERCertificateWithPrivateKey(aCertificateSequence, aPrivateKeySequence);
1869 
1870  if (!xCertificate.is())
1871  return false;
1872 
1873  sfx2::DocumentSigner aDocumentSigner(aURL);
1874  if (!aDocumentSigner.signDocument(xCertificate))
1875  return false;
1876 
1877  return true;
1878 }
1879 
1880 static void lo_registerCallback (LibreOfficeKit* pThis,
1881  LibreOfficeKitCallback pCallback,
1882  void* pData)
1883 {
1884  SolarMutexGuard aGuard;
1885 
1886  LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
1887  pLib->maLastExceptionMsg.clear();
1888 
1889  pLib->mpCallback = pCallback;
1890  pLib->mpCallbackData = pData;
1891 }
1892 
1893 static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const char* pFormat, const char* pFilterOptions)
1894 {
1895  comphelper::ProfileZone aZone("doc_saveAs");
1896 
1897  SolarMutexGuard aGuard;
1899 
1900  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
1901 
1902  OUString sFormat = getUString(pFormat);
1903  OUString aURL(getAbsoluteURL(sUrl));
1904  if (aURL.isEmpty())
1905  {
1906  SetLastExceptionMsg("Filename to save to was not provided.");
1907  SAL_INFO("lok", "URL for save is empty");
1908  return false;
1909  }
1910 
1911  try
1912  {
1913  const ExtensionMap* pMap;
1914 
1915  switch (doc_getDocumentType(pThis))
1916  {
1917  case LOK_DOCTYPE_SPREADSHEET:
1918  pMap = aCalcExtensionMap;
1919  break;
1920  case LOK_DOCTYPE_PRESENTATION:
1921  pMap = aImpressExtensionMap;
1922  break;
1923  case LOK_DOCTYPE_DRAWING:
1924  pMap = aDrawExtensionMap;
1925  break;
1926  case LOK_DOCTYPE_TEXT:
1927  pMap = aWriterExtensionMap;
1928  break;
1929  case LOK_DOCTYPE_OTHER:
1930  default:
1931  SAL_INFO("lok", "Can't save document - unsupported document type.");
1932  return false;
1933  }
1934 
1935  if (pFormat == nullptr)
1936  {
1937  // sniff from the extension
1938  sal_Int32 idx = aURL.lastIndexOf(".");
1939  if( idx > 0 )
1940  {
1941  sFormat = aURL.copy( idx + 1 );
1942  }
1943  else
1944  {
1945  SetLastExceptionMsg("input filename without a suffix");
1946  return false;
1947  }
1948  }
1949 
1950  OUString aFilterName;
1951  for (sal_Int32 i = 0; pMap[i].extn; ++i)
1952  {
1953  if (sFormat.equalsIgnoreAsciiCaseAscii(pMap[i].extn))
1954  {
1955  aFilterName = getUString(pMap[i].filterName);
1956  break;
1957  }
1958  }
1959  if (aFilterName.isEmpty())
1960  {
1961  SetLastExceptionMsg("no output filter found for provided suffix");
1962  return false;
1963  }
1964 
1965  OUString aFilterOptions = getUString(pFilterOptions);
1966 
1967  // Check if watermark for pdf is passed by filteroptions..
1968  // It is not a real filter option so it must be filtered out.
1969  OUString watermarkText;
1970  int aIndex = -1;
1971  if ((aIndex = aFilterOptions.indexOf(",Watermark=")) >= 0)
1972  {
1973  int bIndex = aFilterOptions.indexOf("WATERMARKEND");
1974  watermarkText = aFilterOptions.copy(aIndex+11, bIndex-(aIndex+11));
1975  if(aIndex > 0)
1976  {
1977  OUString temp = aFilterOptions.copy(0, aIndex);
1978  aFilterOptions = temp + aFilterOptions.copy(bIndex+12);
1979  }
1980  else
1981  {
1982  aFilterOptions.clear();
1983  }
1984  }
1985 
1986  // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
1987  // gets a new name). When this is not provided, the meaning of
1988  // saveAs() is more like save-a-copy, which allows saving to any
1989  // random format like PDF or PNG.
1990  // It is not a real filter option, so we have to filter it out.
1991  uno::Sequence<OUString> aOptionSeq = comphelper::string::convertCommaSeparated(aFilterOptions);
1992  std::vector<OUString> aFilteredOptionVec;
1993  bool bTakeOwnership = false;
1994  MediaDescriptor aSaveMediaDescriptor;
1995  for (const auto& rOption : aOptionSeq)
1996  {
1997  if (rOption == "TakeOwnership")
1998  bTakeOwnership = true;
1999  else if (rOption == "NoFileSync")
2000  aSaveMediaDescriptor["NoFileSync"] <<= true;
2001  else
2002  aFilteredOptionVec.push_back(rOption);
2003  }
2004 
2005  aSaveMediaDescriptor["Overwrite"] <<= true;
2006  aSaveMediaDescriptor["FilterName"] <<= aFilterName;
2007 
2008  auto aFilteredOptionSeq = comphelper::containerToSequence<OUString>(aFilteredOptionVec);
2009  aFilterOptions = comphelper::string::convertCommaSeparated(aFilteredOptionSeq);
2010  aSaveMediaDescriptor[MediaDescriptor::PROP_FILTEROPTIONS()] <<= aFilterOptions;
2011  if(!watermarkText.isEmpty())
2012  {
2013  uno::Sequence< beans::PropertyValue > aFilterData( 1 );
2014  aFilterData[ 0 ].Name = "TiledWatermark";
2015  aFilterData[ 0 ].Value <<= watermarkText;
2016  aSaveMediaDescriptor["FilterData"] <<= aFilterData;
2017  }
2018 
2019  // add interaction handler too
2020  if (gImpl)
2021  {
2022  // gImpl does not have to exist when running from an unit test
2023  rtl::Reference<LOKInteractionHandler> const pInteraction(
2024  new LOKInteractionHandler("saveas", gImpl, pDocument));
2025  uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction.get());
2026 
2027  aSaveMediaDescriptor[MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteraction;
2028  }
2029 
2030  uno::Reference<frame::XStorable> xStorable(pDocument->mxComponent, uno::UNO_QUERY_THROW);
2031 
2032  if (bTakeOwnership)
2033  xStorable->storeAsURL(aURL, aSaveMediaDescriptor.getAsConstPropertyValueList());
2034  else
2035  xStorable->storeToURL(aURL, aSaveMediaDescriptor.getAsConstPropertyValueList());
2036 
2037  return true;
2038  }
2039  catch (const uno::Exception& exception)
2040  {
2041  SetLastExceptionMsg("exception: " + exception.Message);
2042  }
2043  return false;
2044 }
2045 
2046 static void doc_iniUnoCommands ()
2047 {
2048  SolarMutexGuard aGuard;
2050 
2051  OUString sUnoCommands[] =
2052  {
2053  OUString(".uno:AlignLeft"),
2054  OUString(".uno:AlignHorizontalCenter"),
2055  OUString(".uno:AlignRight"),
2056  OUString(".uno:BackColor"),
2057  OUString(".uno:BackgroundColor"),
2058  OUString(".uno:TableCellBackgroundColor"),
2059  OUString(".uno:Bold"),
2060  OUString(".uno:CenterPara"),
2061  OUString(".uno:CharBackColor"),
2062  OUString(".uno:CharBackgroundExt"),
2063  OUString(".uno:CharFontName"),
2064  OUString(".uno:Color"),
2065  OUString(".uno:ControlCodes"),
2066  OUString(".uno:DecrementIndent"),
2067  OUString(".uno:DefaultBullet"),
2068  OUString(".uno:DefaultNumbering"),
2069  OUString(".uno:FontColor"),
2070  OUString(".uno:FontHeight"),
2071  OUString(".uno:IncrementIndent"),
2072  OUString(".uno:Italic"),
2073  OUString(".uno:JustifyPara"),
2074  OUString(".uno:OutlineFont"),
2075  OUString(".uno:LeftPara"),
2076  OUString(".uno:LanguageStatus"),
2077  OUString(".uno:RightPara"),
2078  OUString(".uno:Shadowed"),
2079  OUString(".uno:SubScript"),
2080  OUString(".uno:SuperScript"),
2081  OUString(".uno:Strikeout"),
2082  OUString(".uno:StyleApply"),
2083  OUString(".uno:Underline"),
2084  OUString(".uno:ModifiedStatus"),
2085  OUString(".uno:Undo"),
2086  OUString(".uno:Redo"),
2087  OUString(".uno:InsertPage"),
2088  OUString(".uno:DeletePage"),
2089  OUString(".uno:DuplicatePage"),
2090  OUString(".uno:Cut"),
2091  OUString(".uno:Copy"),
2092  OUString(".uno:Paste"),
2093  OUString(".uno:SelectAll"),
2094  OUString(".uno:InsertAnnotation"),
2095  OUString(".uno:DeleteAnnotation"),
2096  OUString(".uno:ReplyComment"),
2097  OUString(".uno:InsertRowsBefore"),
2098  OUString(".uno:InsertRowsAfter"),
2099  OUString(".uno:InsertColumnsBefore"),
2100  OUString(".uno:InsertColumnsAfter"),
2101  OUString(".uno:DeleteRows"),
2102  OUString(".uno:DeleteColumns"),
2103  OUString(".uno:DeleteTable"),
2104  OUString(".uno:SelectTable"),
2105  OUString(".uno:EntireRow"),
2106  OUString(".uno:EntireColumn"),
2107  OUString(".uno:EntireCell"),
2108  OUString(".uno:AssignLayout"),
2109  OUString(".uno:StatusDocPos"),
2110  OUString(".uno:RowColSelCount"),
2111  OUString(".uno:StatusPageStyle"),
2112  OUString(".uno:InsertMode"),
2113  OUString(".uno:SpellOnline"),
2114  OUString(".uno:StatusSelectionMode"),
2115  OUString(".uno:StateTableCell"),
2116  OUString(".uno:StatusBarFunc"),
2117  OUString(".uno:StatePageNumber"),
2118  OUString(".uno:StateWordCount"),
2119  OUString(".uno:SelectionMode"),
2120  OUString(".uno:PageStatus"),
2121  OUString(".uno:LayoutStatus"),
2122  OUString(".uno:Context"),
2123  OUString(".uno:WrapText"),
2124  OUString(".uno:ToggleMergeCells"),
2125  OUString(".uno:NumberFormatCurrency"),
2126  OUString(".uno:NumberFormatPercent"),
2127  OUString(".uno:NumberFormatDate"),
2128  OUString(".uno:SortAscending"),
2129  OUString(".uno:SortDescending"),
2130  OUString(".uno:TrackChanges"),
2131  OUString(".uno:ShowTrackedChanges"),
2132  OUString(".uno:NextTrackedChange"),
2133  OUString(".uno:PreviousTrackedChange"),
2134  OUString(".uno:AcceptAllTrackedChanges"),
2135  OUString(".uno:RejectAllTrackedChanges"),
2136  OUString(".uno:TableDialog"),
2137  OUString(".uno:FormatCellDialog"),
2138  OUString(".uno:FontDialog"),
2139  OUString(".uno:ParagraphDialog"),
2140  OUString(".uno:OutlineBullet"),
2141  OUString(".uno:InsertIndexesEntry"),
2142  OUString(".uno:DocumentRepair"),
2143  OUString(".uno:TransformDialog"),
2144  OUString(".uno:InsertPageHeader"),
2145  OUString(".uno:InsertPageFooter"),
2146  OUString(".uno:OnlineAutoFormat"),
2147  OUString(".uno:InsertSymbol"),
2148  OUString(".uno:EditRegion"),
2149  OUString(".uno:ThesaurusDialog")
2150  };
2151 
2152  util::URL aCommandURL;
2153  SfxViewShell* pViewShell = SfxViewShell::Current();
2154  SfxViewFrame* pViewFrame = pViewShell? pViewShell->GetViewFrame(): nullptr;
2155 
2156  // check if Frame-Controller were created.
2157  if (!pViewShell && !pViewFrame)
2158  {
2159  SAL_WARN("lok", "iniUnoCommands: No Frame-Controller created.");
2160  return;
2161  }
2162 
2163  if (!xContext.is())
2165  if (!xContext.is())
2166  {
2167  SAL_WARN("lok", "iniUnoCommands: Component context is not available");
2168  return;
2169  }
2170 
2171  SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool(pViewFrame);
2172  uno::Reference<util::XURLTransformer> xParser(util::URLTransformer::create(xContext));
2173 
2174  for (const auto & sUnoCommand : sUnoCommands)
2175  {
2176  const SfxSlot* pSlot = nullptr;
2177 
2178  aCommandURL.Complete = sUnoCommand;
2179  xParser->parseStrict(aCommandURL);
2180  pSlot = rSlotPool.GetUnoSlot(aCommandURL.Path);
2181 
2182  // when null, this command is not supported by the given component
2183  // (like eg. Calc does not have ".uno:DefaultBullet" etc.)
2184  if (pSlot)
2185  {
2186  // Initialize slot to dispatch .uno: Command.
2187  pViewFrame->GetBindings().GetDispatch(pSlot, aCommandURL, false);
2188  }
2189  }
2190 }
2191 
2192 static int doc_getDocumentType (LibreOfficeKitDocument* pThis)
2193 {
2194  comphelper::ProfileZone aZone("doc_getDocumentType");
2195 
2196  SolarMutexGuard aGuard;
2198 
2199  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
2200 
2201  try
2202  {
2203  uno::Reference<lang::XServiceInfo> xDocument(pDocument->mxComponent, uno::UNO_QUERY_THROW);
2204 
2205  if (xDocument->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
2206  {
2207  return LOK_DOCTYPE_SPREADSHEET;
2208  }
2209  else if (xDocument->supportsService("com.sun.star.presentation.PresentationDocument"))
2210  {
2211  return LOK_DOCTYPE_PRESENTATION;
2212  }
2213  else if (xDocument->supportsService("com.sun.star.drawing.DrawingDocument"))
2214  {
2215  return LOK_DOCTYPE_DRAWING;
2216  }
2217  else if (xDocument->supportsService("com.sun.star.text.TextDocument") || xDocument->supportsService("com.sun.star.text.WebDocument"))
2218  {
2219  return LOK_DOCTYPE_TEXT;
2220  }
2221  else
2222  {
2223  SetLastExceptionMsg("unknown document type");
2224  }
2225  }
2226  catch (const uno::Exception& exception)
2227  {
2228  SetLastExceptionMsg("exception: " + exception.Message);
2229  }
2230  return LOK_DOCTYPE_OTHER;
2231 }
2232 
2233 static int doc_getParts (LibreOfficeKitDocument* pThis)
2234 {
2235  comphelper::ProfileZone aZone("doc_getParts");
2236 
2237  SolarMutexGuard aGuard;
2238 
2239  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2240  if (!pDoc)
2241  {
2242  SetLastExceptionMsg("Document doesn't support tiled rendering");
2243  return 0;
2244  }
2245 
2246  return pDoc->getParts();
2247 }
2248 
2249 static int doc_getPart (LibreOfficeKitDocument* pThis)
2250 {
2251  comphelper::ProfileZone aZone("doc_getPart");
2252 
2253  SolarMutexGuard aGuard;
2255 
2256  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2257  if (!pDoc)
2258  {
2259  SetLastExceptionMsg("Document doesn't support tiled rendering");
2260  return 0;
2261  }
2262 
2263  return pDoc->getPart();
2264 }
2265 
2266 static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart)
2267 {
2268  comphelper::ProfileZone aZone("doc_setPart");
2269 
2270  SolarMutexGuard aGuard;
2272 
2273  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2274  if (!pDoc)
2275  {
2276  SetLastExceptionMsg("Document doesn't support tiled rendering");
2277  return;
2278  }
2279 
2280  pDoc->setPart( nPart );
2281 }
2282 
2283 static char* doc_getPartInfo(LibreOfficeKitDocument* pThis, int nPart)
2284 {
2285  comphelper::ProfileZone aZone("doc_getPartInfo");
2286 
2287  SolarMutexGuard aGuard;
2288  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2289  if (!pDoc)
2290  {
2291  SetLastExceptionMsg("Document doesn't support tiled rendering");
2292  return nullptr;
2293  }
2294 
2295  OUString aPartInfo = pDoc->getPartInfo( nPart );
2296  OString aString = OUStringToOString(aPartInfo, RTL_TEXTENCODING_UTF8);
2297 
2298  char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
2299  assert(pMemory); // Don't handle OOM conditions
2300  strcpy(pMemory, aString.getStr());
2301  return pMemory;
2302 }
2303 
2304 static char* doc_getPartPageRectangles(LibreOfficeKitDocument* pThis)
2305 {
2306  comphelper::ProfileZone aZone("doc_getPartPageRectangles");
2307 
2308  SolarMutexGuard aGuard;
2310 
2311  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2312  if (!pDoc)
2313  {
2314  SetLastExceptionMsg("Document doesn't support tiled rendering");
2315  return nullptr;
2316  }
2317 
2318  OUString sRectangles = pDoc->getPartPageRectangles();
2319  OString aString = OUStringToOString(sRectangles, RTL_TEXTENCODING_UTF8);
2320  char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
2321  assert(pMemory); // Don't handle OOM conditions
2322  strcpy(pMemory, aString.getStr());
2323  return pMemory;
2324 
2325 }
2326 
2327 static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart)
2328 {
2329  comphelper::ProfileZone aZone("doc_getPartName");
2330 
2331  SolarMutexGuard aGuard;
2333 
2334  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2335  if (!pDoc)
2336  {
2337  SetLastExceptionMsg("Document doesn't support tiled rendering");
2338  return nullptr;
2339  }
2340 
2341  OUString sName = pDoc->getPartName( nPart );
2342  OString aString = OUStringToOString(sName, RTL_TEXTENCODING_UTF8);
2343  char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
2344  assert(pMemory); // Don't handle OOM conditions
2345  strcpy(pMemory, aString.getStr());
2346  return pMemory;
2347 
2348 }
2349 
2350 static char* doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart)
2351 {
2352  comphelper::ProfileZone aZone("doc_getPartHash");
2353 
2354  SolarMutexGuard aGuard;
2356 
2357  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2358  if (!pDoc)
2359  {
2360  SetLastExceptionMsg("Document doesn't support tiled rendering");
2361  return nullptr;
2362  }
2363 
2364  OUString sHash = pDoc->getPartHash(nPart);
2365  OString aString = OUStringToOString(sHash, RTL_TEXTENCODING_UTF8);
2366  char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
2367  assert(pMemory); // Don't handle OOM conditions
2368  strcpy(pMemory, aString.getStr());
2369  return pMemory;
2370 
2371 }
2372 
2373 static void doc_setPartMode(LibreOfficeKitDocument* pThis,
2374  int nPartMode)
2375 {
2376  comphelper::ProfileZone aZone("doc_setPartMode");
2377 
2378  SolarMutexGuard aGuard;
2380 
2381  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2382  if (!pDoc)
2383  {
2384  SetLastExceptionMsg("Document doesn't support tiled rendering");
2385  return;
2386  }
2387 
2388 
2389  int nCurrentPart = pDoc->getPart();
2390 
2391  pDoc->setPartMode(nPartMode);
2392 
2393  // We need to make sure the internal state is updated, just changing the mode
2394  // might not update the relevant shells (i.e. impress will keep rendering the
2395  // previous mode unless we do this).
2396  // TODO: we might want to do this within the relevant components rather than
2397  // here, but that's also dependent on how we implement embedded object
2398  // rendering I guess?
2399  // TODO: we could be clever and e.g. set to 0 when we change to/from
2400  // embedded object mode, and not when changing between slide/notes/combined
2401  // modes?
2402  if ( nCurrentPart < pDoc->getParts() )
2403  {
2404  pDoc->setPart( nCurrentPart );
2405  }
2406  else
2407  {
2408  pDoc->setPart( 0 );
2409  }
2410 }
2411 
2412 #if defined(ANDROID)
2413 bool android_lok_from_jni = false;
2417 #endif
2418 
2419 static void doc_paintTile(LibreOfficeKitDocument* pThis,
2420  unsigned char* pBuffer,
2421  const int nCanvasWidth, const int nCanvasHeight,
2422  const int nTilePosX, const int nTilePosY,
2423  const int nTileWidth, const int nTileHeight)
2424 {
2425  comphelper::ProfileZone aZone("doc_paintTile");
2426 
2427  SolarMutexGuard aGuard;
2429 
2430  SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth << "x" << nTileHeight <<
2431  "]@(" << nTilePosX << ", " << nTilePosY << ") to [" <<
2432  nCanvasWidth << "x" << nCanvasHeight << "]px" );
2433 
2434  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2435  if (!pDoc)
2436  {
2437  SetLastExceptionMsg("Document doesn't support tiled rendering");
2438  return;
2439  }
2440 
2441 #if defined(UNX) && !defined(MACOSX) && !defined(ENABLE_HEADLESS)
2442 
2443  // Painting of zoomed or HiDPI spreadsheets is special, we actually draw everything at 100%,
2444  // and only set cairo's (or CoreGraphic's, in the iOS case) scale factor accordingly, so that
2445  // everything is painted bigger or smaller. This is different to what Calc's internal scaling
2446  // would do - because that one is trying to fit the lines between cells to integer multiples of
2447  // pixels.
2449  double fDPIScaleX = 1;
2450  if (doc_getDocumentType(pThis) == LOK_DOCTYPE_SPREADSHEET)
2451  {
2452  fDPIScaleX = (nCanvasWidth * 3840.0) / (256.0 * nTileWidth);
2453  assert(fabs(fDPIScaleX - ((nCanvasHeight * 3840.0) / (256.0 * nTileHeight))) < 0.0001);
2455  }
2456 
2457 #if defined(IOS)
2458  CGContextRef cgc = CGBitmapContextCreate(pBuffer, nCanvasWidth, nCanvasHeight, 8, nCanvasWidth*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst | kCGImageByteOrder32Little);
2459 
2460  // Use the vcl.cg tag even if this code is not in vcl, to match all other SAL_INFO logging about Core Graphics, in vcl.
2461  SAL_INFO( "vcl.cg", "CGBitmapContextCreate(" << nCanvasWidth << "x" << nCanvasHeight << "x32) = " << cgc );
2462 
2463  CGContextTranslateCTM(cgc, 0, nCanvasHeight);
2464  CGContextScaleCTM(cgc, fDPIScaleX, -fDPIScaleX);
2465 
2466  doc_paintTileToCGContext(pThis, (void*) cgc, nCanvasWidth, nCanvasHeight, nTilePosX, nTilePosY, nTileWidth, nTileHeight);
2467 
2468  SAL_INFO( "vcl.cg", "CGContextRelease(" << cgc << ")" );
2469  CGContextRelease(cgc);
2470 
2471 #else
2472  ScopedVclPtrInstance< VirtualDevice > pDevice(nullptr, Size(1, 1), DeviceFormat::DEFAULT) ;
2473 
2474 #if defined(ANDROID)
2475  if (!android_lok_from_jni)
2476 #endif
2477  {
2478  // Set background to transparent by default.
2479  // [Unless it is the 'old' (JNI-based) Android app - no idea why it
2480  // needs avoiding this.]
2481  pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
2482  }
2483 
2484  pDevice->SetOutputSizePixelScaleOffsetAndBuffer(
2485  Size(nCanvasWidth, nCanvasHeight), Fraction(1.0), Point(),
2486  pBuffer);
2487 
2488  pDoc->paintTile(*pDevice, nCanvasWidth, nCanvasHeight,
2489  nTilePosX, nTilePosY, nTileWidth, nTileHeight);
2490 
2491  static bool bDebug = getenv("LOK_DEBUG_TILES") != nullptr;
2492  if (bDebug)
2493  {
2494  // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
2495  tools::Rectangle aRect(0, 0, 5, 5);
2496  aRect = pDevice->PixelToLogic(aRect);
2497  pDevice->Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
2498  pDevice->SetFillColor(COL_LIGHTRED);
2499  pDevice->SetLineColor();
2500  pDevice->DrawRect(aRect);
2501  pDevice->Pop();
2502  }
2503 #endif
2504 
2505 #else
2506  (void) pBuffer;
2507 #endif
2508 }
2509 
2510 #ifdef IOS
2511 
2512 // This function is separate only to be used by LibreOfficeLight. If that app can be retired, this
2513 // function's code can be inlined into the iOS part of doc_paintTile().
2514 
2515 static void doc_paintTileToCGContext(LibreOfficeKitDocument* pThis,
2516  void* rCGContext,
2517  const int nCanvasWidth, const int nCanvasHeight,
2518  const int nTilePosX, const int nTilePosY,
2519  const int nTileWidth, const int nTileHeight)
2520 {
2521  SolarMutexGuard aGuard;
2523 
2524  SAL_INFO( "lok.tiledrendering", "paintTileToCGContext: painting [" << nTileWidth << "x" << nTileHeight <<
2525  "]@(" << nTilePosX << ", " << nTilePosY << ") to [" <<
2526  nCanvasWidth << "x" << nCanvasHeight << "]px" );
2527 
2528  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2529  if (!pDoc)
2530  {
2531  SetLastExceptionMsg("Document doesn't support tiled rendering");
2532  return;
2533  }
2534 
2536  aData.rCGContext = reinterpret_cast<CGContextRef>(rCGContext);
2537  // the Size argument is irrelevant, I hope
2538  ScopedVclPtrInstance<VirtualDevice> pDevice(&aData, Size(1, 1), DeviceFormat::DEFAULT);
2539 
2540  pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
2541 
2542  pDevice->SetOutputSizePixel(Size(nCanvasWidth, nCanvasHeight));
2543 
2544  pDoc->paintTile(*pDevice, nCanvasWidth, nCanvasHeight,
2545  nTilePosX, nTilePosY, nTileWidth, nTileHeight);
2546 
2547 }
2548 
2549 #endif
2550 
2551 static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
2552  unsigned char* pBuffer,
2553  const int nPart,
2554  const int nCanvasWidth, const int nCanvasHeight,
2555  const int nTilePosX, const int nTilePosY,
2556  const int nTileWidth, const int nTileHeight)
2557 {
2558  comphelper::ProfileZone aZone("doc_paintPartTile");
2559 
2560  SolarMutexGuard aGuard;
2562 
2563  SAL_INFO( "lok.tiledrendering", "paintPartTile: painting @ " << nPart << " ["
2564  << nTileWidth << "x" << nTileHeight << "]@("
2565  << nTilePosX << ", " << nTilePosY << ") to ["
2566  << nCanvasWidth << "x" << nCanvasHeight << "]px" );
2567 
2568  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
2569  int nOrigViewId = doc_getView(pThis);
2570 
2571  if (nOrigViewId < 0)
2572  {
2573  // tile painting always needs a SfxViewShell::Current(), but actually
2574  // it does not really matter which one - all of them should paint the
2575  // same thing.
2576  int viewCount = doc_getViewsCount(pThis);
2577  if (viewCount == 0)
2578  return;
2579 
2580  std::vector<int> viewIds(viewCount);
2581  doc_getViewIds(pThis, viewIds.data(), viewCount);
2582 
2583  nOrigViewId = viewIds[0];
2584  doc_setView(pThis, nOrigViewId);
2585  }
2586 
2587  // Disable callbacks while we are painting.
2588  if (nOrigViewId >= 0 && pDocument->mpCallbackFlushHandlers[nOrigViewId])
2589  pDocument->mpCallbackFlushHandlers[nOrigViewId]->setPartTilePainting(true);
2590 
2591  try
2592  {
2593  // Text documents have a single coordinate system; don't change part.
2594  int nOrigPart = 0;
2595  const bool isText = (doc_getDocumentType(pThis) == LOK_DOCTYPE_TEXT);
2596  int nViewId = nOrigViewId;
2597  if (!isText)
2598  {
2599  // Check if just switching to another view is enough, that has
2600  // less side-effects.
2601  if (nPart != doc_getPart(pThis))
2602  {
2603  SfxViewShell* pViewShell = SfxViewShell::GetFirst();
2604  while (pViewShell)
2605  {
2606  if (pViewShell->getPart() == nPart)
2607  {
2608  nViewId = static_cast<sal_Int32>(pViewShell->GetViewShellId());
2609  doc_setView(pThis, nViewId);
2610  break;
2611  }
2612  pViewShell = SfxViewShell::GetNext(*pViewShell);
2613  }
2614  }
2615 
2616  nOrigPart = doc_getPart(pThis);
2617  if (nPart != nOrigPart)
2618  {
2619  doc_setPart(pThis, nPart);
2620  }
2621  }
2622 
2623  doc_paintTile(pThis, pBuffer, nCanvasWidth, nCanvasHeight, nTilePosX, nTilePosY, nTileWidth, nTileHeight);
2624 
2625  if (!isText && nPart != nOrigPart)
2626  {
2627  doc_setPart(pThis, nOrigPart);
2628  }
2629  if (!isText && nViewId != nOrigViewId)
2630  {
2631  doc_setView(pThis, nOrigViewId);
2632  }
2633  }
2634  catch (const std::exception&)
2635  {
2636  // Nothing to do but restore the PartTilePainting flag.
2637  }
2638 
2639  if (nOrigViewId >= 0 && pDocument->mpCallbackFlushHandlers[nOrigViewId])
2640  pDocument->mpCallbackFlushHandlers[nOrigViewId]->setPartTilePainting(false);
2641 }
2642 
2643 static int doc_getTileMode(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/)
2644 {
2646  return LOK_TILEMODE_BGRA;
2647 }
2648 
2649 static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
2650  long* pWidth,
2651  long* pHeight)
2652 {
2653  comphelper::ProfileZone aZone("doc_getDocumentSize");
2654 
2655  SolarMutexGuard aGuard;
2657 
2658  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2659  if (pDoc)
2660  {
2661  Size aDocumentSize = pDoc->getDocumentSize();
2662  *pWidth = aDocumentSize.Width();
2663  *pHeight = aDocumentSize.Height();
2664  }
2665  else
2666  {
2667  SetLastExceptionMsg("Document doesn't support tiled rendering");
2668  }
2669 }
2670 
2671 static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
2672  const char* pArguments)
2673 {
2674  comphelper::ProfileZone aZone("doc_initializeForRendering");
2675 
2676  SolarMutexGuard aGuard;
2678 
2679  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2680  if (pDoc)
2681  {
2685  }
2686 }
2687 
2688 static void doc_registerCallback(LibreOfficeKitDocument* pThis,
2689  LibreOfficeKitCallback pCallback,
2690  void* pData)
2691 {
2692  SolarMutexGuard aGuard;
2694 
2695  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
2696 
2697  int nView = SfxLokHelper::getView();
2698  if (nView < 0)
2699  return;
2700 
2701  if (pCallback != nullptr)
2702  {
2703  size_t nId = nView;
2704  for (auto& pair : pDocument->mpCallbackFlushHandlers)
2705  {
2706  if (pair.first == nId)
2707  continue;
2708 
2709  pair.second->addViewStates(nView);
2710  }
2711  }
2712  else
2713  {
2714  size_t nId = nView;
2715  for (auto& pair : pDocument->mpCallbackFlushHandlers)
2716  {
2717  if (pair.first == nId)
2718  continue;
2719 
2720  pair.second->removeViewStates(nView);
2721  }
2722  }
2723 
2724  pDocument->mpCallbackFlushHandlers[nView].reset(new CallbackFlushHandler(pThis, pCallback, pData));
2725 
2726  if (pCallback != nullptr)
2727  {
2728  size_t nId = nView;
2729  for (const auto& pair : pDocument->mpCallbackFlushHandlers)
2730  {
2731  if (pair.first == nId)
2732  continue;
2733 
2734  pDocument->mpCallbackFlushHandlers[nView]->addViewStates(pair.first);
2735  }
2736  }
2737 
2738  if (SfxViewShell* pViewShell = SfxViewShell::Current())
2739  {
2740  pViewShell->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback, pDocument->mpCallbackFlushHandlers[nView].get());
2741  }
2742 }
2743 
2745 static char* getPostIts(LibreOfficeKitDocument* pThis)
2746 {
2748  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2749  if (!pDoc)
2750  {
2751  SetLastExceptionMsg("Document doesn't support tiled rendering");
2752  return nullptr;
2753  }
2754  OUString aComments = pDoc->getPostIts();
2755  return strdup(aComments.toUtf8().getStr());
2756 }
2757 
2759 static char* getPostItsPos(LibreOfficeKitDocument* pThis)
2760 {
2762  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2763  if (!pDoc)
2764  {
2765  SetLastExceptionMsg("Document doesn't support tiled rendering");
2766  return nullptr;
2767  }
2768  OUString aComments = pDoc->getPostItsPos();
2769  return strdup(aComments.toUtf8().getStr());
2770 }
2771 
2772 static char* getRulerState(LibreOfficeKitDocument* pThis)
2773 {
2775  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2776  if (!pDoc)
2777  {
2778  SetLastExceptionMsg("Document doesn't support tiled rendering");
2779  return nullptr;
2780  }
2781  OUString state = pDoc->getRulerState();
2782  return strdup(state.toUtf8().getStr());
2783 }
2784 
2785 static void doc_postKeyEvent(LibreOfficeKitDocument* pThis, int nType, int nCharCode, int nKeyCode)
2786 {
2787  comphelper::ProfileZone aZone("doc_postKeyEvent");
2788 
2789  SolarMutexGuard aGuard;
2791 
2792  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2793  if (!pDoc)
2794  {
2795  SetLastExceptionMsg("Document doesn't support tiled rendering");
2796  return;
2797  }
2798 
2799  pDoc->postKeyEvent(nType, nCharCode, nKeyCode);
2800 }
2801 
2802 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis, unsigned nWindowId, int nType, const char* pText)
2803 {
2804  comphelper::ProfileZone aZone("doc_postWindowExtTextInputEvent");
2805 
2806  SolarMutexGuard aGuard;
2807  VclPtr<vcl::Window> pWindow;
2808  if (nWindowId == 0)
2809  {
2810  ITiledRenderable* pDoc = getTiledRenderable(pThis);
2811  if (!pDoc)
2812  {
2813  SetLastExceptionMsg("Document doesn't support tiled rendering");
2814  return;
2815  }
2816  pWindow = pDoc->getDocWindow();
2817  }
2818  else
2819  {
2820  pWindow = vcl::Window::FindLOKWindow(nWindowId);
2821  }
2822 
2823  if (!pWindow)
2824  {
2825  SetLastExceptionMsg("No window found for window id: " + OUString::number(nWindowId));
2826  return;
2827  }
2828 
2829  switch (nType)
2830  {
2831  case LOK_EXT_TEXTINPUT:
2832  pWindow->PostExtTextInputEvent(VclEventId::ExtTextInput,
2833  OUString::fromUtf8(OString(pText, strlen(pText))));
2834  break;
2835  case LOK_EXT_TEXTINPUT_END:
2836  pWindow->PostExtTextInputEvent(VclEventId::EndExtTextInput,
2837  OUString::fromUtf8(OString(pText, strlen(pText))));
2838  break;
2839  default:
2840  assert(false && "Unhandled External Text input event!");
2841  }
2842 }
2843 
2844 static void doc_postWindowKeyEvent(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, int nType, int nCharCode, int nKeyCode)
2845 {
2846  comphelper::ProfileZone aZone("doc_postWindowKeyEvent");
2847 
2848  SolarMutexGuard aGuard;
2850 
2851  VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
2852  if (!pWindow)
2853  {
2854  SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
2855  return;
2856  }
2857 
2858  KeyEvent aEvent(nCharCode, nKeyCode, 0);
2859 
2860  switch (nType)
2861  {
2862  case LOK_KEYEVENT_KEYINPUT:
2863  Application::PostKeyEvent(VclEventId::WindowKeyInput, pWindow, &aEvent);
2864  break;
2865  case LOK_KEYEVENT_KEYUP:
2866  Application::PostKeyEvent(VclEventId::WindowKeyUp, pWindow, &aEvent);
2867  break;
2868  default:
2869  assert(false);
2870  break;
2871  }
2872 }
2873 
2874 static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOutput)
2875 {
2876  comphelper::ProfileZone aZone("doc_renderShapeSelection");
2877 
2878  SolarMutexGuard aGuard;
2880 
2881  LokChartHelper aChartHelper(SfxViewShell::Current());
2882 
2883  if (aChartHelper.GetWindow())
2884  return 0;
2885 
2886  try
2887  {
2888  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
2889 
2890  uno::Reference<frame::XStorable> xStorable(pDocument->mxComponent, uno::UNO_QUERY_THROW);
2891 
2892  SvMemoryStream aOutStream;
2893  uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aOutStream);
2894 
2895  utl::MediaDescriptor aMediaDescriptor;
2896  switch (doc_getDocumentType(pThis))
2897  {
2898  case LOK_DOCTYPE_PRESENTATION:
2899  aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export");
2900  break;
2901  case LOK_DOCTYPE_TEXT:
2902  aMediaDescriptor["FilterName"] <<= OUString("writer_svg_Export");
2903  break;
2904  case LOK_DOCTYPE_SPREADSHEET:
2905  aMediaDescriptor["FilterName"] <<= OUString("calc_svg_Export");
2906  break;
2907  default:
2908  SAL_WARN("lok", "Failed to render shape selection: Document type is not supported");
2909  }
2910  aMediaDescriptor["SelectionOnly"] <<= true;
2911  aMediaDescriptor["OutputStream"] <<= xOut;
2912 
2913  xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
2914 
2915  if (pOutput)
2916  {
2917  const size_t nOutputSize = aOutStream.GetEndOfData();
2918  *pOutput = static_cast<char*>(malloc(nOutputSize));
2919  if (*pOutput)
2920  {
2921  std::memcpy(*pOutput, aOutStream.GetData(), nOutputSize);
2922  return nOutputSize;
2923  }
2924  }
2925  }
2926  catch (const uno::Exception& exception)
2927  {
2928  css::uno::Any exAny( cppu::getCaughtException() );
2929  SetLastExceptionMsg(exception.Message);
2930  SAL_WARN("lok", "Failed to render shape selection: " << exceptionToString(exAny));
2931  }
2932 
2933  return 0;
2934 }
2935 
2943 class DispatchResultListener : public cppu::WeakImplHelper<css::frame::XDispatchResultListener>
2944 {
2945  OString maCommand;
2946  std::shared_ptr<CallbackFlushHandler> mpCallback;
2947 
2948 public:
2949  DispatchResultListener(const char* pCommand, std::shared_ptr<CallbackFlushHandler> const & pCallback)
2950  : maCommand(pCommand)
2951  , mpCallback(pCallback)
2952  {
2953  assert(mpCallback);
2954  }
2955 
2956  virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& rEvent) override
2957  {
2958  boost::property_tree::ptree aTree;
2959  aTree.put("commandName", maCommand.getStr());
2960 
2961  if (rEvent.State != frame::DispatchResultState::DONTKNOW)
2962  {
2963  bool bSuccess = (rEvent.State == frame::DispatchResultState::SUCCESS);
2964  aTree.put("success", bSuccess);
2965  }
2966 
2967  aTree.add_child("result", unoAnyToPropertyTree(rEvent.Result));
2968 
2969  std::stringstream aStream;
2970  boost::property_tree::write_json(aStream, aTree);
2971  OString aPayload = aStream.str().c_str();
2972  mpCallback->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aPayload.getStr());
2973  }
2974 
2975  virtual void SAL_CALL disposing(const css::lang::EventObject&) override {}
2976 };
2977 
2978 static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished)
2979 {
2980  comphelper::ProfileZone aZone("doc_postUnoCommand");
2981 
2982  SolarMutexGuard aGuard;
2984 
2986  OUString aCommand(pCommand, strlen(pCommand), RTL_TEXTENCODING_UTF8);
2987  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
2988 
2989  std::vector<beans::PropertyValue> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments));
2990 
2991  if (!vcl::lok::isUnipoll())
2992  {
2993  beans::PropertyValue aSynchronMode;
2994  aSynchronMode.Name = "SynchronMode";
2995  aSynchronMode.Value <<= false;
2996  aPropertyValuesVector.push_back(aSynchronMode);
2997  }
2998 
2999  int nView = SfxLokHelper::getView();
3000  if (nView < 0)
3001  return;
3002 
3003  // handle potential interaction
3004  if (gImpl && aCommand == ".uno:Save")
3005  {
3006  rtl::Reference<LOKInteractionHandler> const pInteraction(
3007  new LOKInteractionHandler("save", gImpl, pDocument));
3008  uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction.get());
3009 
3010  beans::PropertyValue aValue;
3011  aValue.Name = "InteractionHandler";
3012  aValue.Value <<= xInteraction;
3013  aPropertyValuesVector.push_back(aValue);
3014 
3015  bool bDontSaveIfUnmodified = false;
3016  aPropertyValuesVector.erase(std::remove_if(aPropertyValuesVector.begin(),
3017  aPropertyValuesVector.end(),
3018  [&bDontSaveIfUnmodified](const beans::PropertyValue& aItem){
3019  if (aItem.Name == "DontSaveIfUnmodified")
3020  {
3021  bDontSaveIfUnmodified = aItem.Value.get<bool>();
3022  return true;
3023  }
3024  return false;
3025  }), aPropertyValuesVector.end());
3026 
3027  // skip saving and tell the result via UNO_COMMAND_RESULT
3028  if (bDontSaveIfUnmodified && !pDocSh->IsModified())
3029  {
3030  boost::property_tree::ptree aTree;
3031  aTree.put("commandName", pCommand);
3032  aTree.put("success", false);
3033 
3034  // Add the reason for not saving
3035  const uno::Any aResultValue = uno::makeAny(OUString("unmodified"));
3036  aTree.add_child("result", unoAnyToPropertyTree(aResultValue));
3037 
3038  std::stringstream aStream;
3039  boost::property_tree::write_json(aStream, aTree);
3040  OString aPayload = aStream.str().c_str();
3041  pDocument->mpCallbackFlushHandlers[nView]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aPayload.getStr());
3042  return;
3043  }
3044  }
3045  else if (gImpl && aCommand == ".uno:TransformDialog")
3046  {
3047  bool bNeedConversion = false;
3048  SfxViewShell* pViewShell = SfxViewShell::Current();
3049  LokChartHelper aChartHelper(pViewShell);
3050 
3051  if (aChartHelper.GetWindow() )
3052  {
3053  bNeedConversion = true;
3054  }
3055  else if (const SdrView* pView = pViewShell->GetDrawView())
3056  {
3057  if (OutputDevice* pOutputDevice = pView->GetFirstOutputDevice())
3058  {
3059  bNeedConversion = (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM);
3060  }
3061  }
3062 
3063  if (bNeedConversion)
3064  {
3065  sal_Int32 value;
3066  for (beans::PropertyValue& rPropValue: aPropertyValuesVector)
3067  {
3068  if (rPropValue.Name == "TransformPosX"
3069  || rPropValue.Name == "TransformPosY"
3070  || rPropValue.Name == "TransformWidth"
3071  || rPropValue.Name == "TransformHeight"
3072  || rPropValue.Name == "TransformRotationX"
3073  || rPropValue.Name == "TransformRotationY")
3074  {
3075  rPropValue.Value >>= value;
3076  value = OutputDevice::LogicToLogic(value, MapUnit::MapTwip, MapUnit::Map100thMM);
3077  rPropValue.Value <<= value;
3078  }
3079  }
3080  }
3081 
3082  if (aChartHelper.GetWindow())
3083  {
3084  if (aPropertyValuesVector[0].Name != "Action")
3085  {
3086  tools::Rectangle aChartBB = aChartHelper.GetChartBoundingBox();
3087  int nLeft = OutputDevice::LogicToLogic(aChartBB.Left(), MapUnit::MapTwip, MapUnit::Map100thMM);
3088  int nTop = OutputDevice::LogicToLogic(aChartBB.Top(), MapUnit::MapTwip, MapUnit::Map100thMM);
3089 
3090  sal_Int32 value;
3091  for (beans::PropertyValue& rPropValue: aPropertyValuesVector)
3092  {
3093  if (rPropValue.Name == "TransformPosX" || rPropValue.Name == "TransformRotationX")
3094  {
3095  rPropValue.Value >>= value;
3096  rPropValue.Value <<= value - nLeft;
3097  }
3098  else if (rPropValue.Name == "TransformPosY" || rPropValue.Name == "TransformRotationY")
3099  {
3100  rPropValue.Value >>= value;
3101  rPropValue.Value <<= value - nTop;
3102  }
3103  }
3104  }
3105  util::URL aCommandURL;
3106  aCommandURL.Path = "LOKTransform";
3107  css::uno::Reference<css::frame::XDispatch>& aChartDispatcher = aChartHelper.GetXDispatcher();
3108  aChartDispatcher->dispatch(aCommandURL, comphelper::containerToSequence(aPropertyValuesVector));
3109  return;
3110  }
3111  }
3112 
3113  bool bResult = false;
3114  if (bNotifyWhenFinished && pDocument->mpCallbackFlushHandlers[nView])
3115  {
3116  bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector),
3117  new DispatchResultListener(pCommand, pDocument->mpCallbackFlushHandlers[nView]));
3118  }
3119  else
3120  bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector));
3121 
3122  if (!bResult)
3123  {
3124  SetLastExceptionMsg("Failed to dispatch the .uno: command");
3125  }
3126 }
3127 
3128 static void doc_postMouseEvent(LibreOfficeKitDocument* pThis, int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
3129 {
3130  comphelper::ProfileZone aZone("doc_postMouseEvent");
3131 
3132  SolarMutexGuard aGuard;
3134 
3135  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3136  if (!pDoc)
3137  {
3138  SetLastExceptionMsg("Document doesn't support tiled rendering");
3139  return;
3140  }
3141 
3142  pDoc->postMouseEvent(nType, nX, nY, nCount, nButtons, nModifier);
3143 }
3144 
3145 static void doc_postWindowMouseEvent(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
3146 {
3147  comphelper::ProfileZone aZone("doc_postWindowMouseEvent");
3148 
3149  SolarMutexGuard aGuard;
3151 
3152  VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
3153  if (!pWindow)
3154  {
3155  SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3156  return;
3157  }
3158 
3159  Point aPos(nX, nY);
3160  MouseEvent aEvent(aPos, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
3161 
3162  if (Dialog* pDialog = dynamic_cast<Dialog*>(pWindow.get()))
3163  {
3164  pDialog->EnableInput();
3165  }
3166 
3167  switch (nType)
3168  {
3169  case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
3170  Application::PostMouseEvent(VclEventId::WindowMouseButtonDown, pWindow, &aEvent);
3171  break;
3172  case LOK_MOUSEEVENT_MOUSEBUTTONUP:
3173  Application::PostMouseEvent(VclEventId::WindowMouseButtonUp, pWindow, &aEvent);
3174  break;
3175  case LOK_MOUSEEVENT_MOUSEMOVE:
3176  Application::PostMouseEvent(VclEventId::WindowMouseMove, pWindow, &aEvent);
3177  break;
3178  default:
3179  assert(false);
3180  break;
3181  }
3182 }
3183 
3184 static void doc_postWindowGestureEvent(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, const char* pType, int nX, int nY, int nOffset)
3185 {
3186  comphelper::ProfileZone aZone("doc_postWindowGestureEvent");
3187 
3188  SolarMutexGuard aGuard;
3190 
3191  VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
3192  if (!pWindow)
3193  {
3194  SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3195  return;
3196  }
3197 
3198  OString aType(pType);
3199  GestureEventType eEventType = GestureEventType::PanningUpdate;
3200 
3201  if (aType == "panBegin")
3202  eEventType = GestureEventType::PanningBegin;
3203  else if (aType == "panEnd")
3204  eEventType = GestureEventType::PanningEnd;
3205 
3206  GestureEvent aEvent {
3207  sal_Int32(nX),
3208  sal_Int32(nY),
3209  eEventType,
3210  sal_Int32(nOffset),
3211  PanningOrientation::Vertical,
3212  };
3213 
3214  if (Dialog* pDialog = dynamic_cast<Dialog*>(pWindow.get()))
3215  {
3216  pDialog->EnableInput();
3217  }
3218 
3219  Application::PostGestureEvent(VclEventId::WindowGestureEvent, pWindow, &aEvent);
3220 }
3221 
3222 static void doc_setTextSelection(LibreOfficeKitDocument* pThis, int nType, int nX, int nY)
3223 {
3224  comphelper::ProfileZone aZone("doc_setTextSelection");
3225 
3226  SolarMutexGuard aGuard;
3228 
3229  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3230  if (!pDoc)
3231  {
3232  SetLastExceptionMsg("Document doesn't support tiled rendering");
3233  return;
3234  }
3235 
3236  pDoc->setTextSelection(nType, nX, nY);
3237 }
3238 
3239 static char* doc_getTextSelection(LibreOfficeKitDocument* pThis, const char* pMimeType, char** pUsedMimeType)
3240 {
3241  comphelper::ProfileZone aZone("doc_getTextSelection");
3242 
3243  SolarMutexGuard aGuard;
3245 
3246  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3247  if (!pDoc)
3248  {
3249  SetLastExceptionMsg("Document doesn't support tiled rendering");
3250  return nullptr;
3251  }
3252 
3253  OString aUsedMimeType;
3254  OString aRet = pDoc->getTextSelection(pMimeType, aUsedMimeType);
3255  if (aUsedMimeType.isEmpty())
3256  aRet = pDoc->getTextSelection("text/plain;charset=utf-8", aUsedMimeType);
3257 
3258  char* pMemory = static_cast<char*>(malloc(aRet.getLength() + 1));
3259  assert(pMemory); // Don't handle OOM conditions
3260  strcpy(pMemory, aRet.getStr());
3261 
3262  if (pUsedMimeType)
3263  {
3264  *pUsedMimeType = static_cast<char*>(malloc(aUsedMimeType.getLength() + 1));
3265  strcpy(*pUsedMimeType, aUsedMimeType.getStr());
3266  }
3267 
3268  return pMemory;
3269 }
3270 
3271 static bool doc_paste(LibreOfficeKitDocument* pThis, const char* pMimeType, const char* pData, size_t nSize)
3272 {
3273  comphelper::ProfileZone aZone("doc_paste");
3274 
3275  SolarMutexGuard aGuard;
3277 
3278  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3279  if (!pDoc)
3280  {
3281  SetLastExceptionMsg("Document doesn't support tiled rendering");
3282  return false;
3283  }
3284 
3285  uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable(pMimeType, pData, nSize));
3286  uno::Reference<datatransfer::clipboard::XClipboard> xClipboard(new LOKClipboard);
3287  xClipboard->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
3288  pDoc->setClipboard(xClipboard);
3289  if (!pDoc->isMimeTypeSupported())
3290  {
3291  SetLastExceptionMsg("Document doesn't support this mime type");
3292  return false;
3293  }
3294 
3295  uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
3296  {
3297  {"AnchorType", uno::makeAny(static_cast<sal_uInt16>(text::TextContentAnchorType_AS_CHARACTER))},
3298  {"IgnoreComments", uno::makeAny(true)},
3299  }));
3300  if (!comphelper::dispatchCommand(".uno:Paste", aPropertyValues))
3301  {
3302  SetLastExceptionMsg("Failed to dispatch the .uno: command");
3303  return false;
3304  }
3305 
3306  return true;
3307 }
3308 
3309 static void doc_setGraphicSelection(LibreOfficeKitDocument* pThis, int nType, int nX, int nY)
3310 {
3311  comphelper::ProfileZone aZone("doc_setGraphicSelection");
3312 
3313  SolarMutexGuard aGuard;
3315 
3316  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3317  if (!pDoc)
3318  {
3319  SetLastExceptionMsg("Document doesn't support tiled rendering");
3320  return;
3321  }
3322 
3323  pDoc->setGraphicSelection(nType, nX, nY);
3324 }
3325 
3326 static void doc_resetSelection(LibreOfficeKitDocument* pThis)
3327 {
3328  comphelper::ProfileZone aZone("doc_resetSelection");
3329 
3330  SolarMutexGuard aGuard;
3332 
3333  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3334  if (!pDoc)
3335  {
3336  SetLastExceptionMsg("Document doesn't support tiled rendering");
3337  return;
3338  }
3339 
3340  pDoc->resetSelection();
3341 }
3342 
3343 static char* getLanguages(const char* pCommand)
3344 {
3345  css::uno::Sequence< css::lang::Locale > aLocales;
3346 
3347  if (xContext.is())
3348  {
3349  css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLangSrv = css::linguistic2::LinguServiceManager::create(xContext);
3350  if (xLangSrv.is())
3351  {
3352  css::uno::Reference<css::linguistic2::XSpellChecker> xSpell(xLangSrv->getSpellChecker(), css::uno::UNO_QUERY);
3353  css::uno::Reference<css::linguistic2::XSupportedLocales> xLocales(xSpell, css::uno::UNO_QUERY);
3354 
3355  if (xLocales.is())
3356  aLocales = xLocales->getLocales();
3357  }
3358  }
3359 
3360  boost::property_tree::ptree aTree;
3361  aTree.put("commandName", pCommand);
3362  boost::property_tree::ptree aValues;
3363  boost::property_tree::ptree aChild;
3364  OUString sLanguage;
3365  for ( sal_Int32 itLocale = 0; itLocale < aLocales.getLength(); itLocale++ )
3366  {
3368  if (sLanguage.startsWith("{") && sLanguage.endsWith("}"))
3369  continue;
3370 
3371  aChild.put("", sLanguage.toUtf8());
3372  aValues.push_back(std::make_pair("", aChild));
3373  }
3374  aTree.add_child("commandValues", aValues);
3375  std::stringstream aStream;
3376  boost::property_tree::write_json(aStream, aTree);
3377  char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
3378  assert(pJson); // Don't handle OOM conditions
3379  strcpy(pJson, aStream.str().c_str());
3380  pJson[aStream.str().size()] = '\0';
3381  return pJson;
3382 }
3383 
3384 static char* getFonts (const char* pCommand)
3385 {
3387  const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(
3388  pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
3389  const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
3390 
3391  boost::property_tree::ptree aTree;
3392  aTree.put("commandName", pCommand);
3393  boost::property_tree::ptree aValues;
3394  if ( pList )
3395  {
3396  sal_uInt16 nFontCount = pList->GetFontNameCount();
3397  for (sal_uInt16 i = 0; i < nFontCount; ++i)
3398  {
3399  boost::property_tree::ptree aChildren;
3400  const FontMetric& rFontMetric = pList->GetFontName(i);
3401  const sal_IntPtr* pAry = pList->GetSizeAry(rFontMetric);
3402  sal_uInt16 nSizeCount = 0;
3403  while (pAry[nSizeCount])
3404  {
3405  boost::property_tree::ptree aChild;
3406  aChild.put("", static_cast<float>(pAry[nSizeCount]) / 10);
3407  aChildren.push_back(std::make_pair("", aChild));
3408  nSizeCount++;
3409  }
3410  aValues.add_child(rFontMetric.GetFamilyName().toUtf8().getStr(), aChildren);
3411  }
3412  }
3413  aTree.add_child("commandValues", aValues);
3414  std::stringstream aStream;
3415  boost::property_tree::write_json(aStream, aTree);
3416  char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
3417  assert(pJson); // Don't handle OOM conditions
3418  strcpy(pJson, aStream.str().c_str());
3419  pJson[aStream.str().size()] = '\0';
3420  return pJson;
3421 }
3422 
3423 static char* getFontSubset (const OString& aFontName)
3424 {
3425  OUString aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName, RTL_TEXTENCODING_UTF8), rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8));
3427  const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(
3428  pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
3429  const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
3430 
3431  boost::property_tree::ptree aTree;
3432  aTree.put("commandName", ".uno:FontSubset");
3433  boost::property_tree::ptree aValues;
3434 
3435  if ( pList && !aFoundFont.isEmpty() )
3436  {
3437  sal_uInt16 nFontCount = pList->GetFontNameCount();
3438  sal_uInt16 nItFont = 0;
3439  for (; nItFont < nFontCount; ++nItFont)
3440  {
3441  if (aFoundFont == pList->GetFontName(nItFont).GetFamilyName())
3442  {
3443  break;
3444  }
3445  }
3446 
3447  if ( nItFont < nFontCount )
3448  {
3449  FontCharMapRef xFontCharMap (new FontCharMap());
3450  auto aDevice(VclPtr<VirtualDevice>::Create(nullptr, Size(1, 1), DeviceFormat::DEFAULT));
3451  const vcl::Font& aFont(pList->GetFontName(nItFont));
3452 
3453  aDevice->SetFont(aFont);
3454  aDevice->GetFontCharMap(xFontCharMap);
3455  SubsetMap aSubMap(xFontCharMap);
3456 
3457  for (auto const& subset : aSubMap.GetSubsetMap())
3458  {
3459  boost::property_tree::ptree aChild;
3460  aChild.put("", static_cast<int>(ublock_getCode(subset.GetRangeMin())));
3461  aValues.push_back(std::make_pair("", aChild));
3462  }
3463  }
3464  }
3465 
3466  aTree.add_child("commandValues", aValues);
3467  std::stringstream aStream;
3468  boost::property_tree::write_json(aStream, aTree);
3469  char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
3470  assert(pJson); // Don't handle OOM conditions
3471  strcpy(pJson, aStream.str().c_str());
3472  pJson[aStream.str().size()] = '\0';
3473  return pJson;
3474 }
3475 
3476 static char* getStyles(LibreOfficeKitDocument* pThis, const char* pCommand)
3477 {
3478  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
3479 
3480  boost::property_tree::ptree aTree;
3481  aTree.put("commandName", pCommand);
3482  uno::Reference<css::style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(pDocument->mxComponent, uno::UNO_QUERY);
3483  uno::Reference<container::XNameAccess> xStyleFamilies(xStyleFamiliesSupplier->getStyleFamilies(), uno::UNO_QUERY);
3484  uno::Sequence<OUString> aStyleFamilies = xStyleFamilies->getElementNames();
3485 
3486  static const std::vector<OUString> aWriterStyles =
3487  {
3488  "Text body",
3489  "Quotations",
3490  "Title",
3491  "Subtitle",
3492  "Heading 1",
3493  "Heading 2",
3494  "Heading 3"
3495  };
3496 
3497  // We need to keep a list of the default style names
3498  // in order to filter these out later when processing
3499  // the full list of styles.
3500  std::set<OUString> aDefaultStyleNames;
3501 
3502  boost::property_tree::ptree aValues;
3503  for (sal_Int32 nStyleFam = 0; nStyleFam < aStyleFamilies.getLength(); ++nStyleFam)
3504  {
3505  boost::property_tree::ptree aChildren;
3506  OUString sStyleFam = aStyleFamilies[nStyleFam];
3507  uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName(sStyleFam), uno::UNO_QUERY);
3508 
3509  // Writer provides a huge number of styles, we have a list of 7 "default" styles which
3510  // should be shown in the normal dropdown, which we should add to the start of the list
3511  // to simplify their selection.
3512  if (sStyleFam == "ParagraphStyles"
3513  && doc_getDocumentType(pThis) == LOK_DOCTYPE_TEXT)
3514  {
3515  for (const OUString& rStyle: aWriterStyles)
3516  {
3517  aDefaultStyleNames.insert( rStyle );
3518 
3519  boost::property_tree::ptree aChild;
3520  aChild.put("", rStyle.toUtf8());
3521  aChildren.push_back(std::make_pair("", aChild));
3522  }
3523  }
3524 
3525  uno::Sequence<OUString> aStyles = xStyleFamily->getElementNames();
3526  for (const OUString& rStyle: aStyles )
3527  {
3528  // Filter out the default styles - they are already at the top
3529  // of the list
3530  if (aDefaultStyleNames.find(rStyle) == aDefaultStyleNames.end() ||
3531  (sStyleFam != "ParagraphStyles" || doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT) )
3532  {
3533  boost::property_tree::ptree aChild;
3534  aChild.put("", rStyle.toUtf8());
3535  aChildren.push_back(std::make_pair("", aChild));
3536  }
3537  }
3538  aValues.add_child(sStyleFam.toUtf8().getStr(), aChildren);
3539  }
3540 
3541  // Header & Footer Styles
3542  {
3543  OUString sName;
3544  boost::property_tree::ptree aChild;
3545  boost::property_tree::ptree aChildren;
3546  const OUString sPageStyles("PageStyles");
3547  uno::Reference<beans::XPropertySet> xProperty;
3548  uno::Reference<container::XNameContainer> xContainer;
3549 
3550  if (xStyleFamilies->hasByName(sPageStyles) && (xStyleFamilies->getByName(sPageStyles) >>= xContainer))
3551  {
3552  uno::Sequence<OUString> aSeqNames = xContainer->getElementNames();
3553  for (sal_Int32 itName = 0; itName < aSeqNames.getLength(); itName++)
3554  {
3555  bool bIsPhysical;
3556  sName = aSeqNames[itName];
3557  xProperty.set(xContainer->getByName(sName), uno::UNO_QUERY);
3558  if (xProperty.is() && (xProperty->getPropertyValue("IsPhysical") >>= bIsPhysical) && bIsPhysical)
3559  {
3560  xProperty->getPropertyValue("DisplayName") >>= sName;
3561  aChild.put("", sName.toUtf8());
3562  aChildren.push_back(std::make_pair("", aChild));
3563  }
3564  }
3565  aValues.add_child("HeaderFooter", aChildren);
3566  }
3567  }
3568 
3569  {
3570  boost::property_tree::ptree aCommandList;
3571 
3572  {
3573  boost::property_tree::ptree aChild;
3574 
3575  OUString sClearFormat = SvxResId(RID_SVXSTR_CLEARFORM);
3576 
3577  boost::property_tree::ptree aName;
3578  aName.put("", sClearFormat.toUtf8());
3579  aChild.push_back(std::make_pair("text", aName));
3580 
3581  boost::property_tree::ptree aCommand;
3582  aCommand.put("", ".uno:ResetAttributes");
3583  aChild.push_back(std::make_pair("id", aCommand));
3584 
3585  aCommandList.push_back(std::make_pair("", aChild));
3586  }
3587 
3588  aValues.add_child("Commands", aCommandList);
3589  }
3590 
3591  aTree.add_child("commandValues", aValues);
3592  std::stringstream aStream;
3593  boost::property_tree::write_json(aStream, aTree);
3594  char* pJson = static_cast<char*>(malloc(aStream.str().size() + 1));
3595  assert(pJson); // Don't handle OOM conditions
3596  strcpy(pJson, aStream.str().c_str());
3597  pJson[aStream.str().size()] = '\0';
3598  return pJson;
3599 }
3600 
3601 enum class UndoOrRedo
3602 {
3603  UNDO,
3604  REDO
3605 };
3606 
3608 static char* getUndoOrRedo(LibreOfficeKitDocument* pThis, UndoOrRedo eCommand)
3609 {
3610  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
3611 
3612  auto pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
3613  if (!pBaseModel)
3614  return nullptr;
3615 
3616  SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
3617  if (!pObjectShell)
3618  return nullptr;
3619 
3620  SfxUndoManager* pUndoManager = pObjectShell->GetUndoManager();
3621  if (!pUndoManager)
3622  return nullptr;
3623 
3624  OUString aString;
3625  if (eCommand == UndoOrRedo::UNDO)
3626  aString = pUndoManager->GetUndoActionsInfo();
3627  else
3628  aString = pUndoManager->GetRedoActionsInfo();
3629  char* pJson = strdup(aString.toUtf8().getStr());
3630  return pJson;
3631 }
3632 
3634 static char* getTrackedChanges(LibreOfficeKitDocument* pThis)
3635 {
3636  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
3637 
3638  uno::Reference<document::XRedlinesSupplier> xRedlinesSupplier(pDocument->mxComponent, uno::UNO_QUERY);
3639  std::stringstream aStream;
3640  // We want positions of the track changes also which is not possible from
3641  // UNO. Enable positioning information for text documents only for now, so
3642  // construct the tracked changes JSON from inside the sw/, not here using UNO
3643  if (doc_getDocumentType(pThis) != LOK_DOCTYPE_TEXT && xRedlinesSupplier.is())
3644  {
3645  uno::Reference<container::XEnumeration> xRedlines = xRedlinesSupplier->getRedlines()->createEnumeration();
3646  boost::property_tree::ptree aRedlines;
3647  for (size_t nIndex = 0; xRedlines->hasMoreElements(); ++nIndex)
3648  {
3649  uno::Reference<beans::XPropertySet> xRedline(xRedlines->nextElement(), uno::UNO_QUERY);
3650  boost::property_tree::ptree aRedline;
3651  aRedline.put("index", nIndex);
3652 
3653  OUString sAuthor;
3654  xRedline->getPropertyValue("RedlineAuthor") >>= sAuthor;
3655  aRedline.put("author", sAuthor.toUtf8().getStr());
3656 
3657  OUString sType;
3658  xRedline->getPropertyValue("RedlineType") >>= sType;
3659  aRedline.put("type", sType.toUtf8().getStr());
3660 
3661  OUString sComment;
3662  xRedline->getPropertyValue("RedlineComment") >>= sComment;
3663  aRedline.put("comment", sComment.toUtf8().getStr());
3664 
3665  OUString sDescription;
3666  xRedline->getPropertyValue("RedlineDescription") >>= sDescription;
3667  aRedline.put("description", sDescription.toUtf8().getStr());
3668 
3669  util::DateTime aDateTime;
3670  xRedline->getPropertyValue("RedlineDateTime") >>= aDateTime;
3671  OUString sDateTime = utl::toISO8601(aDateTime);
3672  aRedline.put("dateTime", sDateTime.toUtf8().getStr());
3673 
3674  aRedlines.push_back(std::make_pair("", aRedline));
3675  }
3676 
3677  boost::property_tree::ptree aTree;
3678  aTree.add_child("redlines", aRedlines);
3679  boost::property_tree::write_json(aStream, aTree);
3680  }
3681  else
3682  {
3683  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3684  if (!pDoc)
3685  {
3686  SetLastExceptionMsg("Document doesn't support tiled rendering");
3687  return nullptr;
3688  }
3689  OUString aTrackedChanges = pDoc->getTrackedChanges();
3690  aStream << aTrackedChanges.toUtf8();
3691  }
3692 
3693  char* pJson = strdup(aStream.str().c_str());
3694  return pJson;
3695 }
3696 
3697 
3699 static char* getTrackedChangeAuthors(LibreOfficeKitDocument* pThis)
3700 {
3701  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3702  if (!pDoc)
3703  {
3704  SetLastExceptionMsg("Document doesn't support tiled rendering");
3705  return nullptr;
3706  }
3707  OUString aAuthors = pDoc->getTrackedChangeAuthors();
3708  return strdup(aAuthors.toUtf8().getStr());
3709 }
3710 
3711 static char* doc_getCommandValues(LibreOfficeKitDocument* pThis, const char* pCommand)
3712 {
3713  comphelper::ProfileZone aZone("doc_getCommandValues");
3714 
3715  SolarMutexGuard aGuard;
3717 
3718  OString aCommand(pCommand);
3719  static const OString aViewRowColumnHeaders(".uno:ViewRowColumnHeaders");
3720  static const OString aCellCursor(".uno:CellCursor");
3721  static const OString aFontSubset(".uno:FontSubset&name=");
3722 
3723  if (!strcmp(pCommand, ".uno:LanguageStatus"))
3724  {
3725  return getLanguages(pCommand);
3726  }
3727  else if (!strcmp(pCommand, ".uno:CharFontName"))
3728  {
3729  return getFonts(pCommand);
3730  }
3731  else if (!strcmp(pCommand, ".uno:StyleApply"))
3732  {
3733  return getStyles(pThis, pCommand);
3734  }
3735  else if (aCommand == ".uno:Undo")
3736  {
3737  return getUndoOrRedo(pThis, UndoOrRedo::UNDO);
3738  }
3739  else if (aCommand == ".uno:Redo")
3740  {
3741  return getUndoOrRedo(pThis, UndoOrRedo::REDO);
3742  }
3743  else if (aCommand == ".uno:AcceptTrackedChanges")
3744  {
3745  return getTrackedChanges(pThis);
3746  }
3747  else if (aCommand == ".uno:TrackedChangeAuthors")
3748  {
3749  return getTrackedChangeAuthors(pThis);
3750  }
3751  else if (aCommand == ".uno:ViewAnnotations")
3752  {
3753  return getPostIts(pThis);
3754  }
3755  else if (aCommand == ".uno:ViewAnnotationsPosition")
3756  {
3757  return getPostItsPos(pThis);
3758  }
3759  else if (aCommand == ".uno:RulerState")
3760  {
3761  return getRulerState(pThis);
3762  }
3763  else if (aCommand.startsWith(aViewRowColumnHeaders))
3764  {
3765  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3766  if (!pDoc)
3767  {
3768  SetLastExceptionMsg("Document doesn't support tiled rendering");
3769  return nullptr;
3770  }
3771 
3772  tools::Rectangle aRectangle;
3773  if (aCommand.getLength() > aViewRowColumnHeaders.getLength())
3774  {
3775  // Command has parameters.
3776  int nX = 0;
3777  int nY = 0;
3778  int nWidth = 0;
3779  int nHeight = 0;
3780  OString aArguments = aCommand.copy(aViewRowColumnHeaders.getLength() + 1);
3781  sal_Int32 nParamIndex = 0;
3782  do
3783  {
3784  OString aParamToken = aArguments.getToken(0, '&', nParamIndex);
3785  sal_Int32 nIndex = 0;
3786  OString aKey;
3787  OString aValue;
3788  do
3789  {
3790  OString aToken = aParamToken.getToken(0, '=', nIndex);
3791  if (!aKey.getLength())
3792  aKey = aToken;
3793  else
3794  aValue = aToken;
3795  }
3796  while (nIndex >= 0);
3797  if (aKey == "x")
3798  nX = aValue.toInt32();
3799  else if (aKey == "y")
3800  nY = aValue.toInt32();
3801  else if (aKey == "width")
3802  nWidth = aValue.toInt32();
3803  else if (aKey == "height")
3804  nHeight = aValue.toInt32();
3805  }
3806  while (nParamIndex >= 0);
3807 
3808  aRectangle = tools::Rectangle(nX, nY, nX + nWidth, nY + nHeight);
3809  }
3810 
3811  OUString aHeaders = pDoc->getRowColumnHeaders(aRectangle);
3812  if (aHeaders.isEmpty())
3813  return nullptr;
3814 
3815  OString aString = OUStringToOString(aHeaders, RTL_TEXTENCODING_UTF8);
3816 
3817  char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
3818  assert(pMemory); // Don't handle OOM conditions
3819  strcpy(pMemory, aString.getStr());
3820  return pMemory;
3821  }
3822  else if (aCommand.startsWith(aCellCursor))
3823  {
3824  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3825  if (!pDoc)
3826  {
3827  SetLastExceptionMsg("Document doesn't support tiled rendering");
3828  return nullptr;
3829  }
3830 
3831  // Command has parameters.
3832  int nOutputWidth = 0;
3833  int nOutputHeight = 0;
3834  long nTileWidth = 0;
3835  long nTileHeight = 0;
3836  if (aCommand.getLength() > aCellCursor.getLength())
3837  {
3838  OString aArguments = aCommand.copy(aCellCursor.getLength() + 1);
3839  sal_Int32 nParamIndex = 0;
3840  do
3841  {
3842  OString aParamToken = aArguments.getToken(0, '&', nParamIndex);
3843  sal_Int32 nIndex = 0;
3844  OString aKey;
3845  OString aValue;
3846  do
3847  {
3848  OString aToken = aParamToken.getToken(0, '=', nIndex);
3849  if (!aKey.getLength())
3850  aKey = aToken;
3851  else
3852  aValue = aToken;
3853  }
3854  while (nIndex >= 0);
3855  if (aKey == "outputWidth")
3856  nOutputWidth = aValue.toInt32();
3857  else if (aKey == "outputHeight")
3858  nOutputHeight = aValue.toInt32();
3859  else if (aKey == "tileWidth")
3860  nTileWidth = aValue.toInt64();
3861  else if (aKey == "tileHeight")
3862  nTileHeight = aValue.toInt64();
3863  }
3864  while (nParamIndex >= 0);
3865  }
3866 
3867  OString aString = pDoc->getCellCursor(nOutputWidth, nOutputHeight, nTileWidth, nTileHeight);
3868 
3869  char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
3870  assert(pMemory); // Don't handle OOM conditions
3871  strcpy(pMemory, aString.getStr());
3872  return pMemory;
3873  }
3874  else if (aCommand.startsWith(aFontSubset))
3875  {
3876  return getFontSubset(OString(pCommand + aFontSubset.getLength()));
3877  }
3878  else
3879  {
3880  SetLastExceptionMsg("Unknown command, no values returned");
3881  return nullptr;
3882  }
3883 }
3884 
3885 static void doc_setClientZoom(LibreOfficeKitDocument* pThis, int nTilePixelWidth, int nTilePixelHeight,
3886  int nTileTwipWidth, int nTileTwipHeight)
3887 {
3888  comphelper::ProfileZone aZone("doc_setClientZoom");
3889 
3890  SolarMutexGuard aGuard;
3892 
3893  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3894  if (!pDoc)
3895  {
3896  SetLastExceptionMsg("Document doesn't support tiled rendering");
3897  return;
3898  }
3899 
3900  pDoc->setClientZoom(nTilePixelWidth, nTilePixelHeight, nTileTwipWidth, nTileTwipHeight);
3901 }
3902 
3903 static void doc_setClientVisibleArea(LibreOfficeKitDocument* pThis, int nX, int nY, int nWidth, int nHeight)
3904 {
3905  comphelper::ProfileZone aZone("doc_setClientVisibleArea");
3906 
3907  SolarMutexGuard aGuard;
3909 
3910  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3911  if (!pDoc)
3912  {
3913  SetLastExceptionMsg("Document doesn't support tiled rendering");
3914  return;
3915  }
3916 
3917  tools::Rectangle aRectangle(Point(nX, nY), Size(nWidth, nHeight));
3918  pDoc->setClientVisibleArea(aRectangle);
3919 }
3920 
3921 static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int nLevel, int nIndex, bool bHidden)
3922 {
3923  comphelper::ProfileZone aZone("doc_setOutlineState");
3924 
3925  SolarMutexGuard aGuard;
3927 
3928  ITiledRenderable* pDoc = getTiledRenderable(pThis);
3929  if (!pDoc)
3930  {
3931  SetLastExceptionMsg("Document doesn't support tiled rendering");
3932  return;
3933  }
3934 
3935  pDoc->setOutlineState(bColumn, nLevel, nIndex, bHidden);
3936 }
3937 
3938 static int doc_createViewWithOptions(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/,
3939  const char* pOptions)
3940 {
3941  comphelper::ProfileZone aZone("doc_createView");
3942 
3943  SolarMutexGuard aGuard;
3945 
3946  OUString aOptions = getUString(pOptions);
3947  const OUString aLanguage = extractParameter(aOptions, "Language");
3948 
3949  if (!aLanguage.isEmpty())
3950  {
3951  // Set the LOK language tag, used for dialog tunneling.
3953  }
3954 
3955  return SfxLokHelper::createView();
3956 }
3957 
3958 static int doc_createView(LibreOfficeKitDocument* pThis)
3959 {
3960  return doc_createViewWithOptions(pThis, nullptr); // No options.
3961 }
3962 
3963 static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int nId)
3964 {
3965  comphelper::ProfileZone aZone("doc_destroyView");
3966 
3967  SolarMutexGuard aGuard;
3969 
3971 }
3972 
3973 static void doc_setView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int nId)
3974 {
3975  comphelper::ProfileZone aZone("doc_setView");
3976 
3977  SolarMutexGuard aGuard;
3979 
3980  SfxLokHelper::setView(nId);
3981 }
3982 
3983 static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/)
3984 {
3985  comphelper::ProfileZone aZone("doc_getView");
3986 
3987  SolarMutexGuard aGuard;
3989 
3990  return SfxLokHelper::getView();
3991 }
3992 
3993 static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/)
3994 {
3995  comphelper::ProfileZone aZone("doc_getViewsCount");
3996 
3997  SolarMutexGuard aGuard;
3999 
4000  return SfxLokHelper::getViewsCount();
4001 }
4002 
4003 static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int* pArray, size_t nSize)
4004 {
4005  comphelper::ProfileZone aZone("doc_getViewsIds");
4006 
4007  SolarMutexGuard aGuard;
4009 
4010  return SfxLokHelper::getViewIds(pArray, nSize);
4011 }
4012 
4013 static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int nId, const char* language)
4014 {
4015  comphelper::ProfileZone aZone("doc_setViewLanguage");
4016 
4017  SolarMutexGuard aGuard;
4019 
4020  SfxLokHelper::setViewLanguage(nId, OStringToOUString(language, RTL_TEXTENCODING_UTF8));
4021 }
4022 
4023 unsigned char* doc_renderFont(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/,
4024  const char* pFontName,
4025  const char* pChar,
4026  int* pFontWidth,
4027  int* pFontHeight)
4028 {
4029  comphelper::ProfileZone aZone("doc_renderFont");
4030 
4031  SolarMutexGuard aGuard;
4033 
4034  OString aSearchedFontName(pFontName);
4035  OUString aText(OStringToOUString(pChar, RTL_TEXTENCODING_UTF8));
4037  const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(
4038  pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
4039  const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
4040 
4041  const int nDefaultFontSize = 25;
4042 
4043  if ( pList )
4044  {
4045  sal_uInt16 nFontCount = pList->GetFontNameCount();
4046  for (sal_uInt16 i = 0; i < nFontCount; ++i)
4047  {
4048  const FontMetric& rFontMetric = pList->GetFontName(i);
4049  const OUString& aFontName = rFontMetric.GetFamilyName();
4050  if (aSearchedFontName != aFontName.toUtf8())
4051  continue;
4052 
4053  if (aText.isEmpty())
4054  aText = rFontMetric.GetFamilyName();
4055 
4056  auto aDevice(
4058  nullptr, Size(1, 1), DeviceFormat::DEFAULT));
4059  ::tools::Rectangle aRect;
4060  vcl::Font aFont(rFontMetric);
4061  aFont.SetFontSize(Size(0, nDefaultFontSize));
4062  aDevice->SetFont(aFont);
4063  aDevice->GetTextBoundRect(aRect, aText);
4064  if (aRect.IsEmpty())
4065  break;
4066 
4067  int nFontWidth = aRect.BottomRight().X() + 1;
4068  int nFontHeight = aRect.BottomRight().Y() + 1;
4069 
4070  if (!(nFontWidth > 0 && nFontHeight > 0))
4071  break;
4072 
4073  if (*pFontWidth > 0 && *pFontHeight > 0)
4074  {
4075  double fScaleX = *pFontWidth / static_cast<double>(nFontWidth);
4076  double fScaleY = *pFontHeight / static_cast<double>(nFontHeight);
4077 
4078  double fScale = std::min(fScaleX, fScaleY);
4079 
4080  if (fScale >= 1.0)
4081  {
4082  int nFontSize = fScale * nDefaultFontSize;
4083  aFont.SetFontSize(Size(0, nFontSize));
4084  aDevice->SetFont(aFont);
4085  }
4086 
4087  aRect = tools::Rectangle(0, 0, *pFontWidth, *pFontHeight);
4088 
4089  nFontWidth = *pFontWidth;
4090  nFontHeight = *pFontHeight;
4091 
4092  }
4093 
4094  unsigned char* pBuffer = static_cast<unsigned char*>(malloc(4 * nFontWidth * nFontHeight));
4095  if (!pBuffer)
4096  break;
4097 
4098  memset(pBuffer, 0, nFontWidth * nFontHeight * 4);
4099  aDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
4100  aDevice->SetOutputSizePixelScaleOffsetAndBuffer(
4101  Size(nFontWidth, nFontHeight), Fraction(1.0), Point(),
4102  pBuffer);
4103 
4104  if (*pFontWidth > 0 && *pFontHeight > 0)
4105  {
4106  DrawTextFlags const nStyle =
4107  DrawTextFlags::Center
4108  | DrawTextFlags::VCenter
4109  | DrawTextFlags::MultiLine
4110  | DrawTextFlags::WordBreakHyphenation;// | DrawTextFlags::WordBreak ;
4111 
4112  aDevice->DrawText(aRect, aText, nStyle);
4113  }
4114  else
4115  {
4116  *pFontWidth = nFontWidth;
4117  *pFontHeight = nFontHeight;
4118 
4119  aDevice->DrawText(Point(0,0), aText);
4120  }
4121 
4122 
4123  return pBuffer;
4124  }
4125  }
4126  return nullptr;
4127 }
4128 
4129 static void doc_paintWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
4130  unsigned char* pBuffer,
4131  const int nX, const int nY,
4132  const int nWidth, const int nHeight)
4133 {
4134  doc_paintWindowDPI(pThis, nLOKWindowId, pBuffer, nX, nY, nWidth, nHeight, 1.0);
4135 }
4136 
4137 static void doc_paintWindowDPI(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId,
4138  unsigned char* pBuffer,
4139  const int nX, const int nY,
4140  const int nWidth, const int nHeight,
4141  const double fDPIScale)
4142 {
4143  comphelper::ProfileZone aZone("doc_paintWindowDPI");
4144 
4145  SolarMutexGuard aGuard;
4147 
4148  VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
4149  if (!pWindow)
4150  {
4151  SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4152  return;
4153  }
4154 
4155  // Setup cairo (or CoreGraphics, in the iOS case) to draw with the changed DPI scale (and return
4156  // back to 1.0 when the painting finishes)
4159 
4160 #if defined(IOS)
4161 
4162  CGContextRef cgc = CGBitmapContextCreate(pBuffer, nWidth, nHeight, 8, nWidth*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst | kCGImageByteOrder32Little);
4163 
4164  SAL_INFO( "vcl.cg", "CGBitmapContextCreate(" << nWidth << "x" << nHeight << "x32) = " << cgc);
4165 
4166  CGContextTranslateCTM(cgc, 0, nHeight);
4167  CGContextScaleCTM(cgc, fDPIScale, -fDPIScale);
4168 
4169  SystemGraphicsData aData;
4170  aData.rCGContext = cgc;
4171 
4172  ScopedVclPtrInstance<VirtualDevice> pDevice(&aData, Size(1, 1), DeviceFormat::DEFAULT);
4173  pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
4174 
4175  pDevice->SetOutputSizePixel(Size(nWidth, nHeight));
4176 
4177  MapMode aMapMode(pDevice->GetMapMode());
4178  aMapMode.SetOrigin(Point(-(nX / fDPIScale), -(nY / fDPIScale)));
4179  pDevice->SetMapMode(aMapMode);
4180 
4182  pWindow->PaintToDevice(pDevice.get(), Point(0, 0), Size());
4184 
4185  SAL_INFO( "vcl.cg", "CGContextRelease(" << cgc << ")" );
4186  CGContextRelease(cgc);
4187 
4188 #else
4189 
4190  ScopedVclPtrInstance<VirtualDevice> pDevice(nullptr, Size(1, 1), DeviceFormat::DEFAULT);
4191  pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
4192 
4193  pDevice->SetOutputSizePixelScaleOffsetAndBuffer(Size(nWidth, nHeight), Fraction(1.0), Point(), pBuffer);
4194 
4195  MapMode aMapMode(pDevice->GetMapMode());
4196  aMapMode.SetOrigin(Point(-(nX / fDPIScale), -(nY / fDPIScale)));
4197  pDevice->SetMapMode(aMapMode);
4198 
4200  pWindow->PaintToDevice(pDevice.get(), Point(0, 0), Size());
4202 
4203 #endif
4204 }
4205 
4206 static void doc_postWindow(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindowId, int nAction, const char* pData)
4207 {
4208  comphelper::ProfileZone aZone("doc_postWindow");
4209 
4210  SolarMutexGuard aGuard;
4212 
4213  VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
4214  if (!pWindow)
4215  {
4216  SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4217  return;
4218  }
4219 
4220  if (nAction == LOK_WINDOW_CLOSE)
4221  {
4222  if (Dialog* pDialog = dynamic_cast<Dialog*>(pWindow.get()))
4223  pDialog->Close();
4224  else if (FloatingWindow* pFloatWin = dynamic_cast<FloatingWindow*>(pWindow.get()))
4225  pFloatWin->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll);
4226  }
4227  else if (nAction == LOK_WINDOW_PASTE)
4228  {
4229  OUString aMimeType;
4230  css::uno::Sequence<sal_Int8> aData;
4231  std::vector<beans::PropertyValue> aArgs(jsonToPropertyValuesVector(pData));
4232  {
4233  aArgs.size() == 2 &&
4234  aArgs[0].Name == "MimeType" && (aArgs[0].Value >>= aMimeType) &&
4235  aArgs[1].Name == "Data" && (aArgs[1].Value >>= aData);
4236  }
4237 
4238  if (!aMimeType.isEmpty() && aData.getLength() > 0)
4239  {
4240  uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable(aMimeType, aData));
4241  uno::Reference<datatransfer::clipboard::XClipboard> xClipboard(new LOKClipboard);
4242  xClipboard->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
4243  pWindow->SetClipboard(xClipboard);
4244 
4245  KeyEvent aEvent(0, KEY_PASTE, 0);
4246  Application::PostKeyEvent(VclEventId::WindowKeyInput, pWindow, &aEvent);
4247  }
4248  else
4249  SetLastExceptionMsg("Window command 'paste': wrong parameters.");
4250  }
4251 }
4252 
4253 // CERTIFICATE AND DOCUMENT SIGNING
4254 static bool doc_insertCertificate(LibreOfficeKitDocument* pThis,
4255  const unsigned char* pCertificateBinary, const int nCertificateBinarySize,
4256  const unsigned char* pPrivateKeyBinary, const int nPrivateKeySize)
4257 {
4258  comphelper::ProfileZone aZone("doc_insertCertificate");
4259 
4260  if (!xContext.is())
4261  return false;
4262 
4263  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
4264 
4265  if (!pDocument->mxComponent.is())
4266  return false;
4267 
4268  SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
4269  if (!pBaseModel)
4270  return false;
4271 
4272  SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
4273 
4274  if (!pObjectShell)
4275  return false;
4276 
4277  uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xContext);
4278  uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
4279  if (!xSecurityContext.is())
4280  return false;
4281 
4282  uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
4283  uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY);
4284 
4285  if (!xCertificateCreator.is())
4286  return false;
4287 
4288  uno::Sequence<sal_Int8> aCertificateSequence;
4289 
4290  std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize);
4291  std::string aCertificateBase64String = extractCertificate(aCertificateString);
4292  if (!aCertificateBase64String.empty())
4293  {
4294  OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String.c_str());
4295  comphelper::Base64::decode(aCertificateSequence, aBase64OUString);
4296  }
4297  else
4298  {
4299  aCertificateSequence.realloc(nCertificateBinarySize);
4300  std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.begin());
4301  }
4302 
4303  uno::Sequence<sal_Int8> aPrivateKeySequence;
4304  std::string aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary), nPrivateKeySize);
4305  std::string aPrivateKeyBase64String = extractPrivateKey(aPrivateKeyString);
4306  if (!aPrivateKeyBase64String.empty())
4307  {
4308  OUString aBase64OUString = OUString::createFromAscii(aPrivateKeyBase64String.c_str());
4309  comphelper::Base64::decode(aPrivateKeySequence, aBase64OUString);
4310  }
4311  else
4312  {
4313  aPrivateKeySequence.realloc(nPrivateKeySize);
4314  std::copy(pPrivateKeyBinary, pPrivateKeyBinary + nPrivateKeySize, aPrivateKeySequence.begin());
4315  }
4316 
4317  uno::Reference<security::XCertificate> xCertificate = xCertificateCreator->createDERCertificateWithPrivateKey(aCertificateSequence, aPrivateKeySequence);
4318 
4319  if (!xCertificate.is())
4320  return false;
4321 
4322  SolarMutexGuard aGuard;
4323 
4324  return pObjectShell->SignDocumentContentUsingCertificate(xCertificate);
4325 }
4326 
4327 static bool doc_addCertificate(LibreOfficeKitDocument* pThis,
4328  const unsigned char* pCertificateBinary, const int nCertificateBinarySize)
4329 {
4330  comphelper::ProfileZone aZone("doc_addCertificate");
4331 
4332  if (!xContext.is())
4333  return false;
4334 
4335  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
4336 
4337  if (!pDocument->mxComponent.is())
4338  return false;
4339 
4340  SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
4341  if (!pBaseModel)
4342  return false;
4343 
4344  SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
4345 
4346  if (!pObjectShell)
4347  return false;
4348 
4349  uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xContext);
4350  uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
4351  if (!xSecurityContext.is())
4352  return false;
4353 
4354  uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
4355  uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY);
4356 
4357  if (!xCertificateCreator.is())
4358  return false;
4359 
4360  uno::Sequence<sal_Int8> aCertificateSequence;
4361 
4362  std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize);
4363  std::string aCertificateBase64String = extractCertificate(aCertificateString);
4364  if (!aCertificateBase64String.empty())
4365  {
4366  OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String.c_str());
4367  comphelper::Base64::decode(aCertificateSequence, aBase64OUString);
4368  }
4369  else
4370  {
4371  aCertificateSequence.realloc(nCertificateBinarySize);
4372  std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.begin());
4373  }
4374 
4375  uno::Reference<security::XCertificate> xCertificate = xCertificateCreator->addDERCertificateToTheDatabase(aCertificateSequence, "TCu,Cu,Tu");
4376 
4377  if (!xCertificate.is())
4378  return false;
4379 
4380  SAL_INFO("lok", "Certificate Added = IssuerName: " << xCertificate->getIssuerName() << " SubjectName: " << xCertificate->getSubjectName());
4381 
4382  return true;
4383 }
4384 
4385 static int doc_getSignatureState(LibreOfficeKitDocument* pThis)
4386 {
4387  comphelper::ProfileZone aZone("doc_getSignatureState");
4388 
4389  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
4390 
4391  if (!pDocument->mxComponent.is())
4392  return int(SignatureState::UNKNOWN);
4393 
4394  SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
4395  if (!pBaseModel)
4396  return int(SignatureState::UNKNOWN);
4397 
4398  SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
4399  if (!pObjectShell)
4400  return int(SignatureState::UNKNOWN);
4401 
4402  SolarMutexGuard aGuard;
4403 
4404  pObjectShell->RecheckSignature(false);
4405 
4406  return int(pObjectShell->GetDocumentSignatureState());
4407 }
4408 
4409 static char* lo_getError (LibreOfficeKit *pThis)
4410 {
4411  comphelper::ProfileZone aZone("lo_getError");
4412 
4413  SolarMutexGuard aGuard;
4414 
4415  LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
4416  OString aString = OUStringToOString(pLib->maLastExceptionMsg, RTL_TEXTENCODING_UTF8);
4417  char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
4418  assert(pMemory); // Don't handle OOM conditions
4419  strcpy(pMemory, aString.getStr());
4420  return pMemory;
4421 }
4422 
4423 static void lo_freeError(char* pFree)
4424 {
4425  free(pFree);
4426 }
4427 
4428 static char* lo_getFilterTypes(LibreOfficeKit* pThis)
4429 {
4430  SolarMutexGuard aGuard;
4432 
4433  LibLibreOffice_Impl* pImpl = static_cast<LibLibreOffice_Impl*>(pThis);
4434 
4435  if (!xSFactory.is())
4437 
4438  if (!xSFactory.is())
4439  {
4440  pImpl->maLastExceptionMsg = "Service factory is not available";
4441  return nullptr;
4442  }
4443 
4444  uno::Reference<container::XNameAccess> xTypeDetection(xSFactory->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
4445  uno::Sequence<OUString> aTypes = xTypeDetection->getElementNames();
4446  boost::property_tree::ptree aTree;
4447  for (const OUString& rType : aTypes)
4448  {
4449  uno::Sequence<beans::PropertyValue> aValues;
4450  if (xTypeDetection->getByName(rType) >>= aValues)
4451  {
4452  auto it = std::find_if(aValues.begin(), aValues.end(), [](const beans::PropertyValue& rValue) { return rValue.Name == "MediaType"; });
4453  OUString aValue;
4454  if (it != aValues.end() && (it->Value >>= aValue) && !aValue.isEmpty())
4455  {
4456  boost::property_tree::ptree aChild;
4457  aChild.put("MediaType", aValue.toUtf8());
4458  aTree.add_child(rType.toUtf8().getStr(), aChild);
4459  }
4460  }
4461  }
4462  std::stringstream aStream;
4463  boost::property_tree::write_json(aStream, aTree);
4464  return strdup(aStream.str().c_str());
4465 }
4466 
4467 static void lo_setOptionalFeatures(LibreOfficeKit* pThis, unsigned long long const features)
4468 {
4469  comphelper::ProfileZone aZone("lo_setOptionalFeatures");
4470 
4471  SolarMutexGuard aGuard;
4473 
4474  LibLibreOffice_Impl *const pLib = static_cast<LibLibreOffice_Impl*>(pThis);
4475  pLib->mOptionalFeatures = features;
4476  if (features & LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK)
4478  if (features & LOK_FEATURE_NO_TILED_ANNOTATIONS)
4480  if (features & LOK_FEATURE_RANGE_HEADERS)
4482  if (features & LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK)
4484 }
4485 
4486 static void lo_setDocumentPassword(LibreOfficeKit* pThis,
4487  const char* pURL, const char* pPassword)
4488 {
4489  comphelper::ProfileZone aZone("lo_setDocumentPassword");
4490 
4491  SolarMutexGuard aGuard;
4493 
4494  assert(pThis);
4495  assert(pURL);
4496  LibLibreOffice_Impl *const pLib = static_cast<LibLibreOffice_Impl*>(pThis);
4497  assert(pLib->mInteractionMap.find(OString(pURL)) != pLib->mInteractionMap.end());
4498  pLib->mInteractionMap.find(OString(pURL))->second->SetPassword(pPassword);
4499 }
4500 
4501 static char* lo_getVersionInfo(SAL_UNUSED_PARAMETER LibreOfficeKit* /*pThis*/)
4502 {
4504  const OUString sVersionStrTemplate(
4505  "{ "
4506  "\"ProductName\": \"%PRODUCTNAME\", "
4507  "\"ProductVersion\": \"%PRODUCTVERSION\", "
4508  "\"ProductExtension\": \"%PRODUCTEXTENSION\", "
4509  "\"BuildId\": \"%BUILDID\" "
4510  "}"
4511  );
4512  const OString sVersionStr = OUStringToOString(ReplaceStringHookProc(sVersionStrTemplate), RTL_TEXTENCODING_UTF8);
4513 
4514  char* pVersion = static_cast<char*>(malloc(sVersionStr.getLength() + 1));
4515  assert(pVersion); // Don't handle OOM conditions
4516  strcpy(pVersion, sVersionStr.getStr());
4517  return pVersion;
4518 }
4519 
4520 static void force_c_locale()
4521 {
4522  // force locale (and resource files loaded) to en-US
4523  OUString aLangISO("en-US");
4524  SvtSysLocaleOptions aLocalOptions;
4525  aLocalOptions.SetLocaleConfigString(aLangISO);
4526  aLocalOptions.SetUILocaleConfigString(aLangISO);
4527 }
4528 
4529 static void aBasicErrorFunc(const OUString& rError, const OUString& rAction)
4530 {
4531  OStringBuffer aBuffer("Unexpected dialog: ");
4532  aBuffer.append(OUStringToOString(rAction, RTL_TEXTENCODING_ASCII_US));
4533  aBuffer.append(" Error: ");
4534  aBuffer.append(OUStringToOString(rError, RTL_TEXTENCODING_ASCII_US));
4535 
4536  fprintf(stderr, "Unexpected basic error dialog '%s'\n", aBuffer.getStr());
4537 }
4538 
4539 static bool initialize_uno(const OUString& aAppProgramURL)
4540 {
4541 #ifdef IOS
4542  // For iOS we already hardcode the inifile as "rc" in the .app directory.
4543  rtl::Bootstrap::setIniFilename(aAppProgramURL + "/" SAL_CONFIGFILE("fundamental"));
4544  xContext = cppu::defaultBootstrap_InitialComponentContext(aAppProgramURL + "/rc");
4545 #elif defined MACOSX
4546  rtl::Bootstrap::setIniFilename(aAppProgramURL + "/../Resources/" SAL_CONFIGFILE("soffice"));
4548 #else
4549  rtl::Bootstrap::setIniFilename(aAppProgramURL + "/" SAL_CONFIGFILE("soffice"));
4551 #endif
4552 
4553  if (!xContext.is())
4554  {
4555  SetLastExceptionMsg("XComponentContext could not be created");
4556  SAL_INFO("lok", "XComponentContext could not be created");
4557  return false;
4558  }
4559 
4560  xFactory = xContext->getServiceManager();
4561  if (!xFactory.is())
4562  {
4563  SetLastExceptionMsg("XMultiComponentFactory could not be created");
4564  SAL_INFO("lok", "XMultiComponentFactory could not be created");
4565  return false;
4566  }
4567 
4568  xSFactory.set(xFactory, uno::UNO_QUERY_THROW);
4570 
4571  SAL_INFO("lok", "Uno initialized - " << xContext.is());
4572 
4573  // set UserInstallation to user profile dir in test/user-template
4574 // rtl::Bootstrap aDefaultVars;
4575 // aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
4576  // configmgr setup ?
4577 
4578  return true;
4579 }
4580 
4581 // pre-unipoll version.
4582 static void lo_startmain(void*)
4583 {
4584  osl_setThreadName("lo_startmain");
4585 
4588 
4590 
4591  soffice_main();
4592 
4594 }
4595 
4596 // unipoll version.
4597 static void lo_runLoop(LibreOfficeKit* /*pThis*/,
4598  LibreOfficeKitPollCallback pPollCallback,
4599  LibreOfficeKitWakeCallback pWakeCallback,
4600  void* pData)
4601 {
4602 #ifdef IOS // Maybe ANDROID, too?
4604 #endif
4605 
4606  {
4607  SolarMutexGuard aGuard;
4608 
4609  vcl::lok::registerPollCallbacks(pPollCallback, pWakeCallback, pData);
4611  soffice_main();
4612  }
4613 #ifdef IOS // ANDROID, too?
4616 #endif
4617 }
4618 
4619 static bool bInitialized = false;
4620 
4622 {
4623  LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(data);
4624 
4625  if (!pLib->mpCallback)
4626  return;
4627 
4628  switch (type)
4629  {
4631  pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START, nullptr, pLib->mpCallbackData);
4632  break;
4634  pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE, OUString::number(percent).toUtf8().getStr(), pLib->mpCallbackData);
4635  break;
4637  pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH, nullptr, pLib->mpCallbackData);
4638  break;
4639  }
4640 }
4641 
4643 static void preloadData()
4644 {
4645  comphelper::ProfileZone aZone("preload data");
4646 
4647  // Create user profile in the temp directory for loading the dictionaries
4648  OUString sUserPath;
4649  rtl::Bootstrap::get("UserInstallation", sUserPath);
4650  utl::TempFile aTempDir(nullptr, true);
4651  aTempDir.EnableKillingFile();
4652  rtl::Bootstrap::set("UserInstallation", aTempDir.GetURL());
4653 
4654  // Register the bundled extensions
4657  if(bAbort)
4658  std::cerr << "CheckExtensionDependencies failed" << std::endl;
4659 
4660  // preload all available dictionaries
4661  css::uno::Reference<css::linguistic2::XLinguServiceManager> xLngSvcMgr =
4663  css::uno::Reference<linguistic2::XSpellChecker> xSpellChecker(xLngSvcMgr->getSpellChecker());
4664 
4665  std::cerr << "Preloading dictionaries: ";
4666  css::uno::Reference<linguistic2::XSupportedLocales> xSpellLocales(xSpellChecker, css::uno::UNO_QUERY_THROW);
4667  uno::Sequence< css::lang::Locale > aLocales = xSpellLocales->getLocales();
4668  for (auto &it : aLocales)
4669  {
4670  std::cerr << it.Language << "_" << it.Country << " ";
4671  css::beans::PropertyValues aNone;
4672  xSpellChecker->isValid("forcefed", it, aNone);
4673  }
4674  std::cerr << "\n";
4675 
4676  // preload all available thesauri
4677  css::uno::Reference<linguistic2::XThesaurus> xThesaurus(xLngSvcMgr->getThesaurus());
4678  css::uno::Reference<linguistic2::XSupportedLocales> xThesLocales(xSpellChecker, css::uno::UNO_QUERY_THROW);
4679  aLocales = xThesLocales->getLocales();
4680  std::cerr << "Preloading thesauri: ";
4681  for (auto &it : aLocales)
4682  {
4683  std::cerr << it.Language << "_" << it.Country << " ";
4684  css::beans::PropertyValues aNone;
4685  xThesaurus->queryMeanings("forcefed", it, aNone);
4686  }
4687  std::cerr << "\n";
4688 
4689  css::uno::Reference< css::ui::XAcceleratorConfiguration > xGlobalCfg = css::ui::GlobalAcceleratorConfiguration::create(
4691  xGlobalCfg->getAllKeyEvents();
4692 
4693  std::cerr << "Preload icons\n";
4694  ImageTree &images = ImageTree::get();
4695  images.getImageUrl("forcefed.png", "style", "FO_oo");
4696 
4697  std::cerr << "Preload languages\n";
4698 
4699  // force load language singleton
4701  (void)LanguageTag::isValidBcp47("foo", nullptr);
4702 
4703  std::cerr << "Preload fonts\n";
4704 
4705  // Initialize fonts.
4706  css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLangSrv = css::linguistic2::LinguServiceManager::create(xContext);
4707  if (xLangSrv.is())
4708  {
4709  css::uno::Reference<css::linguistic2::XSpellChecker> xSpell(xLangSrv->getSpellChecker(), css::uno::UNO_QUERY);
4710  css::uno::Reference<css::linguistic2::XSupportedLocales> xLocales(xSpell, css::uno::UNO_QUERY);
4711  if (xLocales.is())
4712  aLocales = xLocales->getLocales();
4713  }
4714 
4715  for (const auto& aLocale : aLocales)
4716  {
4717  //TODO: Add more types and cache more aggressively. For now this initializes the fontcache.
4718  using namespace ::com::sun::star::i18n::ScriptType;
4719  LanguageType nLang;
4721  OutputDevice::GetDefaultFont(DefaultFontType::LATIN_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne);
4723  OutputDevice::GetDefaultFont(DefaultFontType::CJK_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne);
4725  OutputDevice::GetDefaultFont(DefaultFontType::CTL_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne);
4726  }
4727 
4728  // Set user profile's path back to the original one
4729  rtl::Bootstrap::set("UserInstallation", sUserPath);
4730 }
4731 
4733 {
4734  static const int dumpTimeoutMS = 5000;
4735 public:
4736  ProfileZoneDumper() : AutoTimer( "zone dumper" )
4737  {
4738  SetTimeout(dumpTimeoutMS);
4739  Start();
4740  }
4741  virtual void Invoke() override
4742  {
4743  css::uno::Sequence<OUString> aEvents =
4745  OStringBuffer aOutput;
4746  for (auto &s : aEvents)
4747  {
4748  aOutput.append(OUStringToOString(s, RTL_TEXTENCODING_UTF8));
4749  aOutput.append("\n");
4750  }
4751  OString aChunk = aOutput.makeStringAndClear();
4752  if (gImpl && gImpl->mpCallback)
4753  gImpl->mpCallback(LOK_CALLBACK_PROFILE_FRAME, aChunk.getStr(), gImpl->mpCallbackData);
4754  }
4755 };
4756 
4757 static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char* pUserProfileUrl)
4758 {
4759  enum {
4760  PRE_INIT, // setup shared data in master process
4761  SECOND_INIT, // complete init. after fork
4762  FULL_INIT // do a standard complete init.
4763  } eStage;
4764 
4765  // Did we do a pre-initialize
4766  static bool bPreInited = false;
4767  static bool bUnipoll = false;
4768  static bool bProfileZones = false;
4769 
4770  { // cf. string lifetime for preinit
4771  std::vector<OUString> aOpts;
4772 
4773  // ':' delimited options - avoiding ABI change for new parameters
4774  const char *pOptions = getenv("SAL_LOK_OPTIONS");
4775  if (pOptions)
4776  aOpts = comphelper::string::split(OUString(pOptions, strlen(pOptions), RTL_TEXTENCODING_UTF8), ':');
4777  for (auto &it : aOpts)
4778  {
4779  if (it == "unipoll")
4780  bUnipoll = true;
4781  else if (it == "profile_events")
4782  bProfileZones = true;
4783  }
4784  }
4785 
4786  // What stage are we at ?
4787  if (pThis == nullptr)
4788  eStage = PRE_INIT;
4789  else if (bPreInited)
4790  eStage = SECOND_INIT;
4791  else
4792  eStage = FULL_INIT;
4793 
4794  LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
4795 
4796  if (bInitialized)
4797  return 1;
4798 
4799  // Turn profile zones on early
4800  if (bProfileZones && eStage == SECOND_INIT)
4801  {
4803  new ProfileZoneDumper();
4804  }
4805 
4806  comphelper::ProfileZone aZone("lok-init");
4807 
4808  if (eStage == PRE_INIT)
4809  rtl_alloc_preInit(true);
4810  else if (eStage == SECOND_INIT)
4811  rtl_alloc_preInit(false);
4812 
4813  if (eStage != SECOND_INIT)
4815 
4816  if (eStage != PRE_INIT)
4818 
4819  if (pUserProfileUrl && eStage != PRE_INIT)
4820  {
4821  OUString url(
4822  pUserProfileUrl, strlen(pUserProfileUrl), RTL_TEXTENCODING_UTF8);
4823  OUString path;
4824  if (url.startsWithIgnoreAsciiCase("vnd.sun.star.pathname:", &path))
4825  {
4826  OUString url2;
4827  osl::FileBase::RC e = osl::FileBase::getFileURLFromSystemPath(
4828  path, url2);
4829  if (e == osl::FileBase::E_None)
4830  url = url2;
4831  else
4832  SAL_WARN("lok", "resolving <" << url << "> failed with " << +e);
4833  }
4834  rtl::Bootstrap::set("UserInstallation", url);
4835  if (eStage == SECOND_INIT)
4837  }
4838 
4839  OUString aAppPath;
4840  if (pAppPath)
4841  {
4842  aAppPath = OUString(pAppPath, strlen(pAppPath), RTL_TEXTENCODING_UTF8);
4843  }
4844  else
4845  {
4846 #ifdef ANDROID
4847  aAppPath = OUString::fromUtf8(lo_get_app_data_dir()) + "/program";
4848 #else
4849  // Fun conversion dance back and forth between URLs and system paths...
4850  OUString aAppURL;
4851  ::osl::Module::getUrlFromAddress( reinterpret_cast< oslGenericFunction >(lo_initialize),
4852  aAppURL);
4853  osl::FileBase::getSystemPathFromFileURL( aAppURL, aAppPath );
4854 #endif
4855 
4856 #ifdef IOS
4857  // The above gives something like
4858  // "/private/var/containers/Bundle/Application/953AA851-CC15-4C60-A2CB-C2C6F24E6F71/Foo.app/Foo",
4859  // and we want to drop the final component (the binary name).
4860  sal_Int32 lastSlash = aAppPath.lastIndexOf('/');
4861  assert(lastSlash > 0);
4862  aAppPath = aAppPath.copy(0, lastSlash);
4863 #endif
4864  }
4865 
4866  OUString aAppURL;
4867  if (osl::FileBase::getFileURLFromSystemPath(aAppPath, aAppURL) != osl::FileBase::E_None)
4868  return 0;
4869 
4870 #ifdef IOS
4871  // A LibreOffice-using iOS app should have the ICU data file in the app bundle. Initialize ICU
4872  // to use that.
4873  NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
4874 
4875  int fd = open([[bundlePath stringByAppendingPathComponent:@"ICU.dat"] UTF8String], O_RDONLY);
4876  if (fd == -1)
4877  NSLog(@"Could not open ICU data file %s", [[bundlePath stringByAppendingPathComponent:@"ICU.dat"] UTF8String]);
4878  else
4879  {
4880  struct stat st;
4881  if (fstat(fd, &st) == -1)
4882  NSLog(@"fstat on ICU data file failed: %s", strerror(errno));
4883  else
4884  {
4885  void *icudata = mmap(0, (size_t) st.st_size, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
4886  if (icudata == MAP_FAILED)
4887  NSLog(@"mmap failed: %s", strerror(errno));
4888  else
4889  {
4890  UErrorCode icuStatus = U_ZERO_ERROR;
4891  udata_setCommonData(icudata, &icuStatus);
4892  if (U_FAILURE(icuStatus))
4893  NSLog(@"udata_setCommonData failed");
4894  else
4895  {
4896  // Quick test that ICU works...
4897  UConverter *cnv = ucnv_open("iso-8859-3", &icuStatus);
4898  NSLog(@"ucnv_open(iso-8859-3)-> %p, err = %s, name=%s",
4899  (void *)cnv, u_errorName(icuStatus), (!cnv)?"?":ucnv_getName(cnv,&icuStatus));
4900  if (U_SUCCESS(icuStatus))
4901  ucnv_close(cnv);
4902  }
4903  }
4904  }
4905  close(fd);
4906  }
4907 #endif
4908 
4909  try
4910  {
4911  if (eStage != SECOND_INIT)
4912  {
4913  SAL_INFO("lok", "Attempting to initialize UNO");
4914 
4915  if (!initialize_uno(aAppURL))
4916  return false;
4917 
4918  // Force headless -- this is only for bitmap rendering.
4919  rtl::Bootstrap::set("SAL_USE_VCLPLUGIN", "svp");
4920 
4921  // We specifically need to make sure we have the "headless"
4922  // command arg set (various code specifically checks via
4923  // CommandLineArgs):
4925 
4926 #ifdef IOS
4927  if (InitVCL() && [NSThread isMainThread])
4928  {
4929  static bool bFirstTime = true;
4930  if (bFirstTime)
4931  {
4933  bFirstTime = false;
4934  }
4935  }
4937 #endif
4938 
4939  if (eStage == PRE_INIT)
4940  {
4941  {
4942  comphelper::ProfileZone aInit("Init vcl");
4943  std::cerr << "Init vcl\n";
4944  InitVCL();
4945  }
4946 
4947  // pre-load all component libraries.
4948  if (!xContext.is())
4949  throw css::uno::DeploymentException("preInit: XComponentContext is not created");
4950 
4951  css::uno::Reference< css::uno::XInterface > xService;
4952  xContext->getValueByName("/singletons/com.sun.star.lang.theServiceManager") >>= xService;
4953  if (!xService.is())
4954  throw css::uno::DeploymentException("preInit: XMultiComponentFactory is not created");
4955 
4956  css::uno::Reference<css::lang::XInitialization> aService(
4957  xService, css::uno::UNO_QUERY_THROW);
4958 
4959  // pre-requisites:
4960  // In order to load implementations and invoke
4961  // component factory it is required:
4962  // 1) defaultBootstrap_InitialComponentContext()
4963  // 2) comphelper::setProcessServiceFactory(xSFactory);
4964  // 3) InitVCL()
4965  {
4966  comphelper::ProfileZone aInit("preload");
4967  aService->initialize({css::uno::makeAny<OUString>("preload")});
4968  }
4969  { // Force load some modules
4970  comphelper::ProfileZone aInit("preload modules");
4973  }
4974 
4975  preloadData();
4976 
4977  // Release Solar Mutex, lo_startmain thread should acquire it.
4979  }
4980 
4981  force_c_locale();
4982  }
4983 
4984  if (eStage != PRE_INIT)
4985  {
4986  SAL_INFO("lok", "Re-initialize temp paths");
4987  SvtPathOptions aOptions;
4988  OUString aNewTemp;
4989  osl::FileBase::getTempDirURL(aNewTemp);
4990  aOptions.SetTempPath(aNewTemp);
4992 
4993  // The RequestHandler is specifically set to be ready when all the other
4994  // init in Desktop::Main (run from soffice_main) is done. We can enable
4995  // the RequestHandler here (without starting any IPC thread;
4996  // shortcutting the invocation in Desktop::Main that would start the IPC
4997  // thread), and can then use it to wait until we're definitely ready to
4998  // continue.
4999 
5000  SAL_INFO("lok", "Enabling RequestHandler");
5001  RequestHandler::Enable(false);
5002  SAL_INFO("lok", "Starting soffice_main");
5003  RequestHandler::SetReady(false);
5004  if (!bUnipoll)
5005  {
5006  // Start the main thread only in non-unipoll mode (i.e. multithreaded).
5007  pLib->maThread = osl_createThread(lo_startmain, nullptr);
5008  SAL_INFO("lok", "Waiting for RequestHandler");
5010  SAL_INFO("lok", "RequestHandler ready -- continuing");
5011  }
5012  else
5013  InitVCL();
5014  }
5015 
5016  if (eStage != SECOND_INIT)
5018 
5019  SAL_INFO("lok", "LOK Initialized");
5020  if (eStage == PRE_INIT)
5021  bPreInited = true;
5022  else
5023  bInitialized = true;
5024  }
5025  catch (css::uno::Exception& exception)
5026  {
5027  fprintf(stderr, "Bootstrapping exception '%s'\n",
5028  OUStringToOString(exception.Message, RTL_TEXTENCODING_UTF8).getStr());
5029  }
5030 
5031  if (eStage == PRE_INIT)
5032  {
5034  }
5035 
5036  return bInitialized;
5037 }
5038 
5039 SAL_JNI_EXPORT
5040 LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user_profile_url)
5041 {
5042  if (!gImpl)
5043  {
5044  SAL_INFO("lok", "Create libreoffice object");
5045 
5046  gImpl = new LibLibreOffice_Impl();
5047  if (!lo_initialize(gImpl, install_path, user_profile_url))
5048  {
5049  lo_destroy(gImpl);
5050  }
5051  }
5052  return static_cast<LibreOfficeKit*>(gImpl);
5053 }
5054 
5055 SAL_JNI_EXPORT
5056 LibreOfficeKit *libreofficekit_hook(const char* install_path)
5057 {
5058  return libreofficekit_hook_2(install_path, nullptr);
5059 }
5060 
5061 SAL_JNI_EXPORT
5062 int lok_preinit(const char* install_path, const char* user_profile_url)
5063 {
5064  return lo_initialize(nullptr, install_path, user_profile_url);
5065 }
5066 
5067 static void lo_destroy(LibreOfficeKit* pThis)
5068 {
5069  SolarMutexClearableGuard aGuard;
5070 
5071  LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
5072  gImpl = nullptr;
5073 
5074  SAL_INFO("lok", "LO Destroy");
5075 
5077  uno::Reference <frame::XDesktop2> xDesktop = frame::Desktop::create ( ::comphelper::getProcessComponentContext() );
5078  // FIXME: the terminate() call here is a no-op because it detects
5079  // that LibreOfficeKit::isActive() and then returns early!
5080  bool bSuccess = xDesktop.is() && xDesktop->terminate();
5081 
5082  if (!bSuccess)
5083  {
5084  bSuccess = GetpApp() && GetpApp()->QueryExit();
5085  }
5086 
5087  if (!bSuccess)
5088  {
5090  }
5091 
5092  aGuard.clear();
5093 
5094  osl_joinWithThread(pLib->maThread);
5095  osl_destroyThread(pLib->maThread);
5096 
5097  delete pLib;
5098  bInitialized = false;
5099  SAL_INFO("lok", "LO Destroy Done");
5100 }
5101 
5102 }
5103 
5104 #ifdef IOS
5105 
5106 // Used by the unmaintained LibreOfficeLight app. Once that has been retired, get rid of this, too.
5107 
5108 extern "C"
5109 {
5110 __attribute__((visibility("default")))
5111 void temporaryHackToInvokeCallbackHandlers(LibreOfficeKitDocument* pThis)
5112 {
5113  SolarMutexGuard aGuard;
5114  LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
5115 
5116  int nOrigViewId = doc_getView(pThis);
5117 
5118  if (nOrigViewId >= 0 && pDocument->mpCallbackFlushHandlers[nOrigViewId])
5119  {
5120  pDocument->mpCallbackFlushHandlers[nOrigViewId]->Invoke();
5121  }
5122 }
5123 }
5124 #endif
5125 
5126 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SfxViewFrame * GetViewFrame() const
virtual void setClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &xClipboard)=0
virtual OUString getPartHash(int nPart)=0
long Width() const
static char * doc_getPartPageRectangles(LibreOfficeKitDocument *pThis)
Definition: init.cxx:2304
static const ExtensionMap aImpressExtensionMap[]
Definition: init.cxx:215
static void doc_postMouseEvent(LibreOfficeKitDocument *pThis, int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
Definition: init.cxx:3128
static vcl::Font GetDefaultFont(DefaultFontType nType, LanguageType eLang, GetDefaultFontFlags nFlags, const OutputDevice *pOutDev=nullptr)
static void doc_setOutlineState(LibreOfficeKitDocument *pThis, bool bColumn, int nLevel, int nIndex, bool bHidden)
Definition: init.cxx:3921
std::map< OString, rtl::Reference< LOKInteractionHandler > > mInteractionMap
Definition: init.hxx:164
SAL_JNI_EXPORT int lok_preinit(const char *install_path, const char *user_profile_url)
Definition: init.cxx:5062
virtual OUString getPostItsPos()
css::uno::Sequence< OUString > getRecordingAndClear()
static int doc_getDocumentType(LibreOfficeKitDocument *pThis)
Definition: init.cxx:2192
static char * getRulerState(LibreOfficeKitDocument *pThis)
Definition: init.cxx:2772
void SetFontSize(const Size &)
sal_Char const sHash[]
OOO_DLLPUBLIC_DBTOOLS double toDouble(const css::util::Date &rVal, const css::util::Date &_rNullDate=getStandardDate())
static VclPtr< vcl::Window > FindLOKWindow(vcl::LOKWindowId nWindowId)
css::uno::Reference< css::frame::XDispatch > GetDispatch(const SfxSlot *, const css::util::URL &aURL, bool bMasterCommand)
IJScriptValueObject VARIANT value
unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)))
const OUString & GetFamilyName() const
const char * extn
Definition: init.cxx:177
static comphelper::SolarMutex & GetSolarMutex()
const boost::property_tree::ptree & getJson() const
Return the parsed JSON instance.
Definition: init.cxx:528
static size_t doc_renderShapeSelection(LibreOfficeKitDocument *pThis, char **pOutput)
Definition: init.cxx:2874
#define KEY_PASTE
static OUString getUString(const char *pString)
Definition: init.cxx:249
const char aData[]
UndoOrRedo
Definition: init.cxx:3601
VCL_DLLPUBLIC OUString getImageUrl(OUString const &name, OUString const &style, OUString const &lang)
OUString toISO8601(const css::util::DateTime &rDateTime)
SfxObjectShell * GetObjectShell() const
static void doc_getDocumentSize(LibreOfficeKitDocument *pThis, long *pWidth, long *pHeight)
Definition: init.cxx:2649
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
virtual void resetSelection()=0
static void setViewLanguage(int nId, const OUString &rBcp47LanguageTag)
static char * getTrackedChangeAuthors(LibreOfficeKitDocument *pThis)
Returns the JSON representation of the redline author table.
Definition: init.cxx:3699
long Height() const
virtual bool isMimeTypeSupported()=0
const SubsetVec & GetSubsetMap() const
tools::Rectangle GetChartBoundingBox()
SAL_JNI_EXPORT LibreOfficeKit * libreofficekit_hook_2(const char *install_path, const char *user_profile_url)
Definition: init.cxx:5040
static void CreateTemporaryDirectory()
Definition: appinit.cxx:233
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
static void lo_registerCallback(LibreOfficeKit *pThis, LibreOfficeKitCallback pCallback, void *pData)
Definition: init.cxx:1880
static void setView(int nId)
static std::size_t getViewsCount()
static ImplSVEvent * PostGestureEvent(VclEventId nEvent, vcl::Window *pWin, GestureEvent const *pGestureEvent)
void setViewIdForVisCursorInvalidation(bool bViewIdForVisCursorInvalidation)
sal_Int32 toInt32(OUString const &rStr)
tools::Rectangle m_aRectangle
Definition: init.hxx:39
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
OUString ReplaceStringHookProc(const OUString &rStr)
Definition: app.cxx:398
OUString GetUndoActionsInfo() const
virtual OString getCellCursor(int, int, long, long)
static int lo_initialize(LibreOfficeKit *pThis, const char *pInstallPath, const char *pUserProfilePath)
Definition: init.cxx:4757
InteractionHandler is an interface that provides the user with various dialogs / error messages...
virtual void initializeForTiledRendering(const css::uno::Sequence< css::beans::PropertyValue > &rArguments)=0
static void lo_destroy(LibreOfficeKit *pThis)
Definition: init.cxx:5067
static int createView()
sal_Int16 nId
static bool doc_getViewIds(LibreOfficeKitDocument *pThis, int *pArray, size_t nSize)
static const ExtensionMap aDrawExtensionMap[]
Definition: init.cxx:236
static LanguageType resolveSystemLanguageByScriptType(LanguageType nLang, sal_Int16 nType)
static uno::Any jsonToUnoAny(const boost::property_tree::ptree &aTree)
Definition: init.cxx:282
#define ASIAN
static void doc_setClientVisibleArea(LibreOfficeKitDocument *pThis, int nX, int nY, int nWidth, int nHeight)
Definition: init.cxx:3903
static int doc_getViewsCount(LibreOfficeKitDocument *pThis)
constexpr::Color COL_LIGHTRED(0xFF, 0x00, 0x00)
static void preloadData()
Used only by LibreOfficeKit when used by Online to pre-initialize.
Definition: init.cxx:4643
static SfxObjectShell * Current()
virtual SfxUndoManager * GetUndoManager()
virtual int getPart()
static void doc_resetSelection(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3326
OUString Name
bool isInfinite() const
Infinite Rectangle is both sides are equal or longer than SfxLokHelper::MaxTwips. ...
Definition: init.hxx:58
OString toString() const
Definition: init.hxx:47
static void lo_runLoop(LibreOfficeKit *pThis, LibreOfficeKitPollCallback pPollCallback, LibreOfficeKitWakeCallback pWakeCallback, void *pData)
Definition: init.cxx:4597
OString maCommand
Command for which this is the result.
Definition: init.cxx:2945
static void lo_freeError(char *pFree)
Definition: init.cxx:4423
virtual void paintTile(VirtualDevice &rDevice, int nOutputWidth, int nOutputHeight, int nTilePosX, int nTilePosY, long nTileWidth, long nTileHeight)=0
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)
Definition: app.cxx:168
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:2419
virtual OString getTextSelection(const char *pMimeType, OString &rUsedMimeType)=0
void setDPIScale(double fDPIScale)
void SetClipboard(css::uno::Reference< css::datatransfer::clipboard::XClipboard > const &xClipboard)
const SfxSlot * GetUnoSlot(const OUString &rUnoName) const
void setLanguageTag(const LanguageTag &languageTag)
static void doc_setPartMode(LibreOfficeKitDocument *pThis, int nPartMode)
Definition: init.cxx:2373
std::vector< OUString > split(const OUString &rStr, sal_Unicode cSeparator)
virtual void setGraphicSelection(int nType, int nX, int nY)=0
std::shared_ptr< LibreOfficeKitClass > m_pOfficeClass
Definition: init.hxx:159
static void doc_postUnoCommand(LibreOfficeKitDocument *pThis, const char *pCommand, const char *pArguments, bool bNotifyWhenFinished)
Definition: init.cxx:2978
static uno::Reference< css::lang::XMultiServiceFactory > xSFactory
Definition: init.cxx:1605
static char * doc_getCommandValues(LibreOfficeKitDocument *pThis, const char *pCommand)
Definition: init.cxx:3711
bool IsEmpty() const
vcl::Window * GetWindow()
Value
std::size_t GetEndOfData() const
static char * lo_getFilterTypes(LibreOfficeKit *pThis)
Definition: init.cxx:4428
static char * doc_getPartName(LibreOfficeKitDocument *pThis, int nPart)
Definition: init.cxx:2327
static VCL_DLLPUBLIC ImageTree & get()
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:259
constexpr::Color COL_TRANSPARENT(0xFF, 0xFF, 0xFF, 0xFF)
virtual int getPart() const
static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent)
Definition: init.cxx:4621
std::unordered_map< int, std::unordered_map< int, std::string > > m_viewStates
Definition: init.hxx:137
OUString SvxResId(const char *pId)
Any SAL_CALL getCaughtException()
SAL_JNI_EXPORT LibreOfficeKit * libreofficekit_hook(const char *install_path)
Definition: init.cxx:5056
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)
virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent &rEvent) override
Definition: init.cxx:2956
const short UNDO
static void aBasicErrorFunc(const OUString &rError, const OUString &rAction)
Definition: init.cxx:4529
void SetLocaleConfigString(const OUString &rStr)
static SfxViewShell * GetNext(const SfxViewShell &rPrev, bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
static SfxViewShell * Current()
static void doc_setViewLanguage(LibreOfficeKitDocument *pThis, int nId, const char *language)
virtual void Start() override
virtual OUString getPartPageRectangles()
static void doc_postWindow(LibreOfficeKitDocument *pThis, unsigned nLOKWindowId, int nAction, const char *pData)
Definition: init.cxx:4206
static void doc_initializeForRendering(LibreOfficeKitDocument *pThis, const char *pArguments)
Definition: init.cxx:2671
static bool HasLanguageType(const LanguageType eType)
static int doc_getSignatureState(LibreOfficeKitDocument *pThis)
Definition: init.cxx:4385
virtual VclPtr< vcl::Window > getDocWindow()=0
static void Quit()
virtual OUString getTrackedChanges()
long Top() const
tools::Rectangle GetIntersection(const tools::Rectangle &rRect) const
Application * GetpApp()
static int doc_createView(LibreOfficeKitDocument *pThis)
Definition: init.cxx:3958
void acquire(sal_uInt32 nLockCount=1)
static int doc_getPart(LibreOfficeKitDocument *pThis)
Definition: init.cxx:2249
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
static bool doc_addCertificate(LibreOfficeKitDocument *pThis, const unsigned char *pCertificateBinary, const int nCertificateBinarySize)
Definition: init.cxx:4327
if(nullptr==pCandidateA||nullptr==pCandidateB)
const sal_IntPtr * GetSizeAry(const FontMetric &rFontMetric) const
void registerPollCallbacks(LibreOfficeKitPollCallback pPollCallback, LibreOfficeKitWakeCallback pWakeCallback, void *pData)
sal_uInt32 release(bool bUnlockAll=false)
css::uno::Reference< css::lang::XComponent > xComponent
css::uno::Reference< css::lang::XComponent > mxComponent
Definition: init.hxx:148
static char * getPostItsPos(LibreOfficeKitDocument *pThis)
Returns the JSON representation of the positions of all the comments in the document.
Definition: init.cxx:2759
static ThreadPool & getSharedOptimalPool()
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:4137
static void lo_startmain(void *)
Definition: init.cxx:4582
static ImplSVEvent * PostMouseEvent(VclEventId nEvent, vcl::Window *pWin, MouseEvent const *pMouseEvent)
static void doc_setView(LibreOfficeKitDocument *pThis, int nId)
const FontMetric & GetFontName(size_t nFont) const
static void callback(const int type, const char *payload, void *data)
Definition: init.cxx:963
Point BottomRight() const
const SfxPoolItem * GetItem(sal_uInt16 nSlotId) const
static SfxApplication * GetOrCreate()
VCL_DLLPUBLIC bool InitVCL()
#define SAL_CONFIGFILE(name)
static char * getStyles(LibreOfficeKitDocument *pThis, const char *pCommand)
Definition: init.cxx:3476
void setRangeHeaders(bool bTiledAnnotations)
void unregisterPollCallbacks()
std::map< size_t, std::shared_ptr< CallbackFlushHandler > > mpCallbackFlushHandlers
Definition: init.hxx:150
SignatureState GetDocumentSignatureState()
bool signDocument(css::uno::Reference< css::security::XCertificate > const &rxCertificate)
static int doc_getTileMode(LibreOfficeKitDocument *pThis)
OUString const & GetURL() const
static int getView(SfxViewShell *pViewShell=nullptr)