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