Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 : #include <boost/shared_ptr.hpp>
17 : #include <boost/weak_ptr.hpp>
18 : #include <boost/property_tree/json_parser.hpp>
19 :
20 : #define LOK_USE_UNSTABLE_API
21 : #include <LibreOfficeKit/LibreOfficeKit.h>
22 : #include <LibreOfficeKit/LibreOfficeKitEnums.h>
23 :
24 : #include <sal/log.hxx>
25 : #include <tools/errinf.hxx>
26 : #include <osl/file.hxx>
27 : #include <osl/process.h>
28 : #include <osl/thread.h>
29 : #include <rtl/strbuf.hxx>
30 : #include <rtl/bootstrap.hxx>
31 : #include <cppuhelper/bootstrap.hxx>
32 : #include <comphelper/dispatchcommand.hxx>
33 : #include <comphelper/lok.hxx>
34 : #include <comphelper/processfactory.hxx>
35 :
36 : #include <com/sun/star/beans/XPropertySet.hpp>
37 : #include <com/sun/star/frame/Desktop.hpp>
38 : #include <com/sun/star/frame/XStorable.hpp>
39 : #include <com/sun/star/lang/Locale.hpp>
40 : #include <com/sun/star/lang/XComponent.hpp>
41 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 : #include <com/sun/star/ucb/XContentProvider.hpp>
43 : #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
44 :
45 : #include <vcl/svapp.hxx>
46 : #include <vcl/svpforlokit.hxx>
47 : #include <tools/resmgr.hxx>
48 : #include <tools/fract.hxx>
49 : #include <vcl/graphicfilter.hxx>
50 : #include <vcl/sysdata.hxx>
51 : #include <vcl/virdev.hxx>
52 : #include <vcl/ITiledRenderable.hxx>
53 : #include <unotools/syslocaleoptions.hxx>
54 : #include <unotools/mediadescriptor.hxx>
55 : #include <osl/module.hxx>
56 : #include <comphelper/sequence.hxx>
57 :
58 : #include <app.hxx>
59 :
60 : #include "../app/cmdlineargs.hxx"
61 : // We also need to hackily be able to start the main libreoffice thread:
62 : #include "../app/sofficemain.h"
63 : #include "../app/officeipcthread.hxx"
64 :
65 : using namespace css;
66 : using namespace vcl;
67 : using namespace desktop;
68 : using namespace utl;
69 :
70 : using namespace boost;
71 :
72 : struct LibLODocument_Impl;
73 : struct LibLibreOffice_Impl;
74 :
75 : static LibLibreOffice_Impl *gImpl = NULL;
76 116 : static weak_ptr< LibreOfficeKitClass > gOfficeClass;
77 116 : static weak_ptr< LibreOfficeKitDocumentClass > gDocumentClass;
78 :
79 : typedef struct
80 : {
81 : const char *extn;
82 : const char *filterName;
83 : } ExtensionMap;
84 :
85 : // We need a shared_array for passing into the BitmapDevice (via
86 : // VirtualDevice.SetOutputSizePixelScaleOffsetAndBuffer which goes via the
87 : // SvpVirtualDevice, ending up in the basebmp BitmapDevice. However as we're
88 : // given the array externally we can't delete it, and hence need to override
89 : // shared_array's default of deleting its pointer.
90 : template<typename T>
91 : struct NoDelete
92 : {
93 0 : void operator()(T* /* p */) {}
94 : };
95 :
96 : static const ExtensionMap aWriterExtensionMap[] =
97 : {
98 : { "doc", "MS Word 97" },
99 : { "docx", "MS Word 2007 XML" },
100 : { "fodt", "OpenDocument Text Flat XML" },
101 : { "html", "HTML (StarWriter)" },
102 : { "odt", "writer8" },
103 : { "ott", "writer8_template" },
104 : { "pdf", "writer_pdf_Export" },
105 : { "txt", "Text" },
106 : { "xhtml", "XHTML Writer File" },
107 : { NULL, NULL }
108 : };
109 :
110 : static const ExtensionMap aCalcExtensionMap[] =
111 : {
112 : { "csv", "Text - txt - csv (StarCalc)" },
113 : { "fods", "OpenDocument Spreadsheet Flat XML" },
114 : { "html", "HTML (StarCalc)" },
115 : { "ods", "calc8" },
116 : { "ots", "calc8_template" },
117 : { "pdf", "calc_pdf_Export" },
118 : { "xhtml", "XHTML Calc File" },
119 : { "xls", "MS Excel 97" },
120 : { "xlsx", "Calc MS Excel 2007 XML" },
121 : { NULL, NULL }
122 : };
123 :
124 : static const ExtensionMap aImpressExtensionMap[] =
125 : {
126 : { "fodp", "OpenDocument Presentation Flat XML" },
127 : { "html", "impress_html_Export" },
128 : { "odg", "impress8_draw" },
129 : { "odp", "impress8" },
130 : { "otp", "impress8_template" },
131 : { "pdf", "impress_pdf_Export" },
132 : { "potm", "Impress MS PowerPoint 2007 XML Template" },
133 : { "pot", "MS PowerPoint 97 Vorlage" },
134 : { "pptx", "Impress MS PowerPoint 2007 XML" },
135 : { "pps", "MS PowerPoint 97 Autoplay" },
136 : { "ppt", "MS PowerPoint 97" },
137 : { "svg", "impress_svg_Export" },
138 : { "swf", "impress_flash_Export" },
139 : { "xhtml", "XHTML Impress File" },
140 : { NULL, NULL }
141 : };
142 :
143 : static const ExtensionMap aDrawExtensionMap[] =
144 : {
145 : { "fodg", "draw_ODG_FlatXML" },
146 : { "html", "draw_html_Export" },
147 : { "odg", "draw8" },
148 : { "pdf", "draw_pdf_Export" },
149 : { "svg", "draw_svg_Export" },
150 : { "swf", "draw_flash_Export" },
151 : { "xhtml", "XHTML Draw File" },
152 : { NULL, NULL }
153 : };
154 :
155 3 : static OUString getUString(const char* pString)
156 : {
157 3 : if (pString == NULL)
158 0 : return OUString();
159 :
160 3 : OString sString(pString, strlen(pString));
161 3 : return OStringToOUString(sString, RTL_TEXTENCODING_UTF8);
162 : }
163 :
164 : // Try to convert a relative URL to an absolute one
165 3 : static OUString getAbsoluteURL(const char* pURL)
166 : {
167 3 : OUString aURL( getUString( pURL ) );
168 6 : OUString sAbsoluteDocUrl, sWorkingDir, sDocPathUrl;
169 :
170 : // FIXME: this would appear to kill non-file URLs.
171 3 : osl_getProcessWorkingDir(&sWorkingDir.pData);
172 3 : osl::FileBase::getFileURLFromSystemPath( aURL, sDocPathUrl );
173 3 : osl::FileBase::getAbsoluteFileURL(sWorkingDir, sDocPathUrl, sAbsoluteDocUrl);
174 :
175 6 : return sAbsoluteDocUrl;
176 : }
177 :
178 : extern "C"
179 : {
180 :
181 : static void doc_destroy(LibreOfficeKitDocument* pThis);
182 : static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* pUrl, const char* pFormat, const char* pFilterOptions);
183 : static int doc_getDocumentType(LibreOfficeKitDocument* pThis);
184 : static int doc_getParts(LibreOfficeKitDocument* pThis);
185 : static int doc_getPart(LibreOfficeKitDocument* pThis);
186 : static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart);
187 : static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart);
188 : static void doc_setPartMode(LibreOfficeKitDocument* pThis, int nPartMode);
189 : void doc_paintTile(LibreOfficeKitDocument* pThis,
190 : unsigned char* pBuffer,
191 : const int nCanvasWidth, const int nCanvasHeight,
192 : const int nTilePosX, const int nTilePosY,
193 : const int nTileWidth, const int nTileHeight);
194 : static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
195 : long* pWidth,
196 : long* pHeight);
197 : static void doc_initializeForRendering(LibreOfficeKitDocument* pThis);
198 :
199 : static void doc_registerCallback(LibreOfficeKitDocument* pThis,
200 : LibreOfficeKitCallback pCallback,
201 : void* pData);
202 : static void doc_postKeyEvent(LibreOfficeKitDocument* pThis,
203 : int nType,
204 : int nCharCode,
205 : int nKeyCode);
206 : static void doc_postMouseEvent (LibreOfficeKitDocument* pThis,
207 : int nType,
208 : int nX,
209 : int nY,
210 : int nCount);
211 : static void doc_postUnoCommand(LibreOfficeKitDocument* pThis,
212 : const char* pCommand,
213 : const char* pArguments);
214 : static void doc_setTextSelection (LibreOfficeKitDocument* pThis,
215 : int nType,
216 : int nX,
217 : int nY);
218 : static void doc_setGraphicSelection (LibreOfficeKitDocument* pThis,
219 : int nType,
220 : int nX,
221 : int nY);
222 : static void doc_resetSelection (LibreOfficeKitDocument* pThis);
223 :
224 : struct LibLODocument_Impl : public _LibreOfficeKitDocument
225 : {
226 : uno::Reference<css::lang::XComponent> mxComponent;
227 : shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass;
228 :
229 2 : LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent) :
230 2 : mxComponent( xComponent )
231 : {
232 2 : if (!(m_pDocumentClass = gDocumentClass.lock()))
233 : {
234 1 : m_pDocumentClass.reset(new LibreOfficeKitDocumentClass);
235 :
236 1 : m_pDocumentClass->nSize = sizeof(LibreOfficeKitDocument);
237 :
238 1 : m_pDocumentClass->destroy = doc_destroy;
239 1 : m_pDocumentClass->saveAs = doc_saveAs;
240 1 : m_pDocumentClass->getDocumentType = doc_getDocumentType;
241 1 : m_pDocumentClass->getParts = doc_getParts;
242 1 : m_pDocumentClass->getPart = doc_getPart;
243 1 : m_pDocumentClass->setPart = doc_setPart;
244 1 : m_pDocumentClass->getPartName = doc_getPartName;
245 1 : m_pDocumentClass->setPartMode = doc_setPartMode;
246 1 : m_pDocumentClass->paintTile = doc_paintTile;
247 1 : m_pDocumentClass->getDocumentSize = doc_getDocumentSize;
248 1 : m_pDocumentClass->initializeForRendering = doc_initializeForRendering;
249 1 : m_pDocumentClass->registerCallback = doc_registerCallback;
250 1 : m_pDocumentClass->postKeyEvent = doc_postKeyEvent;
251 1 : m_pDocumentClass->postMouseEvent = doc_postMouseEvent;
252 1 : m_pDocumentClass->postUnoCommand = doc_postUnoCommand;
253 1 : m_pDocumentClass->setTextSelection = doc_setTextSelection;
254 1 : m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection;
255 1 : m_pDocumentClass->resetSelection = doc_resetSelection;
256 :
257 1 : gDocumentClass = m_pDocumentClass;
258 : }
259 2 : pClass = m_pDocumentClass.get();
260 2 : }
261 :
262 2 : ~LibLODocument_Impl()
263 2 : {
264 2 : mxComponent->dispose();
265 2 : }
266 : };
267 :
268 2 : static void doc_destroy(LibreOfficeKitDocument *pThis)
269 : {
270 2 : LibLODocument_Impl *pDocument = static_cast<LibLODocument_Impl*>(pThis);
271 2 : delete pDocument;
272 2 : }
273 :
274 : static void lo_destroy (LibreOfficeKit* pThis);
275 : static int lo_initialize (LibreOfficeKit* pThis, const char* pInstallPath, const char* pUserProfilePath);
276 : static LibreOfficeKitDocument* lo_documentLoad (LibreOfficeKit* pThis, const char* pURL);
277 : static char * lo_getError (LibreOfficeKit* pThis);
278 : static LibreOfficeKitDocument* lo_documentLoadWithOptions (LibreOfficeKit* pThis,
279 : const char* pURL,
280 : const char* pOptions);
281 : static void lo_registerCallback (LibreOfficeKit* pThis,
282 : LibreOfficeKitCallback pCallback,
283 : void* pData);
284 :
285 1 : struct LibLibreOffice_Impl : public _LibreOfficeKit
286 : {
287 : OUString maLastExceptionMsg;
288 : shared_ptr< LibreOfficeKitClass > m_pOfficeClass;
289 : oslThread maThread;
290 : LibreOfficeKitCallback mpCallback;
291 : void *mpCallbackData;
292 :
293 1 : LibLibreOffice_Impl()
294 : : maThread(0)
295 : , mpCallback(nullptr)
296 1 : , mpCallbackData(nullptr)
297 : {
298 1 : if(!(m_pOfficeClass = gOfficeClass.lock())) {
299 1 : m_pOfficeClass.reset(new LibreOfficeKitClass);
300 1 : m_pOfficeClass->nSize = sizeof(LibreOfficeKitClass);
301 :
302 1 : m_pOfficeClass->destroy = lo_destroy;
303 1 : m_pOfficeClass->documentLoad = lo_documentLoad;
304 1 : m_pOfficeClass->getError = lo_getError;
305 1 : m_pOfficeClass->documentLoadWithOptions = lo_documentLoadWithOptions;
306 1 : m_pOfficeClass->registerCallback = lo_registerCallback;
307 :
308 1 : gOfficeClass = m_pOfficeClass;
309 : }
310 :
311 1 : pClass = m_pOfficeClass.get();
312 1 : }
313 : };
314 :
315 : namespace
316 : {
317 :
318 0 : ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
319 : {
320 0 : LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
321 0 : return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get());
322 : }
323 :
324 : } // anonymous namespace
325 :
326 : // Wonder global state ...
327 116 : static uno::Reference<css::uno::XComponentContext> xContext;
328 116 : static uno::Reference<css::lang::XMultiServiceFactory> xSFactory;
329 116 : static uno::Reference<css::lang::XMultiComponentFactory> xFactory;
330 :
331 0 : static LibreOfficeKitDocument* lo_documentLoad(LibreOfficeKit* pThis, const char* pURL)
332 : {
333 0 : return lo_documentLoadWithOptions(pThis, pURL, NULL);
334 : }
335 :
336 3 : static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis, const char* pURL, const char* pOptions)
337 : {
338 3 : LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
339 :
340 3 : SolarMutexGuard aGuard;
341 :
342 6 : OUString aURL = getAbsoluteURL(pURL);
343 :
344 3 : pLib->maLastExceptionMsg.clear();
345 :
346 3 : if (!xContext.is())
347 : {
348 0 : pLib->maLastExceptionMsg = "ComponentContext is not available";
349 : SAL_INFO("lok", "ComponentContext is not available");
350 0 : return NULL;
351 : }
352 :
353 6 : uno::Reference<frame::XDesktop2> xComponentLoader = frame::Desktop::create(xContext);
354 :
355 3 : if (!xComponentLoader.is())
356 : {
357 0 : pLib->maLastExceptionMsg = "ComponentLoader is not available";
358 : SAL_INFO("lok", "ComponentLoader is not available");
359 0 : return NULL;
360 : }
361 :
362 : try
363 : {
364 3 : uno::Sequence<css::beans::PropertyValue> aFilterOptions(1);
365 6 : aFilterOptions[0] = css::beans::PropertyValue( OUString("FilterOptions"),
366 : 0,
367 : uno::makeAny(OUString::createFromAscii(pOptions)),
368 3 : beans::PropertyState_DIRECT_VALUE);
369 6 : uno::Reference<lang::XComponent> xComponent;
370 8 : xComponent = xComponentLoader->loadComponentFromURL(
371 : aURL, OUString("_blank"), 0,
372 5 : aFilterOptions);
373 :
374 2 : if (!xComponent.is())
375 : {
376 0 : pLib->maLastExceptionMsg = "loadComponentFromURL returned an empty reference";
377 : SAL_INFO("lok", "Document can't be loaded - " << pLib->maLastExceptionMsg);
378 0 : return NULL;
379 : }
380 :
381 5 : return new LibLODocument_Impl(xComponent);
382 :
383 : }
384 2 : catch (const uno::Exception& exception)
385 : {
386 1 : pLib->maLastExceptionMsg = exception.Message;
387 : SAL_INFO("lok", "Document can't be loaded - exception: " << exception.Message);
388 : }
389 :
390 4 : return NULL;
391 : }
392 :
393 0 : static void lo_registerCallback (LibreOfficeKit* pThis,
394 : LibreOfficeKitCallback pCallback,
395 : void* pData)
396 : {
397 0 : LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
398 :
399 0 : pLib->mpCallback = pCallback;
400 0 : pLib->mpCallbackData = pData;
401 0 : }
402 :
403 0 : static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const char* pFormat, const char* pFilterOptions)
404 : {
405 0 : LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
406 :
407 0 : OUString sFormat = getUString(pFormat);
408 0 : OUString aURL = getAbsoluteURL(sUrl);
409 :
410 : try
411 : {
412 : const ExtensionMap* pMap;
413 :
414 0 : switch (doc_getDocumentType(pThis))
415 : {
416 : case LOK_DOCTYPE_SPREADSHEET:
417 0 : pMap = aCalcExtensionMap;
418 0 : break;
419 : case LOK_DOCTYPE_PRESENTATION:
420 0 : pMap = aImpressExtensionMap;
421 0 : break;
422 : case LOK_DOCTYPE_DRAWING:
423 0 : pMap = aDrawExtensionMap;
424 0 : break;
425 : case LOK_DOCTYPE_TEXT:
426 0 : pMap = aWriterExtensionMap;
427 0 : break;
428 : case LOK_DOCTYPE_OTHER:
429 : default:
430 0 : return false;
431 : }
432 :
433 0 : if (pFormat == NULL)
434 : {
435 : // sniff from the extension
436 0 : sal_Int32 idx = aURL.lastIndexOf(".");
437 0 : if( idx > 0 )
438 : {
439 0 : sFormat = aURL.copy( idx + 1 );
440 : }
441 : else
442 : {
443 0 : gImpl->maLastExceptionMsg = "input filename without a suffix";
444 0 : return false;
445 : }
446 : }
447 :
448 0 : OUString aFilterName;
449 0 : for (sal_Int32 i = 0; pMap[i].extn; ++i)
450 : {
451 0 : if (sFormat.equalsIgnoreAsciiCaseAscii(pMap[i].extn))
452 : {
453 0 : aFilterName = getUString(pMap[i].filterName);
454 0 : break;
455 : }
456 : }
457 0 : if (aFilterName.isEmpty())
458 : {
459 0 : gImpl->maLastExceptionMsg = "no output filter found for provided suffix";
460 0 : return false;
461 : }
462 :
463 0 : OUString aFilterOptions = getUString(pFilterOptions);
464 :
465 0 : MediaDescriptor aSaveMediaDescriptor;
466 0 : aSaveMediaDescriptor["Overwrite"] <<= sal_True;
467 0 : aSaveMediaDescriptor["FilterName"] <<= aFilterName;
468 0 : aSaveMediaDescriptor[MediaDescriptor::PROP_FILTEROPTIONS()] <<= aFilterOptions;
469 :
470 0 : uno::Reference<frame::XStorable> xStorable(pDocument->mxComponent, uno::UNO_QUERY_THROW);
471 0 : xStorable->storeToURL(aURL, aSaveMediaDescriptor.getAsConstPropertyValueList());
472 :
473 0 : return true;
474 : }
475 0 : catch (const uno::Exception& exception)
476 : {
477 0 : gImpl->maLastExceptionMsg = "exception: " + exception.Message;
478 : }
479 0 : return false;
480 : }
481 :
482 2 : static int doc_getDocumentType (LibreOfficeKitDocument* pThis)
483 : {
484 2 : LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
485 :
486 : try
487 : {
488 2 : uno::Reference<lang::XServiceInfo> xDocument(pDocument->mxComponent, uno::UNO_QUERY_THROW);
489 :
490 2 : if (xDocument->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
491 : {
492 0 : return LOK_DOCTYPE_SPREADSHEET;
493 : }
494 2 : else if (xDocument->supportsService("com.sun.star.presentation.PresentationDocument"))
495 : {
496 1 : return LOK_DOCTYPE_PRESENTATION;
497 : }
498 1 : else if (xDocument->supportsService("com.sun.star.drawing.DrawingDocument"))
499 : {
500 0 : return LOK_DOCTYPE_DRAWING;
501 : }
502 1 : else if (xDocument->supportsService("com.sun.star.text.TextDocument"))
503 : {
504 1 : return LOK_DOCTYPE_TEXT;
505 : }
506 : else
507 : {
508 0 : gImpl->maLastExceptionMsg = "unknown document type";
509 0 : }
510 : }
511 0 : catch (const uno::Exception& exception)
512 : {
513 0 : gImpl->maLastExceptionMsg = "exception: " + exception.Message;
514 : }
515 0 : return LOK_DOCTYPE_OTHER;
516 : }
517 :
518 0 : static int doc_getParts (LibreOfficeKitDocument* pThis)
519 : {
520 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
521 0 : if (!pDoc)
522 : {
523 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
524 0 : return 0;
525 : }
526 :
527 0 : return pDoc->getParts();
528 : }
529 :
530 0 : static int doc_getPart (LibreOfficeKitDocument* pThis)
531 : {
532 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
533 0 : if (!pDoc)
534 : {
535 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
536 0 : return 0;
537 : }
538 :
539 0 : return pDoc->getPart();
540 : }
541 :
542 0 : static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart)
543 : {
544 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
545 0 : if (!pDoc)
546 : {
547 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
548 0 : return;
549 : }
550 :
551 0 : SolarMutexGuard aGuard;
552 0 : pDoc->setPart( nPart );
553 : }
554 :
555 0 : static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart)
556 : {
557 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
558 0 : if (!pDoc)
559 : {
560 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
561 0 : return 0;
562 : }
563 :
564 0 : OUString sName = pDoc->getPartName( nPart );
565 0 : OString aString = OUStringToOString(sName, RTL_TEXTENCODING_UTF8);
566 0 : char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
567 0 : strcpy(pMemory, aString.getStr());
568 0 : return pMemory;
569 :
570 : }
571 :
572 0 : static void doc_setPartMode(LibreOfficeKitDocument* pThis,
573 : int nPartMode)
574 : {
575 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
576 0 : if (!pDoc)
577 : {
578 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
579 0 : return;
580 : }
581 :
582 0 : SolarMutexGuard aGuard;
583 :
584 0 : int nCurrentPart = pDoc->getPart();
585 :
586 0 : pDoc->setPartMode(nPartMode);
587 :
588 : // We need to make sure the internal state is updated, just changing the mode
589 : // might not update the relevant shells (i.e. impress will keep rendering the
590 : // previous mode unless we do this).
591 : // TODO: we might want to do this within the relevant components rather than
592 : // here, but that's also dependent on how we implement embedded object
593 : // rendering I guess?
594 : // TODO: we could be clever and e.g. set to 0 when we change to/from
595 : // embedded object mode, and not when changing between slide/notes/combined
596 : // modes?
597 0 : if ( nCurrentPart < pDoc->getParts() )
598 : {
599 0 : pDoc->setPart( nCurrentPart );
600 : }
601 : else
602 : {
603 0 : pDoc->setPart( 0 );
604 0 : }
605 : }
606 :
607 0 : void doc_paintTile (LibreOfficeKitDocument* pThis,
608 : unsigned char* pBuffer,
609 : const int nCanvasWidth, const int nCanvasHeight,
610 : const int nTilePosX, const int nTilePosY,
611 : const int nTileWidth, const int nTileHeight)
612 : {
613 : SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth << "x" << nTileHeight <<
614 : "]@(" << nTilePosX << ", " << nTilePosY << ") to [" <<
615 : nCanvasWidth << "x" << nCanvasHeight << "]px" );
616 :
617 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
618 0 : if (!pDoc)
619 : {
620 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
621 0 : return;
622 : }
623 :
624 0 : SolarMutexGuard aGuard;
625 :
626 : #if defined(UNX) && !defined(MACOSX) && !defined(ENABLE_HEADLESS)
627 :
628 : #ifndef IOS
629 0 : InitSvpForLibreOfficeKit();
630 :
631 0 : ScopedVclPtrInstance< VirtualDevice > pDevice(nullptr, Size(1, 1), (sal_uInt16)32) ;
632 0 : boost::shared_array< sal_uInt8 > aBuffer( pBuffer, NoDelete< sal_uInt8 >() );
633 : pDevice->SetOutputSizePixelScaleOffsetAndBuffer(
634 : Size(nCanvasWidth, nCanvasHeight), Fraction(1.0), Point(),
635 0 : aBuffer, true );
636 :
637 0 : pDoc->paintTile(*pDevice.get(), nCanvasWidth, nCanvasHeight,
638 0 : nTilePosX, nTilePosY, nTileWidth, nTileHeight);
639 : #else
640 : SystemGraphicsData aData;
641 : aData.rCGContext = reinterpret_cast<CGContextRef>(pBuffer);
642 : // the Size argument is irrelevant, I hope
643 : ScopedVclPtrInstance<VirtualDevice> pDevice(&aData, Size(1, 1), (sal_uInt16)0);
644 :
645 : pDoc->paintTile(*pDevice.get(), nCanvasWidth, nCanvasHeight,
646 : nTilePosX, nTilePosY, nTileWidth, nTileHeight);
647 : #endif
648 :
649 0 : static bool bDebug = getenv("LOK_DEBUG") != 0;
650 0 : if (bDebug)
651 : {
652 : // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
653 0 : Rectangle aRect(0, 0, 5, 5);
654 0 : aRect = pDevice->PixelToLogic(aRect);
655 0 : pDevice->Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
656 0 : pDevice->SetFillColor(COL_LIGHTRED);
657 0 : pDevice->SetLineColor();
658 0 : pDevice->DrawRect(aRect);
659 0 : pDevice->Pop();
660 0 : }
661 :
662 : #else
663 : (void) pBuffer;
664 : (void) nCanvasWidth;
665 : (void) nCanvasHeight;
666 : (void) nTilePosX;
667 : (void) nTilePosY;
668 : (void) nTileWidth;
669 : (void) nTileHeight;
670 : #endif
671 : }
672 :
673 0 : static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
674 : long* pWidth,
675 : long* pHeight)
676 : {
677 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
678 0 : if (pDoc)
679 : {
680 0 : Size aDocumentSize = pDoc->getDocumentSize();
681 0 : *pWidth = aDocumentSize.Width();
682 0 : *pHeight = aDocumentSize.Height();
683 : }
684 : else
685 : {
686 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
687 : }
688 0 : }
689 :
690 0 : static void doc_initializeForRendering(LibreOfficeKitDocument* pThis)
691 : {
692 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
693 0 : if (pDoc)
694 : {
695 0 : pDoc->initializeForTiledRendering();
696 : }
697 0 : }
698 :
699 0 : static void doc_registerCallback(LibreOfficeKitDocument* pThis,
700 : LibreOfficeKitCallback pCallback,
701 : void* pData)
702 : {
703 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
704 0 : if (!pDoc)
705 : {
706 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
707 0 : return;
708 : }
709 :
710 0 : pDoc->registerCallback(pCallback, pData);
711 : }
712 :
713 0 : static void doc_postKeyEvent(LibreOfficeKitDocument* pThis, int nType, int nCharCode, int nKeyCode)
714 : {
715 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
716 0 : if (!pDoc)
717 : {
718 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
719 0 : return;
720 : }
721 :
722 0 : pDoc->postKeyEvent(nType, nCharCode, nKeyCode);
723 : }
724 :
725 1 : static void jsonToPropertyValues(const char* pJSON, uno::Sequence<beans::PropertyValue>& rPropertyValues)
726 : {
727 1 : std::vector<beans::PropertyValue> aArguments;
728 1 : if (pJSON)
729 : {
730 0 : boost::property_tree::ptree aTree;
731 0 : std::stringstream aStream(pJSON);
732 0 : boost::property_tree::read_json(aStream, aTree);
733 :
734 0 : for (const std::pair<std::string, boost::property_tree::ptree>& rPair : aTree)
735 : {
736 0 : const std::string& rType = rPair.second.get<std::string>("type");
737 0 : const std::string& rValue = rPair.second.get<std::string>("value");
738 :
739 0 : beans::PropertyValue aValue;
740 0 : aValue.Name = OUString::fromUtf8(rPair.first.c_str());
741 0 : if (rType == "string")
742 0 : aValue.Value <<= OUString::fromUtf8(rValue.c_str());
743 0 : else if (rType == "boolean")
744 0 : aValue.Value <<= OString(rValue.c_str()).toBoolean();
745 0 : else if (rType == "long")
746 0 : aValue.Value <<= OString(rValue.c_str()).toInt32();
747 : else
748 : SAL_WARN("desktop.lib", "jsonToPropertyValues: unhandled type '"<<rType<<"'");
749 0 : aArguments.push_back(aValue);
750 0 : }
751 : }
752 1 : rPropertyValues = comphelper::containerToSequence(aArguments);
753 1 : }
754 :
755 1 : static void doc_postUnoCommand(LibreOfficeKitDocument* /*pThis*/, const char* pCommand, const char* pArguments)
756 : {
757 1 : OUString aCommand(pCommand, strlen(pCommand), RTL_TEXTENCODING_UTF8);
758 :
759 2 : uno::Sequence<beans::PropertyValue> aPropertyValues;
760 1 : jsonToPropertyValues(pArguments, aPropertyValues);
761 1 : if (!comphelper::dispatchCommand(aCommand, aPropertyValues))
762 : {
763 0 : gImpl->maLastExceptionMsg = "Failed to dispatch the .uno: command";
764 1 : }
765 1 : }
766 :
767 0 : static void doc_postMouseEvent(LibreOfficeKitDocument* pThis, int nType, int nX, int nY, int nCount)
768 : {
769 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
770 0 : if (!pDoc)
771 : {
772 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
773 0 : return;
774 : }
775 :
776 0 : pDoc->postMouseEvent(nType, nX, nY, nCount);
777 : }
778 :
779 0 : static void doc_setTextSelection(LibreOfficeKitDocument* pThis, int nType, int nX, int nY)
780 : {
781 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
782 0 : if (!pDoc)
783 : {
784 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
785 0 : return;
786 : }
787 :
788 0 : pDoc->setTextSelection(nType, nX, nY);
789 : }
790 :
791 0 : static void doc_setGraphicSelection(LibreOfficeKitDocument* pThis, int nType, int nX, int nY)
792 : {
793 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
794 0 : if (!pDoc)
795 : {
796 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
797 0 : return;
798 : }
799 :
800 0 : pDoc->setGraphicSelection(nType, nX, nY);
801 : }
802 :
803 0 : static void doc_resetSelection(LibreOfficeKitDocument* pThis)
804 : {
805 0 : ITiledRenderable* pDoc = getTiledRenderable(pThis);
806 0 : if (!pDoc)
807 : {
808 0 : gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
809 0 : return;
810 : }
811 :
812 0 : pDoc->resetSelection();
813 : }
814 :
815 0 : static char* lo_getError (LibreOfficeKit *pThis)
816 : {
817 0 : LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
818 0 : OString aString = OUStringToOString(pLib->maLastExceptionMsg, RTL_TEXTENCODING_UTF8);
819 0 : char* pMemory = static_cast<char*>(malloc(aString.getLength() + 1));
820 0 : strcpy(pMemory, aString.getStr());
821 0 : return pMemory;
822 : }
823 :
824 1 : static void force_c_locale()
825 : {
826 : // force locale (and resource files loaded) to en-US
827 1 : OUString aLangISO("en-US");
828 2 : LanguageTag aLocale(aLangISO);
829 1 : ResMgr::SetDefaultLocale(aLocale);
830 2 : SvtSysLocaleOptions aLocalOptions;
831 1 : aLocalOptions.SetLocaleConfigString(aLangISO);
832 2 : aLocalOptions.SetUILocaleConfigString(aLangISO);
833 1 : }
834 :
835 0 : static void aBasicErrorFunc(const OUString& rError, const OUString& rAction)
836 : {
837 0 : OStringBuffer aBuffer("Unexpected dialog: ");
838 0 : aBuffer.append(OUStringToOString(rAction, RTL_TEXTENCODING_ASCII_US));
839 0 : aBuffer.append(" Error: ");
840 0 : aBuffer.append(OUStringToOString(rError, RTL_TEXTENCODING_ASCII_US));
841 :
842 0 : fprintf(stderr, "Unexpected basic error dialog '%s'\n", aBuffer.getStr());
843 0 : }
844 :
845 1 : static bool initialize_uno(const OUString& aAppProgramURL)
846 : {
847 : #ifdef IOS
848 : // For iOS we already hardocde the inifile as "rc" in the .app directory.
849 : (void) aAppProgramURL;
850 : #elif defined MACOSX
851 : rtl::Bootstrap::setIniFilename(aAppProgramURL + "/../Resources/" SAL_CONFIGFILE("soffice"));
852 : #else
853 1 : rtl::Bootstrap::setIniFilename(aAppProgramURL + "/" SAL_CONFIGFILE("soffice"));
854 : #endif
855 :
856 1 : xContext = cppu::defaultBootstrap_InitialComponentContext();
857 1 : if (!xContext.is())
858 : {
859 0 : gImpl->maLastExceptionMsg = "XComponentContext could not be created";
860 : SAL_INFO("lok", "XComponentContext could not be created");
861 0 : return false;
862 : }
863 :
864 1 : xFactory = xContext->getServiceManager();
865 1 : if (!xFactory.is())
866 : {
867 0 : gImpl->maLastExceptionMsg = "XMultiComponentFactory could not be created";
868 : SAL_INFO("lok", "XMultiComponentFactory could not be created");
869 0 : return false;
870 : }
871 :
872 1 : xSFactory = uno::Reference<lang::XMultiServiceFactory>(xFactory, uno::UNO_QUERY_THROW);
873 1 : if (!xSFactory.is())
874 : {
875 0 : gImpl->maLastExceptionMsg = "XMultiServiceFactory could not be created";
876 : SAL_INFO("lok", "XMultiServiceFactory could not be created");
877 0 : return false;
878 : }
879 1 : comphelper::setProcessServiceFactory(xSFactory);
880 :
881 : SAL_INFO("lok", "Uno initialized - " << xContext.is());
882 :
883 : // set UserInstallation to user profile dir in test/user-template
884 : // rtl::Bootstrap aDefaultVars;
885 : // aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
886 : // configmgr setup ?
887 :
888 1 : return true;
889 : }
890 :
891 1 : static void lo_startmain(void*)
892 : {
893 1 : soffice_main();
894 1 : }
895 :
896 : static bool bInitialized = false;
897 :
898 80 : static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent)
899 : {
900 80 : LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(data);
901 :
902 80 : if (!pLib->mpCallback)
903 160 : return;
904 :
905 0 : switch (type)
906 : {
907 : case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start:
908 0 : pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START, 0, pLib->mpCallbackData);
909 0 : break;
910 : case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue:
911 0 : pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE, OUString::number(percent).toUtf8().getStr(), pLib->mpCallbackData);
912 0 : break;
913 : case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Finish:
914 0 : pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH, 0, pLib->mpCallbackData);
915 0 : break;
916 : }
917 : }
918 :
919 1 : static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char* pUserProfilePath)
920 : {
921 1 : LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
922 :
923 1 : if (bInitialized)
924 0 : return 1;
925 :
926 1 : comphelper::LibreOfficeKit::setActive();
927 1 : comphelper::LibreOfficeKit::setStatusIndicatorCallback(lo_status_indicator_callback, pLib);
928 :
929 1 : if (pUserProfilePath)
930 0 : rtl::Bootstrap::set(OUString("UserInstallation"), OUString(pUserProfilePath, strlen(pUserProfilePath), RTL_TEXTENCODING_UTF8));
931 :
932 1 : OUString aAppPath;
933 1 : if (pAppPath)
934 : {
935 1 : aAppPath = OUString(pAppPath, strlen(pAppPath), RTL_TEXTENCODING_UTF8);
936 : }
937 : else
938 : {
939 : // Fun conversion dance back and forth between URLs and system paths...
940 0 : OUString aAppURL;
941 : ::osl::Module::getUrlFromAddress( reinterpret_cast< oslGenericFunction >(lo_initialize),
942 0 : aAppURL);
943 0 : osl::FileBase::getSystemPathFromFileURL( aAppURL, aAppPath );
944 : }
945 :
946 2 : OUString aAppURL;
947 1 : if (osl::FileBase::getFileURLFromSystemPath(aAppPath, aAppURL) != osl::FileBase::E_None)
948 0 : return 0;
949 :
950 : try
951 : {
952 : SAL_INFO("lok", "Attempting to initalize UNO");
953 1 : if (!initialize_uno(aAppURL))
954 : {
955 0 : return false;
956 : }
957 1 : force_c_locale();
958 :
959 : // Force headless -- this is only for bitmap rendering.
960 1 : rtl::Bootstrap::set("SAL_USE_VCLPLUGIN", "svp");
961 :
962 : // We specifically need to make sure we have the "headless"
963 : // command arg set (various code specifically checks via
964 : // CommandLineArgs):
965 1 : desktop::Desktop::GetCommandLineArgs().setHeadless();
966 :
967 1 : Application::EnableHeadlessMode(true);
968 :
969 : // This is horrible crack. I really would want to go back to simply just call
970 : // InitVCL() here. The OfficeIPCThread thing is just horrible.
971 :
972 : // We could use InitVCL() here -- and used to before using soffice_main,
973 : // however that now deals with the initialisation for us (and it's not
974 : // possible to try to set up VCL twice.
975 :
976 : // Instead VCL init is done for us by soffice_main in a separate thread,
977 : // however we specifically can't proceed until this setup is complete
978 : // (or you get segfaults trying to use VCL and/or deadlocks due to other
979 : // setup within soffice_main). Specifically the various Application::
980 : // functions depend on VCL being ready -- the deadlocks would happen
981 : // if you try to use loadDocument too early.
982 :
983 : // The OfficeIPCThread is specifically set to be read when all the other
984 : // init in Desktop::Main (run from soffice_main) is done. We can "enable"
985 : // the Thread from wherever (it's done again in Desktop::Main), and can
986 : // then use it to wait until we're definitely ready to continue.
987 :
988 : SAL_INFO("lok", "Enabling OfficeIPCThread");
989 1 : OfficeIPCThread::EnableOfficeIPCThread();
990 : SAL_INFO("lok", "Starting soffice_main");
991 1 : pLib->maThread = osl_createThread(lo_startmain, NULL);
992 : SAL_INFO("lok", "Waiting for OfficeIPCThread");
993 1 : OfficeIPCThread::WaitForReady();
994 : SAL_INFO("lok", "OfficeIPCThread ready -- continuing");
995 :
996 : // If the Thread has been disabled again that indicates that a
997 : // restart is required (or in any case we don't have a useable
998 : // process around).
999 1 : if (!OfficeIPCThread::IsEnabled())
1000 : {
1001 0 : fprintf(stderr, "LOK init failed -- restart required\n");
1002 0 : return false;
1003 : }
1004 :
1005 1 : ErrorHandler::RegisterDisplay(aBasicErrorFunc);
1006 :
1007 : SAL_INFO("lok", "LOK Initialized");
1008 1 : bInitialized = true;
1009 : }
1010 0 : catch (css::uno::Exception& exception)
1011 : {
1012 : fprintf(stderr, "Bootstrapping exception '%s'\n",
1013 0 : OUStringToOString(exception.Message, RTL_TEXTENCODING_UTF8).getStr());
1014 : }
1015 2 : return bInitialized;
1016 : }
1017 :
1018 : // Undo our clever trick of having SAL_DLLPUBLIC_EXPORT actually not
1019 : // meaning what is says in for the DISABLE_DYNLOADING case. See
1020 : // <sal/types.h>. Normally, when building just one big dylib (Android)
1021 : // or executable (iOS), most of our "public" symbols don't need to be
1022 : // visible outside that resulting dylib/executable. But
1023 : // libreofficekit_hook must be exported for dlsym() to find it,
1024 : // though, at least on iOS.
1025 :
1026 : #if defined(__GNUC__) && defined(HAVE_GCC_VISIBILITY_FEATURE) && defined(DISABLE_DYNLOADING)
1027 : __attribute__ ((visibility("default")))
1028 : #else
1029 : SAL_DLLPUBLIC_EXPORT
1030 : #endif
1031 1 : LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user_profile_path)
1032 : {
1033 1 : if (!gImpl)
1034 : {
1035 : SAL_INFO("lok", "Create libreoffice object");
1036 :
1037 1 : gImpl = new LibLibreOffice_Impl();
1038 1 : if (!lo_initialize(gImpl, install_path, user_profile_path))
1039 : {
1040 0 : lo_destroy(gImpl);
1041 : }
1042 : }
1043 1 : return static_cast<LibreOfficeKit*>(gImpl);
1044 : }
1045 :
1046 : #if defined(__GNUC__) && defined(HAVE_GCC_VISIBILITY_FEATURE) && defined(DISABLE_DYNLOADING)
1047 : __attribute__ ((visibility("default")))
1048 : #else
1049 : SAL_DLLPUBLIC_EXPORT
1050 : #endif
1051 0 : LibreOfficeKit *libreofficekit_hook(const char* install_path)
1052 : {
1053 0 : return libreofficekit_hook_2(install_path, NULL);
1054 : }
1055 :
1056 1 : static void lo_destroy(LibreOfficeKit* pThis)
1057 : {
1058 1 : LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
1059 1 : gImpl = NULL;
1060 :
1061 : SAL_INFO("lok", "LO Destroy");
1062 :
1063 1 : comphelper::LibreOfficeKit::setStatusIndicatorCallback(0, 0);
1064 :
1065 1 : Application::Quit();
1066 1 : osl_joinWithThread(pLib->maThread);
1067 1 : osl_destroyThread(pLib->maThread);
1068 :
1069 1 : delete pLib;
1070 1 : bInitialized = false;
1071 : SAL_INFO("lok", "LO Destroy Done");
1072 1 : }
1073 :
1074 348 : }
1075 :
1076 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|