/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sfx2/lokhelper.hxx>
#include <sal/types.h>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <config_buildconfig.h>
#include <config_cairo_rgba.h>
#include <config_features.h>
#include <editeng/unolingu.hxx>
#include <stdio.h>
#ifdef IOS
#include <sys/mman.h>
#include <sys/stat.h>
#include <unicode/udata.h>
#include <unicode/ucnv.h>
#include <premac.h>
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#include <postmac.h>
#endif
#undef HAVE_MALLOC_TRIM
#ifdef UNX
# include <fcntl.h>
#endif
#ifdef LINUX
#if defined __GLIBC__
# include <malloc.h>
# define HAVE_MALLOC_TRIM
#endif
#endif
#ifdef ANDROID
#include <osl/detail/android-bootstrap.h>
#endif
#ifdef EMSCRIPTEN
#include <osl/detail/emscripten-bootstrap.h>
#endif
#include <algorithm>
#include <memory>
#include <iostream>
#include <string_view>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string.hpp>
#include <LibreOfficeKit/LibreOfficeKit.h>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <sal/log.hxx>
#include <utility>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/errinf.hxx>
#include <vcl/lok.hxx>
#include <o3tl/any.hxx>
#include <o3tl/unit_conversion.hxx>
#include <o3tl/string_view.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <osl/thread.h>
#include <rtl/bootstrap.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/uri.hxx>
#include <svl/cryptosign.hxx>
#include <linguistic/misc.hxx>
#include <salhelper/timer.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <comphelper/random.hxx>
#include <comphelper/base64.hxx>
#include <comphelper/dispatchcommand.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <comphelper/profilezone.hxx>
#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/scopeguard.hxx>
#include <comphelper/threadpool.hxx>
#include <comphelper/types.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <com/sun/star/connection/XConnection.hpp>
#include <com/sun/star/document/MacroExecMode.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/document/XTypeDetection.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/DispatchResultEvent.hpp>
#include <com/sun/star/frame/DispatchResultState.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/frame/XDispatchResultListener.hpp>
#include <com/sun/star/frame/XSynchronousDispatch.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/util/thePathSettings.hpp>
#include <com/sun/star/util/PathSubstitution.hpp>
#include <com/sun/star/util/URLTransformer.hpp>
#include <com/sun/star/util/XFlushable.hpp>
#include <com/sun/star/configuration/theDefaultProvider.hpp>
#include <com/sun/star/configuration/Update.hpp>
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
#include <com/sun/star/datatransfer/XTransferable2.hpp>
#include <com/sun/star/text/TextContentAnchorType.hpp>
#include <com/sun/star/document/XRedlinesSupplier.hpp>
#include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
#include <com/sun/star/bridge/BridgeFactory.hpp>
#include <com/sun/star/bridge/XBridgeFactory.hpp>
#include <com/sun/star/bridge/XBridge.hpp>
#include <com/sun/star/uno/XNamingService.hpp>
#include <com/sun/star/xml/crypto/SEInitializer.hpp>
#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
#include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
#include <com/sun/star/security/XCertificate.hpp>
#include <com/sun/star/linguistic2/DictionaryList.hpp>
#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
#include <com/sun/star/linguistic2/XSpellChecker.hpp>
#include <com/sun/star/linguistic2/XProofreader.hpp>
#include <com/sun/star/i18n/LocaleCalendar2.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/i18n/BreakIterator.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <editeng/flstitem.hxx>
#ifdef IOS
#include <sfx2/app.hxx>
#endif
#include <sfx2/objsh.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/lokcomponenthelpers.hxx>
#include <sfx2/DocumentSigner.hxx>
#include <sfx2/sidebar/Sidebar.hxx>
#include <sfx2/lokunocmdlist.hxx>
#include <svl/numformat.hxx>
#include <svx/dialmgr.hxx>
#include <svx/strings.hrc>
#include <svx/svdview.hxx>
#include <svx/svxids.hrc>
#include <svx/ucsubset.hxx>
#include <vcl/vclevent.hxx>
#include <vcl/GestureEventPan.hxx>
#include <vcl/svapp.hxx>
#include <unotools/resmgr.hxx>
#include <tools/fract.hxx>
#include <tools/json_writer.hxx>
#include <svtools/ctrltool.hxx>
#include <svtools/langtab.hxx>
#include <vcl/fontcharmap.hxx>
#ifdef IOS
#include <vcl/sysdata.hxx>
#endif
#include <vcl/virdev.hxx>
#include <vcl/ImageTree.hxx>
#include <vcl/ITiledRenderable.hxx>
#include <vcl/dialoghelper.hxx>
#ifdef _WIN32
#include <vcl/BitmapTools.hxx>
#endif
#include <unicode/uchar.h>
#include <unotools/securityoptions.hxx>
#include <unotools/confignode.hxx>
#include <unotools/syslocaleoptions.hxx>
#include <unotools/mediadescriptor.hxx>
#include <unotools/pathoptions.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/streamwrap.hxx>
#include <osl/module.hxx>
#include <comphelper/sequence.hxx>
#include <sfx2/sfxbasemodel.hxx>
#include <svl/undo.hxx>
#include <unotools/datetime.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <vcl/abstdlg.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <vcl/uitest/uiobject.hxx>
#include <vcl/jsdialog/executor.hxx>
#include <vcl/scheduler.hxx>
// Needed for getUndoManager()
#include <com/sun/star/document/XUndoManager.hpp>
#include <com/sun/star/document/XUndoManagerSupplier.hpp>
#include <com/sun/star/document/XLinkTargetSupplier.hpp>
#include <editeng/sizeitem.hxx>
#include <svx/rulritem.hxx>
#include <svx/pageitem.hxx>
#include <app.hxx>
#include "../app/cmdlineargs.hxx"
// We also need to hackily be able to start the main libreoffice thread:
#include "../app/sofficemain.h"
#include "../app/officeipcthread.hxx"
#include <lib/init.hxx>
#include "lokinteractionhandler.hxx"
#include "lokclipboard.hxx"
#include <officecfg/Office/Common.hxx>
#include <officecfg/Office/Impress.hxx>
#include <officecfg/Office/Linguistic.hxx>
#include <officecfg/Office/UI/ToolbarMode.hxx>
#include <unotools/optionsdlg.hxx>
#include <svl/ctloptions.hxx>
#include <svtools/colorcfg.hxx>
#include <svtools/miscopt.hxx>
#include <unotools/cmdoptions.hxx>
#include <unotools/lingucfg.hxx>
#include <unotools/moduleoptions.hxx>
#include <unotools/searchopt.hxx>
#include <unotools/useroptions.hxx>
#include <vcl/settings.hxx>
#include <officecfg/Setup.hxx>
#include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
#include <svtools/acceleratorexecute.hxx>
#include <tools/hostfilter.hxx>
using namespace css;
using namespace vcl;
using namespace desktop;
using namespace utl;
using namespace bridge;
using namespace uno;
using namespace lang;
#ifdef UNX
static int urandom = -1;
extern "C" {
int SAL_JNI_EXPORT lok_open_urandom()
{
return dup(urandom);
}
};
#endif
using LanguageToolCfg = officecfg::Office::Linguistic::GrammarChecking::LanguageToo
l;
static LibLibreOffice_Impl *gImpl = nullptr;
static bool lok_preinit_2_called = false ;
static bool gUseCompactFonts = false ;
static std::weak_ptr< LibreOfficeKitClass > gOfficeClass;
static std::weak_ptr< LibreOfficeKitDocumentClass > gDocumentClass;
static void SetLastExceptionMsg(const OUString& s = OUString())
{
SAL_WARN_IF(!s.isEmpty(), "lok" , "lok exception '" + s + "'" );
if (gImpl)
gImpl->maLastExceptionMsg = s;
}
namespace {
struct ExtensionMap
{
std::string_view extn;
OUString filterName;
};
class TraceEventDumper : public AutoTimer
{
static const int dumpTimeoutMS = 5000;
public :
TraceEventDumper() : AutoTimer( "Trace Event dumper" )
{
SetTimeout(dumpTimeoutMS);
Start();
}
virtual void Invoke() override
{
flushRecordings();
}
static void flushRecordings()
{
const css::uno::Sequence<OUString> aEvents =
comphelper::TraceEvent::getRecordingAndClear();
OStringBuffer aOutput;
for (const auto &s : aEvents)
{
aOutput.append(OUStringToOString(s, RTL_TEXTENCODING_UTF8)
+ "\n" );
}
if (aOutput.getLength() > 0)
{
OString aChunk = aOutput.makeStringAndClear();
if (gImpl && gImpl->mpCallback)
gImpl->mpCallback(LOK_CALLBACK_PROFILE_FRAME, aChunk.getStr(), gImpl->mpCallbackData);
}
}
};
TraceEventDumper *traceEventDumper = nullptr;
constexpr ExtensionMap aWriterExtensionMap[] =
{
{ "doc" , u"MS Word 97" _ustr },
{ "docm" , u"MS Word 2007 XML VBA" _ustr },
{ "docx" , u"Office Open XML Text" _ustr },
{ "fodt" , u"OpenDocument Text Flat XML" _ustr },
{ "html" , u"HTML (StarWriter)" _ustr },
{ "odt" , u"writer8" _ustr },
{ "ott" , u"writer8_template" _ustr },
{ "pdf" , u"writer_pdf_Export" _ustr },
{ "epub" , u"EPUB" _ustr },
{ "rtf" , u"Rich Text Format" _ustr },
{ "txt" , u"Text" _ustr },
{ "xhtml" , u"XHTML Writer File" _ustr },
{ "png" , u"writer_png_Export" _ustr },
{ "xml" , u"writer_indexing_export" _ustr },
};
constexpr ExtensionMap aCalcExtensionMap[] =
{
{ "csv" , u"Text - txt - csv (StarCalc)" _ustr },
{ "fods" , u"OpenDocument Spreadsheet Flat XML" _ustr },
{ "html" , u"HTML (StarCalc)" _ustr },
{ "ods" , u"calc8" _ustr },
{ "ots" , u"calc8_template" _ustr },
{ "pdf" , u"calc_pdf_Export" _ustr },
{ "xhtml" , u"XHTML Calc File" _ustr },
{ "xls" , u"MS Excel 97" _ustr },
{ "xlsm" , u"Calc MS Excel 2007 VBA XML" _ustr },
{ "xlsx" , u"Calc MS Excel 2007 XML" _ustr },
{ "png" , u"calc_png_Export" _ustr },
};
constexpr ExtensionMap aImpressExtensionMap[] =
{
{ "fodp" , u"OpenDocument Presentation Flat XML" _ustr },
{ "html" , u"impress_html_Export" _ustr },
{ "odg" , u"impress8_draw" _ustr },
{ "odp" , u"impress8" _ustr },
{ "otp" , u"impress8_template" _ustr },
{ "pdf" , u"impress_pdf_Export" _ustr },
{ "potm" , u"Impress MS PowerPoint 2007 XML Template" _ustr },
{ "pot" , u"MS PowerPoint 97 Vorlage" _ustr },
{ "pptm" , u"Impress MS PowerPoint 2007 XML VBA" _ustr },
{ "pptx" , u"Impress MS PowerPoint 2007 XML" _ustr },
{ "pps" , u"MS PowerPoint 97 Autoplay" _ustr },
{ "ppt" , u"MS PowerPoint 97" _ustr },
{ "svg" , u"impress_svg_Export" _ustr },
{ "xhtml" , u"XHTML Impress File" _ustr },
{ "png" , u"impress_png_Export" _ustr },
{ "bmp" , u"impress_bmp_Export" _ustr },
{ "gif" , u"impress_gif_Export" _ustr },
{ "tif" , u"impress_tif_Export" _ustr },
{ "tiff" , u"impress_tif_Export" _ustr }, // tif and tiff are the same format: see https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types#tiff_tagged_image_file_format
};
constexpr ExtensionMap aDrawExtensionMap[] =
{
{ "fodg" , u"draw_ODG_FlatXML" _ustr },
{ "html" , u"draw_html_Export" _ustr },
{ "odg" , u"draw8" _ustr },
{ "pdf" , u"draw_pdf_Export" _ustr },
{ "svg" , u"draw_svg_Export" _ustr },
{ "xhtml" , u"XHTML Draw File" _ustr },
{ "png" , u"draw_png_Export" _ustr },
};
OUString getUString(const char * pString)
{
if (pString == nullptr)
return OUString();
return OStringToOUString(pString, RTL_TEXTENCODING_UTF8);
}
// Tolerate embedded \0s etc.
char *convertOString(const OString &rStr)
{
char * pMemory = static_cast <char *>(malloc(rStr.getLength() + 1));
assert(pMemory); // don't tolerate failed allocations.
memcpy(pMemory, rStr.getStr(), rStr.getLength() + 1);
return pMemory;
}
char *convertOUString(std::u16string_view aStr)
{
return convertOString(OUStringToOString(aStr, RTL_TEXTENCODING_UTF8));
}
/// Try to convert a relative URL to an absolute one, unless it already looks like a URL.
OUString getAbsoluteURL(const char * pURL)
{
OUString aURL(getUString(pURL));
if (aURL.isEmpty())
return aURL;
// convert relative paths to absolute ones
OUString aWorkingDir;
osl_getProcessWorkingDir(&aWorkingDir.pData);
if (!aWorkingDir.endsWith("/" ))
aWorkingDir += "/" ;
try
{
return rtl::Uri::convertRelToAbs(aWorkingDir, aURL);
}
catch (const rtl::MalformedUriException &)
{
}
return OUString();
}
} // unnamed namespace
std::vector<beans::PropertyValue> desktop::jsonToPropertyValuesVector(const char * pJSON)
{
std::vector<beans::PropertyValue> aArguments;
if (pJSON && pJSON[0] != '\0' )
{
aArguments = comphelper::JsonToPropertyValues(pJSON);
}
return aArguments;
}
static void extractLinks(const uno::Reference< container::XNameAccess >& xLinks, bool subcontent, tools::JsonWriter& aJson)
{
for (const OUString& aLink : xLinks->getElementNames())
{
uno::Any aAny;
try
{
aAny = xLinks->getByName( aLink );
}
catch (const uno::Exception&)
{
// if the name of the target was invalid (like empty headings)
// no object can be provided
continue ;
}
uno::Reference< beans::XPropertySet > xTarget;
if ( aAny >>= xTarget )
{
try
{
// get name to display
aAny = xTarget->getPropertyValue(u"LinkDisplayName" _ustr);
OUString aStrDisplayname;
aAny >>= aStrDisplayname;
if (subcontent)
{
aJson.put(aStrDisplayname, aLink);
}
else
{
uno::Reference<lang::XServiceInfo> xSI(xTarget, uno::UNO_QUERY_THROW);
if (xSI->supportsService(u"com.sun.star.document.LinkTarget" _ustr))
{
aJson.put(aStrDisplayname, aLink);
continue ;
}
else
{
auto aNode = aJson.startNode(
OUStringToOString(aStrDisplayname, RTL_TEXTENCODING_UTF8));
uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, uno::UNO_QUERY );
if ( xLTS.is() )
extractLinks(xLTS->getLinks(), true , aJson);
}
}
}
catch (...)
{
SAL_WARN("lok" , "extractLinks: Exception" );
}
}
}
}
static void unoAnyToJson(tools::JsonWriter& rJson, std::string_view pNodeName, const uno::Any& anyItem)
{
auto aNode = rJson.startNode(pNodeName);
OUString aType = anyItem.getValueTypeName();
rJson.put("type" , aType);
if (aType == "string" )
rJson.put("value" , anyItem.get<OUString>());
else if (aType == "unsigned long" )
rJson.put("value" , OString::number(anyItem.get<sal_uInt32>()));
else if (aType == "long" )
rJson.put("value" , OString::number(anyItem.get<sal_Int32>()));
else if (aType == "[]any" )
{
uno::Sequence<uno::Any> aSeq;
if (anyItem >>= aSeq)
{
auto valueNode = rJson.startNode("value" );
for (auto i = 0; i < aSeq.getLength(); ++i)
{
unoAnyToJson(rJson, OString::number(i), aSeq[i]);
}
}
}
}
static int lcl_getViewId(std::string_view payload);
namespace desktop {
RectangleAndPart RectangleAndPart::Create(const OString& rPayload)
{
RectangleAndPart aRet;
if (rPayload.startsWith("EMPTY" )) // payload starts with "EMPTY"
{
aRet.m_aRectangle = tools::Rectangle(0, 0, SfxLokHelper::MaxTwips, SfxLokHelper::MaxTwips);
if (comphelper::LibreOfficeKit::isPartInInvalidation())
{
int nSeparatorPos = rPayload.indexOf(',' , 6);
bool bHasMode = nSeparatorPos > 0;
if (bHasMode)
{
aRet.m_nPart = o3tl::toInt32(rPayload.subView(6, nSeparatorPos - 6));
assert(rPayload.getLength() > nSeparatorPos);
aRet.m_nMode = o3tl::toInt32(rPayload.subView(nSeparatorPos + 1));
}
else
{
aRet.m_nPart = o3tl::toInt32(rPayload.subView(6));
aRet.m_nMode = 0;
}
}
return aRet;
}
// Read '<left>, <top>, <width>, <height>[, <part>, <mode>]'. C++ streams are simpler but slower.
const char * pos = rPayload.getStr();
const char * end = rPayload.getStr() + rPayload.getLength();
tools::Long nLeft = rtl_str_toInt64_WithLength(pos, 10, end - pos);
while (pos < end && *pos != ',' )
++pos;
if (pos < end)
++pos;
assert(pos < end);
tools::Long nTop = rtl_str_toInt64_WithLength(pos, 10, end - pos);
while (pos < end && *pos != ',' )
++pos;
if (pos < end)
++pos;
assert(pos < end);
tools::Long nWidth = rtl_str_toInt64_WithLength(pos, 10, end - pos);
while (pos < end && *pos != ',' )
++pos;
if (pos < end)
++pos;
assert(pos < end);
tools::Long nHeight = rtl_str_toInt64_WithLength(pos, 10, end - pos);
tools::Long nPart = INT_MIN;
tools::Long nMode = 0;
if (comphelper::LibreOfficeKit::isPartInInvalidation())
{
while (pos < end && *pos != ',' )
++pos;
if (pos < end)
++pos;
assert(pos < end);
nPart = rtl_str_toInt64_WithLength(pos, 10, end - pos);
while (pos < end && *pos != ',' )
++pos;
if (pos < end)
{
++pos;
assert(pos < end);
nMode = rtl_str_toInt64_WithLength(pos, 10, end - pos);
}
}
aRet.m_aRectangle = SanitizedRectangle(nLeft, nTop, nWidth, nHeight);
aRet.m_nPart = nPart;
aRet.m_nMode = nMode;
return aRet;
}
tools::Rectangle RectangleAndPart::SanitizedRectangle(tools::Long nLeft, tools::Long nTop, tools::Long nWidth, tools::Long nHeight)
{
if (nWidth <= 0 || nHeight <= 0)
return tools::Rectangle();
// The top-left corner starts at (0, 0).
// Anything negative is invalid.
if (nLeft < 0)
{
nWidth += nLeft;
nLeft = 0;
}
if (nTop < 0)
{
nHeight += nTop;
nTop = 0;
}
if (nWidth > 0 && nHeight > 0)
return tools::Rectangle(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
// Else set empty rect.
return tools::Rectangle();
}
tools::Rectangle RectangleAndPart::SanitizedRectangle(const tools::Rectangle& rect)
{
return SanitizedRectangle(rect.Left(), rect.Top(), rect.getOpenWidth(), rect.getOpenHeight());
}
const OString& CallbackFlushHandler::CallbackData::getPayload() const
{
if (PayloadString.isEmpty())
{
// Do to-string conversion on demand, as many calls will get dropped without
// needing the string.
if (PayloadObject.which() == 1)
PayloadString = getRectangleAndPart().toString();
}
return PayloadString;
}
void CallbackFlushHandler::CallbackData::updateRectangleAndPart(const RectangleAndPart& rRectAndPart)
{
PayloadObject = rRectAndPart;
PayloadString.clear(); // will be set on demand if needed
}
const RectangleAndPart& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
{
// TODO: In case of unittests, they do not pass invalidations in binary but as text messages.
// LO core should preferably always pass binary for performance.
if (PayloadObject.which() != 1)
PayloadObject = RectangleAndPart::Create(PayloadString);
return boost::get<RectangleAndPart>(PayloadObject);
}
boost::property_tree::ptree& CallbackFlushHandler::CallbackData::setJson(const std::string& payload)
{
boost::property_tree::ptree aTree;
std::stringstream aStream(payload);
boost::property_tree::read_json(aStream, aTree);
// Let boost normalize the payload so it always matches the cache.
setJson(aTree);
// Return reference to the cached object.
return boost::get<boost::property_tree::ptree>(PayloadObject);
}
void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree& rTree)
{
std::stringstream aJSONStream;
constexpr bool bPretty = false ; // Don't waste time and bloat logs.
boost::property_tree::write_json(aJSONStream, rTree, bPretty);
PayloadString = OString(o3tl::trim(aJSONStream.str()));
PayloadObject = rTree;
}
const boost::property_tree::ptree& CallbackFlushHandler::CallbackData::getJson() const
{
assert(PayloadObject.which() == 2);
return boost::get<boost::property_tree::ptree>(PayloadObject);
}
int CallbackFlushHandler::CallbackData::getViewId() const
{
if (isCached())
{
assert(PayloadObject.which() == 3);
return boost::get<int >(PayloadObject);
}
return lcl_getViewId(getPayload());
}
bool CallbackFlushHandler::CallbackData::validate() const
{
switch (PayloadObject.which())
{
// Not cached.
case 0:
return true ;
// RectangleAndPart.
case 1:
return getRectangleAndPart().toString().getStr() == getPayload();
// Json.
case 2:
{
std::stringstream aJSONStream;
boost::property_tree::write_json(aJSONStream, getJson(), false );
const std::string aExpected = boost::trim_copy(aJSONStream.str());
return getPayload() == std::string_view(aExpected);
}
// View id.
case 3:
return getViewId() == lcl_getViewId( getPayload());
default :
assert(!"Unknown variant type; please add an entry to validate." );
}
return false ;
}
} // namespace desktop
static bool lcl_isViewCallbackType(const int type)
{
switch (type)
{
case LOK_CALLBACK_CELL_VIEW_CURSOR:
case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
return true ;
default :
return false ;
}
}
static bool isUpdatedType(int type)
{
switch (type)
{
case LOK_CALLBACK_TEXT_SELECTION:
case LOK_CALLBACK_TEXT_SELECTION_START:
case LOK_CALLBACK_TEXT_SELECTION_END:
return true ;
default :
return false ;
}
}
static bool isUpdatedTypePerViewId(int type)
{
switch (type)
{
case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
return true ;
default :
return false ;
}
}
static int lcl_getViewId(std::string_view payload)
{
// this is a cheap way how to get the viewId from a JSON message; proper
// parsing is terribly expensive, and we just need the viewId here
size_t viewIdPos = payload.find("viewId" );
if (viewIdPos == std::string::npos)
return 0;
size_t numberPos = payload.find(":" , viewIdPos + 6);
if (numberPos == std::string::npos)
return 0;
for (++numberPos; numberPos < payload.length(); ++numberPos)
{
if (payload[numberPos] == ',' || payload[numberPos] == '}' || (payload[numberPos] >= '0' && payload[numberPos] <= '9' ))
break ;
}
if (numberPos < payload.length() && payload[numberPos] >= '0' && payload[numberPos] <= '9' )
return o3tl::toInt32(payload.substr(numberPos));
return 0;
}
// Wonder global state ...
static uno::Reference<css::uno::XComponentContext> xContext;
static uno::Reference<css::lang::XMultiServiceFactory> xSFactory;
static uno::Reference<css::lang::XMultiComponentFactory> xFactory;
namespace {
OUString lcl_getCurrentDocumentMimeType(const LibLODocument_Impl* pDocument)
{
SfxBaseModel* pBaseModel = dynamic_cast <SfxBaseModel*>(pDocument->mxComponent.get());
if (!pBaseModel)
return u"" _ustr;
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
if (!pObjectShell)
return u"" _ustr;
SfxMedium* pMedium = pObjectShell->GetMedium();
if (!pMedium)
return u"" _ustr;
auto pFilter = pMedium->GetFilter();
if (!pFilter)
return u"" _ustr;
return pFilter->GetMimeType();
}
// Gets an undo manager to enter and exit undo context. Needed by ToggleOrientation
css::uno::Reference< css::document::XUndoManager > getUndoManager( const css::uno::Reference< css::frame::XFrame >& rxFrame )
{
const css::uno::Reference< css::frame::XController > xController = rxFrame->getController();
if ( xController.is() )
{
const css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
if ( xModel.is() )
{
const css::uno::Reference< css::document::XUndoManagerSupplier > xSuppUndo( xModel, css::uno::UNO_QUERY_THROW );
return css::uno::Reference< css::document::XUndoManager >( xSuppUndo->getUndoManager(), css::uno::UNO_SET_THROW );
}
}
return css::uno::Reference< css::document::XUndoManager > ();
}
// Adjusts page margins for Writer doc. Needed by ToggleOrientation
void ExecuteMarginLRChange(
const tools::Long nPageLeftMargin,
const tools::Long nPageRightMargin,
SvxLongLRSpaceItem* pPageLRMarginItem)
{
pPageLRMarginItem->SetLeft( nPageLeftMargin );
pPageLRMarginItem->SetRight( nPageRightMargin );
SfxViewShell* pViewSh = SfxViewShell::Current();
if (!pViewSh)
return ;
pViewSh->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_LRSPACE,
SfxCallMode::RECORD, { pPageLRMarginItem });
}
// Adjusts page margins for Writer doc. Needed by ToggleOrientation
void ExecuteMarginULChange(
const tools::Long nPageTopMargin,
const tools::Long nPageBottomMargin,
SvxLongULSpaceItem* pPageULMarginItem)
{
pPageULMarginItem->SetUpper( nPageTopMargin );
pPageULMarginItem->SetLower( nPageBottomMargin );
SfxViewShell* pViewSh = SfxViewShell::Current();
if (!pViewSh)
return ;
pViewSh->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_ULSPACE,
SfxCallMode::RECORD, { pPageULMarginItem });
}
// Main function which toggles page orientation of the Writer doc. Needed by ToggleOrientation
void ExecuteOrientationChange()
{
SfxViewFrame* pViewFrm = SfxViewFrame::Current();
if (!pViewFrm)
return ;
std::unique_ptr<SvxPageItem> pPageItem(new SvxPageItem(SID_ATTR_PAGE));
// 1mm in twips rounded
// This should be in sync with MINBODY in sw/source/uibase/sidebar/PageMarginControl.hxx
constexpr tools::Long MINBODY = o3tl::toTwips(1, o3tl::Length::mm);
css::uno::Reference< css::document::XUndoManager > mxUndoManager(
getUndoManager( pViewFrm->GetFrame().GetFrameInterface() ) );
if ( mxUndoManager.is() )
mxUndoManager->enterUndoContext( u"" _ustr );
SfxPoolItemHolder aResult;
pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_SIZE, aResult);
std::unique_ptr<SvxSizeItem> pPageSizeItem(static_cast <const SvxSizeItem*>(aResult.getItem())->Clone());
pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_LRSPACE, aResult);
std::unique_ptr<SvxLongLRSpaceItem> pPageLRMarginItem(static_cast <const SvxLongLRSpaceItem*>(aResult.getItem())->Clone());
pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_ULSPACE, aResult);
std::unique_ptr<SvxLongULSpaceItem> pPageULMarginItem(static_cast <const SvxLongULSpaceItem*>(aResult.getItem())->Clone());
{
bool bIsLandscape = false ;
if ( pPageSizeItem->GetSize().Width() > pPageSizeItem->GetSize().Height())
bIsLandscape = true ;
// toggle page orientation
pPageItem->SetLandscape(!bIsLandscape);
// swap the width and height of the page size
const tools::Long nRotatedWidth = pPageSizeItem->GetSize().Height();
const tools::Long nRotatedHeight = pPageSizeItem->GetSize().Width();
pPageSizeItem->SetSize(Size(nRotatedWidth, nRotatedHeight));
// apply changed attributes
if (SfxViewShell* pCurrent = SfxViewShell::Current())
{
pCurrent->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_SIZE,
SfxCallMode::RECORD, { pPageSizeItem.get(), pPageItem.get() });
}
}
// check, if margin values still fit to the changed page size.
// if not, adjust margin values
{
const tools::Long nML = pPageLRMarginItem->GetLeft();
const tools::Long nMR = pPageLRMarginItem->GetRight();
const tools::Long nTmpPW = nML + nMR + MINBODY;
const tools::Long nPW = pPageSizeItem->GetSize().Width();
if ( nTmpPW > nPW )
{
if ( nML <= nMR )
{
ExecuteMarginLRChange( pPageLRMarginItem->GetLeft(), nMR - (nTmpPW - nPW ), pPageLRMarginItem.get() );
}
else
{
ExecuteMarginLRChange( nML - (nTmpPW - nPW ), pPageLRMarginItem->GetRight(), pPageLRMarginItem.get() );
}
}
const tools::Long nMT = pPageULMarginItem->GetUpper();
const tools::Long nMB = pPageULMarginItem->GetLower();
const tools::Long nTmpPH = nMT + nMB + MINBODY;
const tools::Long nPH = pPageSizeItem->GetSize().Height();
if ( nTmpPH > nPH )
{
if ( nMT <= nMB )
{
ExecuteMarginULChange( pPageULMarginItem->GetUpper(), nMB - ( nTmpPH - nPH ), pPageULMarginItem.get() );
}
else
{
ExecuteMarginULChange( nMT - ( nTmpPH - nPH ), pPageULMarginItem->GetLower(), pPageULMarginItem.get() );
}
}
}
if ( mxUndoManager.is() )
mxUndoManager->leaveUndoContext();
}
void hideSidebar()
{
SfxViewShell* pViewShell = SfxViewShell::Current();
SfxViewFrame* pViewFrame = pViewShell ? &pViewShell->GetViewFrame() : nullptr;
if (pViewFrame)
pViewFrame->SetChildWindow(SID_SIDEBAR, false , false );
else
SetLastExceptionMsg(u"No view shell or sidebar" _ustr);
}
css::uno::Sequence<css::lang::Locale> setLanguageToolConfig()
{
css::uno::Sequence<css::lang::Locale> aLTLocales;
const char * pEnabled = ::getenv("LANGUAGETOOL_ENABLED" );
const char * pBaseUrlString = ::getenv("LANGUAGETOOL_BASEURL" );
if (pEnabled && pBaseUrlString)
{
const char * pUsername = ::getenv("LANGUAGETOOL_USERNAME" );
const char * pApikey = ::getenv("LANGUAGETOOL_APIKEY" );
const char * pSSLVerification = ::getenv("LANGUAGETOOL_SSL_VERIFICATION" );
const char * pRestProtocol = ::getenv("LANGUAGETOOL_RESTPROTOCOL" );
OUString aEnabled = OStringToOUString(pEnabled, RTL_TEXTENCODING_UTF8);
if (aEnabled != "true" )
return aLTLocales;
OUString aBaseUrl = OStringToOUString(pBaseUrlString, RTL_TEXTENCODING_UTF8);
try
{
using LanguageToolCfg = officecfg::Office::Linguistic::GrammarChecking::LanguageTool;
auto batch(comphelper::ConfigurationChanges::create());
LanguageToolCfg::BaseURL::set(aBaseUrl, batch);
LanguageToolCfg::IsEnabled::set(true , batch);
if (pSSLVerification)
{
OUString aSSLVerification = OStringToOUString(pSSLVerification, RTL_TEXTENCODING_UTF8);
LanguageToolCfg::SSLCertVerify::set(aSSLVerification == "true" , batch);
}
if (pRestProtocol)
{
OUString aRestProtocol = OStringToOUString(pRestProtocol, RTL_TEXTENCODING_UTF8);
LanguageToolCfg::RestProtocol::set(aRestProtocol, batch);
}
if (pUsername && pApikey)
{
OUString aUsername = OStringToOUString(pUsername, RTL_TEXTENCODING_UTF8);
OUString aApiKey = OStringToOUString(pApikey, RTL_TEXTENCODING_UTF8);
LanguageToolCfg::Username::set(aUsername, batch);
LanguageToolCfg::ApiKey::set(aApiKey, batch);
}
batch->commit();
uno::Reference<linguistic2::XProofreader> xGC(
xContext->getServiceManager()->createInstanceWithContext(u"org.openoffice.lingu.LanguageToolGrammarChecker" _ustr, xContext),
uno::UNO_QUERY_THROW);
uno::Reference<linguistic2::XSupportedLocales> xSuppLoc(xGC, uno::UNO_QUERY_THROW);
css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLangSrv =
css::linguistic2::LinguServiceManager::create(xContext);
if (xLangSrv.is())
{
css::uno::Reference<css::linguistic2::XSpellChecker> xSpell = xLangSrv->getSpellChecker();
if (xSpell.is())
{
Sequence<OUString> aEmpty;
Sequence<css::lang::Locale> aLocales = xSpell->getLocales();
for (int itLocale = 0; itLocale < aLocales.getLength(); itLocale++)
{
// turn off spell checker if LanguageTool supports the locale already
if (xSuppLoc->hasLocale(aLocales[itLocale]))
xLangSrv->setConfiguredServices(
SN_SPELLCHECKER, aLocales[itLocale], aEmpty);
}
}
}
aLTLocales = xSuppLoc->getLocales();
}
catch (uno::Exception const & rException)
{
SAL_WARN("lok" , "Failed to set LanguageTool API settings: " << rException.Message);
}
}
return aLTLocales;
}
} // end anonymous namespace
// Could be anonymous in principle, but for the unit testing purposes, we
// declare it in init.hxx.
OUString desktop::extractParameter(OUString& rOptions, std::u16string_view rName)
{
OUString aValue;
OUString aNameEquals(OUString::Concat(rName) + "=" );
OUString aCommaNameEquals(OUString::Concat("," ) + rName + "=" );
int nIndex = -1;
if (rOptions.startsWith(aNameEquals))
{
size_t nLen = aNameEquals.getLength();
int nComma = rOptions.indexOf("," , nLen);
if (nComma >= 0)
{
aValue = rOptions.copy(nLen, nComma - nLen);
rOptions = rOptions.copy(nComma + 1);
}
else
{
aValue = rOptions.copy(nLen);
rOptions.clear();
}
}
else if ((nIndex = rOptions.indexOf(aCommaNameEquals)) >= 0)
{
size_t nLen = aCommaNameEquals.getLength();
int nComma = rOptions.indexOf("," , nIndex + nLen);
if (nComma >= 0)
{
aValue = rOptions.copy(nIndex + nLen, nComma - nIndex - nLen);
rOptions = OUString::Concat(rOptions.subView(0, nIndex)) + rOptions.subView(nComma);
}
else
{
aValue = rOptions.copy(nIndex + nLen);
rOptions = rOptions.copy(0, nIndex);
}
}
return aValue;
}
extern "C"
{
static void doc_destroy(LibreOfficeKitDocument* pThis);
static int doc_saveAs(LibreOfficeKitDocument* pThis, const char * pUrl, const char * pFormat, const char * pFilterOptions);
static int doc_getDocumentType(LibreOfficeKitDocument* pThis);
static int doc_getParts(LibreOfficeKitDocument* pThis);
static char * doc_getPartPageRectangles(LibreOfficeKitDocument* pThis);
static int doc_getPart(LibreOfficeKitDocument* pThis);
static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart);
static void doc_selectPart(LibreOfficeKitDocument* pThis, int nPart, int nSelect);
static void doc_moveSelectedParts(LibreOfficeKitDocument* pThis, int nPosition, bool bDuplicate);
static char * doc_getPartName(LibreOfficeKitDocument* pThis, int nPart);
static void doc_setPartMode(LibreOfficeKitDocument* pThis, int nPartMode);
static int doc_getEditMode(LibreOfficeKitDocument* pThis);
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);
static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
unsigned char * pBuffer,
const int nPart,
const int nMode,
const int nCanvasWidth, const int nCanvasHeight,
const int nTilePosX, const int nTilePosY,
const int nTileWidth, const int nTileHeight);
static int doc_getTileMode(LibreOfficeKitDocument* pThis);
static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
long * pWidth,
long * pHeight);
static void doc_getDataArea(LibreOfficeKitDocument* pThis,
long nTab,
long * pCol,
long * pRow);
static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
const char * pArguments);
static void doc_registerCallback(LibreOfficeKitDocument* pThis,
LibreOfficeKitCallback pCallback,
void * pData);
static void doc_postKeyEvent(LibreOfficeKitDocument* pThis,
int nType,
int nCharCode,
int nKeyCode);
static void doc_setBlockedCommandList(LibreOfficeKitDocument* pThis,
int nViewId,
const char * blockedCommandList);
static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis,
unsigned nWindowId,
int nType,
const char * pText);
static void doc_removeTextContext(LibreOfficeKitDocument* pThis,
unsigned nLOKWindowId,
int nCharBefore,
int nCharAfter);
static void doc_sendDialogEvent(LibreOfficeKitDocument* pThis,
unsigned long long int nLOKWindowId,
const char * pArguments);
static void doc_postWindowKeyEvent(LibreOfficeKitDocument* pThis,
unsigned nLOKWindowId,
int nType,
int nCharCode,
int nKeyCode);
static void doc_postMouseEvent (LibreOfficeKitDocument* pThis,
int nType,
int nX,
int nY,
int nCount,
int nButtons,
int nModifier);
static void doc_postWindowMouseEvent (LibreOfficeKitDocument* pThis,
unsigned nLOKWindowId,
int nType,
int nX,
int nY,
int nCount,
int nButtons,
int nModifier);
static void doc_postWindowGestureEvent(LibreOfficeKitDocument* pThis,
unsigned nLOKWindowId,
const char * pType,
int nX,
int nY,
int nOffset);
static void doc_postUnoCommand(LibreOfficeKitDocument* pThis,
const char * pCommand,
const char * pArguments,
bool bNotifyWhenFinished);
static void doc_setWindowTextSelection(LibreOfficeKitDocument* pThis,
unsigned nLOKWindowId,
bool swap,
int nX,
int nY);
static void doc_setTextSelection (LibreOfficeKitDocument* pThis,
int nType,
int nX,
int nY);
static char * doc_getTextSelection(LibreOfficeKitDocument* pThis,
const char * pMimeType,
char ** pUsedMimeType);
static int doc_getSelectionType(LibreOfficeKitDocument* pThis);
static int doc_getSelectionTypeAndText(LibreOfficeKitDocument* pThis,
const char * pMimeType,
char ** pText,
char ** pUsedMimeType);
static int doc_getClipboard (LibreOfficeKitDocument* pThis,
const char **pMimeTypes,
size_t *pOutCount,
char ***pOutMimeTypes,
size_t **pOutSizes,
char ***pOutStreams);
static int doc_setClipboard (LibreOfficeKitDocument* pThis,
const size_t nInCount,
const char **pInMimeTypes,
const size_t *pInSizes,
const char **pInStreams);
static bool doc_paste(LibreOfficeKitDocument* pThis,
const char * pMimeType,
const char * pData,
size_t nSize);
static void doc_setGraphicSelection (LibreOfficeKitDocument* pThis,
int nType,
int nX,
int nY);
static void doc_resetSelection (LibreOfficeKitDocument* pThis);
static char * doc_getCommandValues(LibreOfficeKitDocument* pThis, const char * pCommand);
static void doc_setClientZoom(LibreOfficeKitDocument* pThis,
int nTilePixelWidth,
int nTilePixelHeight,
int nTileTwipWidth,
int nTileTwipHeight);
static void doc_setClientVisibleArea(LibreOfficeKitDocument* pThis, int nX, int nY, int nWidth, int nHeight);
static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int nLevel, int nIndex, bool bHidden);
static int doc_createView(LibreOfficeKitDocument* pThis);
static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis, const char * pOptions);
static void doc_destroyView(LibreOfficeKitDocument* pThis, int nId);
static void doc_setView(LibreOfficeKitDocument* pThis, int nId);
static int doc_getView(LibreOfficeKitDocument* pThis);
static int doc_getViewsCount(LibreOfficeKitDocument* pThis);
static bool doc_getViewIds(LibreOfficeKitDocument* pThis, int * pArray, size_t nSize);
static void doc_setViewLanguage(LibreOfficeKitDocument* pThis, int nId, const char * language);
static unsigned char * doc_renderFontOrientation(LibreOfficeKitDocument* pThis,
const char *pFontName,
const char *pChar,
int * pFontWidth,
int * pFontHeight,
int pOrientation);
static unsigned char * doc_renderFont(LibreOfficeKitDocument* pThis,
const char *pFontName,
const char *pChar,
int * pFontWidth,
int * pFontHeight);
static char * doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart);
static void doc_paintWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char * pBuffer,
const int nX, const int nY,
const int nWidth, const int nHeight);
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);
static void doc_paintWindowForView(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char * pBuffer,
const int nX, const int nY,
const int nWidth, const int nHeight,
const double fDPIScale, int viewId);
static void doc_postWindow(LibreOfficeKitDocument* pThis, unsigned
nLOKWindowId, int nAction, const char * pData);
static char * doc_getPartInfo(LibreOfficeKitDocument* pThis, int nPart);
static bool doc_insertCertificate(LibreOfficeKitDocument* pThis,
const unsigned char * pCertificateBinary,
const int nCertificateBinarySize,
const unsigned char * pPrivateKeyBinary,
const int nPrivateKeyBinarySize);
static bool doc_addCertificate(LibreOfficeKitDocument* pThis,
const unsigned char * pCertificateBinary,
const int nCertificateBinarySize);
static int doc_getSignatureState(LibreOfficeKitDocument* pThis);
static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char ** pOutput);
static void doc_resizeWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
const int nWidth, const int nHeight);
static void doc_completeFunction(LibreOfficeKitDocument* pThis, const char *);
static void doc_sendFormFieldEvent(LibreOfficeKitDocument* pThis,
const char * pArguments);
static bool doc_renderSearchResult(LibreOfficeKitDocument* pThis,
const char * pSearchResult, unsigned char ** pBitmapBuffer,
int * pWidth, int * pHeight, size_t* pByteSize);
static void doc_sendContentControlEvent(LibreOfficeKitDocument* pThis, const char * pArguments);
static void doc_setViewTimezone(LibreOfficeKitDocument* pThis, int nId, const char * timezone);
static void doc_setViewReadOnly(LibreOfficeKitDocument* pThis, int nId, const bool readonly);
static void doc_setAllowChangeComments(LibreOfficeKitDocument* pThis, int nId, const bool allow);
static void doc_setAccessibilityState(LibreOfficeKitDocument* pThis, int nId, bool bEnabled);
static char * doc_getA11yFocusedParagraph(LibreOfficeKitDocument* pThis);
static int doc_getA11yCaretPosition(LibreOfficeKitDocument* pThis);
static char * doc_getPresentationInfo(LibreOfficeKitDocument* pThis);
static bool doc_createSlideRenderer(
LibreOfficeKitDocument* pThis,
const char * pSlideHash,
int nSlideNumber, unsigned * nViewWidth, unsigned * nViewHeight,
bool bRenderBackground, bool bRenderMasterPage);
static void doc_postSlideshowCleanup(LibreOfficeKitDocument* pThis);
static bool doc_renderNextSlideLayer(
LibreOfficeKitDocument* pThis, unsigned char * pBuffer, bool * bIsBitmapLayer, double * pScale, char ** pJsonMsg);
static void doc_setViewOption(LibreOfficeKitDocument* pDoc, const char * pOption, const char * pValue);
} // extern "C"
namespace {
ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
{
LibLODocument_Impl* pDocument = static_cast <LibLODocument_Impl*>(pThis);
return dynamic_cast <ITiledRenderable*>(pDocument->mxComponent.get());
}
/*
* Unfortunately clipboard creation using UNO is insanely baroque.
* we also need to ensure that this works for the first view which
* has no clear 'createView' called for it (unfortunately).
*/
rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocument *pThis)
{
ITiledRenderable* pDoc = getTiledRenderable(pThis);
rtl::Reference<LOKClipboard> xClip(LOKClipboardFactory::getClipboardForCurView());
if (!pDoc)
{
return xClip;
}
SAL_INFO("lok" , "Set to clipboard for view " << xClip.get());
// FIXME: using a hammer here - should not be necessary if all tests used createView.
pDoc->setClipboard(uno::Reference<datatransfer::clipboard::XClipboard>(xClip->getXI(), UNO_QUERY));
return xClip;
}
const vcl::Font* FindFont(std::u16string_view rFontName)
{
SfxObjectShell* pDocSh = SfxObjectShell::Current();
if (!pDocSh)
return nullptr;
const SvxFontListItem* pFonts
= static_cast <const SvxFontListItem*>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
if (pList && !rFontName.empty())
if (sal_Handle hMetric = pList->GetFirstFontMetric(rFontName))
return &FontList::GetFontMetric(hMetric);
return nullptr;
}
vcl::Font FindFont_FallbackToDefault(std::u16string_view rFontName)
{
if (auto pFound = FindFont(rFontName))
return *pFound;
return OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE, LANGUAGE_NONE,
GetDefaultFontFlags::NONE);
}
int getDocumentType (LibreOfficeKitDocument* pThis)
{
SetLastExceptionMsg();
LibLODocument_Impl* pDocument = static_cast <LibLODocument_Impl*>(pThis);
try
{
uno::Reference<lang::XServiceInfo> xDocument(pDocument->mxComponent, uno::UNO_QUERY_THROW);
if (xDocument->supportsService(u"com.sun.star.sheet.SpreadsheetDocument" _ustr))
{
return LOK_DOCTYPE_SPREADSHEET;
}
else if (xDocument->supportsService(u"com.sun.star.presentation.PresentationDocument" _ustr))
{
return LOK_DOCTYPE_PRESENTATION;
}
else if (xDocument->supportsService(u"com.sun.star.drawing.DrawingDocument" _ustr))
{
return LOK_DOCTYPE_DRAWING;
}
else if (xDocument->supportsService(u"com.sun.star.text.TextDocument" _ustr) || xDocument->supportsService(u"com.sun.star.text.WebDocument" _ustr))
{
return LOK_DOCTYPE_TEXT;
}
else
{
SetLastExceptionMsg(u"unknown document type" _ustr);
}
}
catch (const uno::Exception& exception)
{
SetLastExceptionMsg("exception: " + exception.Message);
}
return LOK_DOCTYPE_OTHER;
}
} // anonymous namespace
LibLODocument_Impl::LibLODocument_Impl(uno::Reference <css::lang::XComponent> xComponent, int nDocumentId)
: mxComponent(std::move(xComponent))
, mnDocumentId(nDocumentId)
{
assert(nDocumentId != -1 && "Cannot set mnDocumentId to -1" );
m_pDocumentClass = gDocumentClass.lock();
if (!m_pDocumentClass)
{
m_pDocumentClass = std::make_shared<LibreOfficeKitDocumentClass>();
m_pDocumentClass->nSize = sizeof (LibreOfficeKitDocumentClass);
m_pDocumentClass->destroy = doc_destroy;
m_pDocumentClass->saveAs = doc_saveAs;
m_pDocumentClass->getDocumentType = doc_getDocumentType;
m_pDocumentClass->getParts = doc_getParts;
m_pDocumentClass->getPartPageRectangles = doc_getPartPageRectangles;
m_pDocumentClass->getPart = doc_getPart;
m_pDocumentClass->setPart = doc_setPart;
m_pDocumentClass->selectPart = doc_selectPart;
m_pDocumentClass->moveSelectedParts = doc_moveSelectedParts;
m_pDocumentClass->getPartName = doc_getPartName;
m_pDocumentClass->setPartMode = doc_setPartMode;
m_pDocumentClass->getEditMode = doc_getEditMode;
m_pDocumentClass->paintTile = doc_paintTile;
m_pDocumentClass->paintPartTile = doc_paintPartTile;
m_pDocumentClass->getTileMode = doc_getTileMode;
m_pDocumentClass->getDocumentSize = doc_getDocumentSize;
m_pDocumentClass->getDataArea = doc_getDataArea;
m_pDocumentClass->initializeForRendering = doc_initializeForRendering;
m_pDocumentClass->registerCallback = doc_registerCallback;
m_pDocumentClass->postKeyEvent = doc_postKeyEvent;
m_pDocumentClass->postWindowExtTextInputEvent = doc_postWindowExtTextInputEvent;
m_pDocumentClass->removeTextContext = doc_removeTextContext;
m_pDocumentClass->postWindowKeyEvent = doc_postWindowKeyEvent;
m_pDocumentClass->postMouseEvent = doc_postMouseEvent;
m_pDocumentClass->postWindowMouseEvent = doc_postWindowMouseEvent;
m_pDocumentClass->sendDialogEvent = doc_sendDialogEvent;
m_pDocumentClass->postUnoCommand = doc_postUnoCommand;
m_pDocumentClass->setTextSelection = doc_setTextSelection;
m_pDocumentClass->setWindowTextSelection = doc_setWindowTextSelection;
m_pDocumentClass->getTextSelection = doc_getTextSelection;
m_pDocumentClass->getSelectionType = doc_getSelectionType;
m_pDocumentClass->getSelectionTypeAndText = doc_getSelectionTypeAndText;
m_pDocumentClass->getClipboard = doc_getClipboard;
m_pDocumentClass->setClipboard = doc_setClipboard;
m_pDocumentClass->paste = doc_paste;
m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection;
m_pDocumentClass->resetSelection = doc_resetSelection;
m_pDocumentClass->getCommandValues = doc_getCommandValues;
m_pDocumentClass->setClientZoom = doc_setClientZoom;
m_pDocumentClass->setClientVisibleArea = doc_setClientVisibleArea;
m_pDocumentClass->setOutlineState = doc_setOutlineState;
m_pDocumentClass->createView = doc_createView;
m_pDocumentClass->destroyView = doc_destroyView;
m_pDocumentClass->setView = doc_setView;
m_pDocumentClass->getView = doc_getView;
m_pDocumentClass->getViewsCount = doc_getViewsCount;
m_pDocumentClass->getViewIds = doc_getViewIds;
m_pDocumentClass->renderFont = doc_renderFont;
m_pDocumentClass->renderFontOrientation = doc_renderFontOrientation;
m_pDocumentClass->getPartHash = doc_getPartHash;
m_pDocumentClass->paintWindow = doc_paintWindow;
m_pDocumentClass->paintWindowDPI = doc_paintWindowDPI;
m_pDocumentClass->paintWindowForView = doc_paintWindowForView;
m_pDocumentClass->postWindow = doc_postWindow;
m_pDocumentClass->resizeWindow = doc_resizeWindow;
m_pDocumentClass->setViewLanguage = doc_setViewLanguage;
m_pDocumentClass->getPartInfo = doc_getPartInfo;
m_pDocumentClass->insertCertificate = doc_insertCertificate;
m_pDocumentClass->addCertificate = doc_addCertificate;
m_pDocumentClass->getSignatureState = doc_getSignatureState;
m_pDocumentClass->renderShapeSelection = doc_renderShapeSelection;
m_pDocumentClass->postWindowGestureEvent = doc_postWindowGestureEvent;
m_pDocumentClass->createViewWithOptions = doc_createViewWithOptions;
m_pDocumentClass->completeFunction = doc_completeFunction;
m_pDocumentClass->sendFormFieldEvent = doc_sendFormFieldEvent;
m_pDocumentClass->renderSearchResult = doc_renderSearchResult;
m_pDocumentClass->setBlockedCommandList = doc_setBlockedCommandList;
m_pDocumentClass->sendContentControlEvent = doc_sendContentControlEvent;
m_pDocumentClass->setViewTimezone = doc_setViewTimezone;
m_pDocumentClass->setAccessibilityState = doc_setAccessibilityState;
m_pDocumentClass->getA11yFocusedParagraph = doc_getA11yFocusedParagraph;
m_pDocumentClass->getA11yCaretPosition = doc_getA11yCaretPosition;
m_pDocumentClass->setViewReadOnly = doc_setViewReadOnly;
m_pDocumentClass->setAllowChangeComments = doc_setAllowChangeComments;
m_pDocumentClass->getPresentationInfo = doc_getPresentationInfo;
m_pDocumentClass->createSlideRenderer = doc_createSlideRenderer;
m_pDocumentClass->postSlideshowCleanup = doc_postSlideshowCleanup;
m_pDocumentClass->renderNextSlideLayer = doc_renderNextSlideLayer;
m_pDocumentClass->setViewOption = doc_setViewOption;
gDocumentClass = m_pDocumentClass;
}
pClass = m_pDocumentClass.get();
forceSetClipboardForCurrentView(this );
}
LibLODocument_Impl::~LibLODocument_Impl()
{
if (comphelper::LibreOfficeKit::isForkedChild())
{
// Touch the least memory possible, while trying to avoid leaking files.
SfxBaseModel* pBaseModel = dynamic_cast <SfxBaseModel*>(mxComponent.get());
if (pBaseModel)
{
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
if (pObjectShell)
pObjectShell->InternalCloseAndRemoveFiles();
}
return ;
}
try
{
mxComponent->dispose();
}
catch (const css::lang::DisposedException&)
{
TOOLS_WARN_EXCEPTION("lok" , "failed to dispose document" );
}
}
static OUString getGenerator()
{
OUString sGenerator(
Translate::ExpandVariables(u"%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)" _ustr));
OUString os(u"$_OS" _ustr);
::rtl::Bootstrap::expandMacros(os);
return sGenerator.replaceFirst("%1" , os);
}
extern "C" {
// One of these is created per view to handle events cf. doc_registerCallback
CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, LibreOfficeKitCallback pCallback, void * pData)
: m_pDocument(pDocument),
m_pCallback(pCallback),
m_pFlushEvent(nullptr),
m_pData(pData),
m_nDisableCallbacks(0)
{
// Add the states that are safe to skip duplicates on, even when
// not consequent (i.e. do no emit them if unchanged from last).
m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_GRAPHIC_SELECTION, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_MOUSE_POINTER, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_CELL_CURSOR, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_CELL_FORMULA, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_CELL_ADDRESS, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_SET_PART, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_TABLE_SELECTED, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_TAB_STOP_LIST, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_RULER_UPDATE, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_VERTICAL_RULER_UPDATE, "NIL" _ostr);
m_states.emplace(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE, "NIL" _ostr);
if (char * pViewRenderState = pDocument->pClass->getCommandValues(pDocument, ".uno:ViewRenderState" ))
{
m_aViewRenderState = pViewRenderState;
free(pViewRenderState);
}
}
void CallbackFlushHandler::stop()
{
if (m_pFlushEvent)
{
Application::RemoveUserEvent(m_pFlushEvent);
m_pFlushEvent = nullptr;
}
}
CallbackFlushHandler::~CallbackFlushHandler()
{
stop();
}
CallbackFlushHandler::queue_type2::iterator CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::iterator pos)
{
int delta = std::distance(m_queue1.begin(), pos);
return m_queue2.begin() + delta;
}
CallbackFlushHandler::queue_type2::reverse_iterator CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::reverse_iterator pos)
{
int delta = std::distance(m_queue1.rbegin(), pos);
return m_queue2.rbegin() + delta;
}
void CallbackFlushHandler::setUpdatedType( int nType, bool value )
{
assert(isUpdatedType(nType));
if ( m_updatedTypes.size() <= o3tl::make_unsigned( nType ))
m_updatedTypes.resize( nType + 1 ); // new are default-constructed, i.e. false
m_updatedTypes[ nType ] = value;
if (value)
scheduleFlush();
}
void CallbackFlushHandler::resetUpdatedType( int nType )
{
setUpdatedType( nType, false );
}
void CallbackFlushHandler::setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value )
{
assert(isUpdatedTypePerViewId(nType));
std::vector<PerViewIdData>& types = m_updatedTypesPerViewId[ nViewId ];
if ( types.size() <= o3tl::make_unsigned( nType ))
types.resize( nType + 1 ); // new are default-constructed, i.e. 'set' is false
types[ nType ] = PerViewIdData{ value, nSourceViewId };
if (value)
scheduleFlush();
}
void CallbackFlushHandler::resetUpdatedTypePerViewId( int nType, int nViewId )
{
assert(isUpdatedTypePerViewId(nType));
bool allViewIds = false ;
// Handle specially messages that do not have viewId for backwards compatibility.
if ( nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
allViewIds = true ;
if ( !allViewIds )
{
setUpdatedTypePerViewId( nType, nViewId, -1, false );
return ;
}
for ( auto & it : m_updatedTypesPerViewId )
{
std::vector<PerViewIdData>& types = it.second;
if ( types.size() >= o3tl::make_unsigned( nType ))
types[ nType ].set = false ;
}
}
void CallbackFlushHandler::libreOfficeKitViewCallback(int nType, const OString& pPayload)
{
CallbackData callbackData(pPayload);
queue(nType, callbackData);
}
void CallbackFlushHandler::libreOfficeKitViewCallbackWithViewId(int nType, const OString& pPayload, int nViewId)
{
CallbackData callbackData(pPayload, nViewId);
queue(nType, callbackData);
}
void CallbackFlushHandler::libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart, int nMode)
{
tools::Rectangle& rPaintedTiles = m_aPaintedTiles[nPart][nMode];
if (rPaintedTiles.IsEmpty())
{
// We have not sent any tiles: don't send invalidations.
return ;
}
tools::Rectangle aRect;
if (pRect)
{
// We got an invalidate: crop it against the bbox.
aRect = *pRect;
aRect.Intersection(rPaintedTiles);
if (aRect.IsEmpty())
{
return ;
}
}
else
{
// EMPTY invalidation: reset the bbox.
rPaintedTiles = tools::Rectangle();
// nullptr pRect means: invalidate everything.
aRect = RectangleAndPart::emptyAllRectangle;
}
// RectangleAndPart ctor doesn't store &aRect, so this is OK.
CallbackData callbackData(&aRect, nPart, nMode);
queue(LOK_CALLBACK_INVALIDATE_TILES, callbackData);
}
void CallbackFlushHandler::libreOfficeKitViewUpdatedCallback(int nType)
{
assert(isUpdatedType( nType ));
std::unique_lock<std::recursive_mutex> lock(m_mutex);
SAL_INFO("lok" , "Updated: [" << nType << "]" );
setUpdatedType(nType, true );
}
void CallbackFlushHandler::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId)
{
assert(isUpdatedTypePerViewId( nType ));
std::unique_lock<std::recursive_mutex> lock(m_mutex);
SAL_INFO("lok" , "Updated: [" << nType << "]" );
setUpdatedTypePerViewId(nType, nViewId, nSourceViewId, true );
}
void CallbackFlushHandler::dumpState(rtl::OStringBuffer &rState)
{
// NB. no locking
rState.append("\n View:\t" );
rState.append(static_cast <sal_Int32>(m_viewId));
rState.append("\n\tDisableCallbacks:\t" );
rState.append(static_cast <sal_Int32>(m_nDisableCallbacks));
rState.append("\n\tStates:\n" );
for (const auto &i : m_states)
{
rState.append("\n\t\t" );
rState.append(static_cast <sal_Int32>(i.first));
rState.append("\t" );
rState.append(i.second);
}
}
void CallbackFlushHandler::libreOfficeKitViewAddPendingInvalidateTiles()
{
// Invoke() will call flushPendingLOKInvalidateTiles(), so just make sure the timer is active.
scheduleFlush();
}
void CallbackFlushHandler::queue(const int type, const OString& data)
{
CallbackData callbackData(data);
queue(type, callbackData);
}
void CallbackFlushHandler::queue(const int type, CallbackData& aCallbackData)
{
comphelper::ProfileZone aZone("CallbackFlushHandler::queue" );
SAL_INFO("lok" , "Queue: [" << type << "]: [" << aCallbackData.getPayload() << "] on " << m_queue1.size() << " entries." );
if (comphelper::LibreOfficeKit::isForkedChild())
{
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=93 H=99 G=95
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland