diff options
Diffstat (limited to 'desktop/source/lib/init.cxx')
-rw-r--r-- | desktop/source/lib/init.cxx | 522 |
1 files changed, 330 insertions, 192 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 8428dc2343d4..f1becd67d215 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -183,6 +183,7 @@ #include "lokinteractionhandler.hxx" #include "lokclipboard.hxx" +#include <officecfg/Office/Common.hxx> #include <officecfg/Office/Impress.hxx> using namespace css; @@ -217,8 +218,14 @@ public: SetTimeout(dumpTimeoutMS); Start(); } + virtual void Invoke() override { + flushRecordings(); + } + + static void flushRecordings() + { const css::uno::Sequence<OUString> aEvents = comphelper::TraceEvent::getRecordingAndClear(); OStringBuffer aOutput; @@ -1077,6 +1084,10 @@ static void doc_postKeyEvent(LibreOfficeKitDocument* pThis, int nType, int nCharCode, int nKeyCode); +static void doc_setBlockedCommandList(LibreOfficeKitDocument* pThis, + int nViewId, + const char* bolckedCommandList); + static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis, unsigned nWindowId, int nType, @@ -1251,6 +1262,26 @@ rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocum #endif +const vcl::Font* FindFont(const OUString& rFontName) +{ + SfxObjectShell* pDocSh = SfxObjectShell::Current(); + const SvxFontListItem* pFonts + = static_cast<const SvxFontListItem*>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST)); + const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr; + if (pList && !rFontName.isEmpty()) + if (sal_Handle hMetric = pList->GetFirstFontMetric(rFontName)) + return &FontList::GetFontMetric(hMetric); + return nullptr; +} + +vcl::Font FindFont_FallbackToDefault(const OUString& rFontName) +{ + if (auto pFound = FindFont(rFontName)) + return *pFound; + + return OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE, LANGUAGE_NONE, + GetDefaultFontFlags::NONE); +} } // anonymous namespace LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent, int nDocumentId) @@ -1340,6 +1371,8 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone m_pDocumentClass->sendFormFieldEvent = doc_sendFormFieldEvent; + m_pDocumentClass->setBlockedCommandList = doc_setBlockedCommandList; + gDocumentClass = m_pDocumentClass; } pClass = m_pDocumentClass.get(); @@ -1372,13 +1405,29 @@ static OUString getGenerator() extern "C" { +CallbackFlushHandler::TimeoutIdle::TimeoutIdle( CallbackFlushHandler* handler ) + : Timer( "lokit timer callback" ) + , mHandler( handler ) +{ + // A second timer with higher priority, it'll ensure we flush in reasonable time if we get too busy + // to get POST_PAINT priority processing. Otherwise it could take a long time to flush. + SetPriority(TaskPriority::DEFAULT); + SetTimeout( 100 ); // 100 ms +} + +void CallbackFlushHandler::TimeoutIdle::Invoke() +{ + mHandler->Invoke(); +} + CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, LibreOfficeKitCallback pCallback, void* pData) - : Idle( "lokit timer callback" ), + : Idle( "lokit idle callback" ), m_pDocument(pDocument), m_pCallback(pCallback), m_pData(pData), m_nDisableCallbacks(0), - m_bEventLatch(false) + m_bEventLatch(false), + m_TimeoutIdle( this ) { SetPriority(TaskPriority::POST_PAINT); @@ -1394,6 +1443,7 @@ CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, Li m_states.emplace(LOK_CALLBACK_CELL_ADDRESS, "NIL"); m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL"); m_states.emplace(LOK_CALLBACK_SET_PART, "NIL"); + m_states.emplace(LOK_CALLBACK_TABLE_SELECTED, "NIL"); Start(); } @@ -1412,22 +1462,33 @@ void CallbackFlushHandler::callback(const int type, const char* payload, void* d } } +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::queue(const int type, const char* data) { comphelper::ProfileZone aZone("CallbackFlushHander::queue"); - CallbackData aCallbackData(type, (data ? data : "(nil)")); + CallbackData aCallbackData(data ? data : "(nil)"); const std::string& payload = aCallbackData.PayloadString; - SAL_INFO("lok", "Queue: [" << type << "]: [" << payload << "] on " << m_queue.size() << " entries."); + SAL_INFO("lok", "Queue: [" << type << "]: [" << payload << "] on " << m_queue1.size() << " entries."); bool bIsChartActive = false; + bool bIsComment = false; if (type == LOK_CALLBACK_GRAPHIC_SELECTION) { LokChartHelper aChartHelper(SfxViewShell::Current()); bIsChartActive = aChartHelper.GetWindow() != nullptr; } + else if (type == LOK_CALLBACK_COMMENT) + { + bIsComment = true; + } - if (callbacksDisabled() && !bIsChartActive) + if (callbacksDisabled() && !bIsChartActive && !bIsComment) { // We drop notifications when this is set, except for important ones. // When we issue a complex command (such as .uno:InsertAnnotation) @@ -1496,11 +1557,13 @@ void CallbackFlushHandler::queue(const int type, const char* data) case LOK_CALLBACK_WINDOW: case LOK_CALLBACK_CALC_FUNCTION_LIST: case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY: + case LOK_CALLBACK_REFERENCE_MARKS: + case LOK_CALLBACK_CELL_AUTO_FILL_AREA: { - const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(), - [type] (const queue_type::value_type& elem) { return (elem.Type == type); }); - - if (pos != m_queue.rend() && pos->PayloadString == payload) + const auto& pos = std::find_if(m_queue1.rbegin(), m_queue1.rend(), + [type] (int elemType) { return (elemType == type); }); + auto pos2 = toQueue2(pos); + if (pos != m_queue1.rend() && pos2->PayloadString == payload) { SAL_INFO("lok", "Skipping queue duplicate [" << type << + "]: [" << payload << "]."); return; @@ -1511,15 +1574,17 @@ void CallbackFlushHandler::queue(const int type, const char* data) if (type == LOK_CALLBACK_TEXT_SELECTION && payload.empty()) { - const auto& posStart = std::find_if(m_queue.rbegin(), m_queue.rend(), - [] (const queue_type::value_type& elem) { return (elem.Type == LOK_CALLBACK_TEXT_SELECTION_START); }); - if (posStart != m_queue.rend()) - posStart->PayloadString.clear(); + const auto& posStart = std::find_if(m_queue1.rbegin(), m_queue1.rend(), + [] (int elemType) { return (elemType == LOK_CALLBACK_TEXT_SELECTION_START); }); + auto posStart2 = toQueue2(posStart); + if (posStart != m_queue1.rend()) + posStart2->PayloadString.clear(); - const auto& posEnd = std::find_if(m_queue.rbegin(), m_queue.rend(), - [] (const queue_type::value_type& elem) { return (elem.Type == LOK_CALLBACK_TEXT_SELECTION_END); }); - if (posEnd != m_queue.rend()) - posEnd->PayloadString.clear(); + const auto& posEnd = std::find_if(m_queue1.rbegin(), m_queue1.rend(), + [] (int elemType) { return (elemType == LOK_CALLBACK_TEXT_SELECTION_END); }); + auto posEnd2 = toQueue2(posEnd); + if (posEnd != m_queue1.rend()) + posEnd2->PayloadString.clear(); } // When payload is empty discards any previous state. @@ -1534,7 +1599,7 @@ void CallbackFlushHandler::queue(const int type, const char* data) case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: case LOK_CALLBACK_INVALIDATE_TILES: if (removeAll( - [type](const queue_type::value_type& elem) { return (elem.Type == type); })) + [type](int elemType, const CallbackData&) { return (elemType == type); })) SAL_INFO("lok", "Removed dups of [" << type << "]: [" << payload << "]."); break; } @@ -1558,7 +1623,7 @@ void CallbackFlushHandler::queue(const int type, const char* data) case LOK_CALLBACK_RULER_UPDATE: { if (removeAll( - [type](const queue_type::value_type& elem) { return (elem.Type == type); })) + [type](int elemType, const CallbackData&) { return (elemType == type); })) SAL_INFO("lok", "Removed dups of [" << type << "]: [" << payload << "]."); } break; @@ -1582,15 +1647,15 @@ void CallbackFlushHandler::queue(const int type, const char* data) payload.find("\"hyperlink\": {}") == std::string::npos; const int nViewId = lcl_getViewId(payload); removeAll( - [type, nViewId, hyperLinkException] (const queue_type::value_type& elem) { - return (elem.Type == type && nViewId == lcl_getViewId(elem) && !hyperLinkException); + [type, nViewId, hyperLinkException] (int elemType, const CallbackData& elemData) { + return (elemType == type && nViewId == lcl_getViewId(elemData) && !hyperLinkException); } ); } break; case LOK_CALLBACK_INVALIDATE_TILES: - if (processInvalidateTilesEvent(aCallbackData)) + if (processInvalidateTilesEvent(type, aCallbackData)) return; break; @@ -1608,8 +1673,8 @@ void CallbackFlushHandler::queue(const int type, const char* data) if (name != ".uno:ModifiedStatus=") { removeAll( - [type, &name] (const queue_type::value_type& elem) { - return (elem.Type == type) && (elem.PayloadString.compare(0, name.size(), name) == 0); + [type, &name] (int elemType, const CallbackData& elemData) { + return (elemType == type) && (elemData.PayloadString.compare(0, name.size(), name) == 0); } ); } @@ -1618,7 +1683,7 @@ void CallbackFlushHandler::queue(const int type, const char* data) break; case LOK_CALLBACK_WINDOW: - if (processWindowEvent(aCallbackData)) + if (processWindowEvent(type, aCallbackData)) return; break; @@ -1626,8 +1691,8 @@ void CallbackFlushHandler::queue(const int type, const char* data) { // remove only selection ranges and 'EMPTY' messages // always send 'INPLACE' and 'INPLACE EXIT' messages - removeAll([type, payload] (const queue_type::value_type& elem) - { return (elem.Type == type && elem.PayloadString[0] != 'I'); }); + removeAll([type, payload] (int elemType, const CallbackData& elemData) + { return (elemType == type && elemData.PayloadString[0] != 'I'); }); } break; } @@ -1635,23 +1700,26 @@ void CallbackFlushHandler::queue(const int type, const char* data) // Validate that the cached data and the payload string are identical. assert(aCallbackData.validate() && "Cached callback payload object and string mismatch!"); - m_queue.emplace_back(aCallbackData); - SAL_INFO("lok", "Queued #" << (m_queue.size() - 1) << - " [" << type << "]: [" << payload << "] to have " << m_queue.size() << " entries."); + m_queue1.emplace_back(type); + m_queue2.emplace_back(aCallbackData); + SAL_INFO("lok", "Queued #" << (m_queue1.size() - 1) << + " [" << type << "]: [" << payload << "] to have " << m_queue1.size() << " entries."); #ifdef DBG_UTIL { // Dump the queue state and validate cached data. int i = 1; std::ostringstream oss; - if (m_queue.empty()) + if (m_queue1.empty()) oss << "Empty"; else - oss << m_queue.size() << " items\n"; - for (const CallbackData& c : m_queue) - oss << i++ << ": [" << c.Type << "] [" << c.PayloadString << "].\n"; + oss << m_queue1.size() << " items\n"; + auto it1 = m_queue1.begin(); + auto it2 = m_queue2.begin(); + for (; it1 != m_queue1.end(); ++it1, ++it2) + oss << i++ << ": [" << *it1 << "] [" << it2->PayloadString << "].\n"; SAL_INFO("lok", "Current Queue: " << oss.str()); - for (const CallbackData& c : m_queue) + for (const CallbackData& c : m_queue2) assert(c.validate()); } #endif @@ -1661,12 +1729,13 @@ void CallbackFlushHandler::queue(const int type, const char* data) { Start(); } + if (!m_TimeoutIdle.IsActive()) + m_TimeoutIdle.Start(); } -bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackData) +bool CallbackFlushHandler::processInvalidateTilesEvent(int type, CallbackData& aCallbackData) { const std::string& payload = aCallbackData.PayloadString; - const int type = aCallbackData.Type; RectangleAndPart& rcNew = aCallbackData.setRectangleAndPart(payload); if (rcNew.isEmpty()) @@ -1678,12 +1747,13 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa // If we have to invalidate all tiles, we can skip any new tile invalidation. // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all. const auto& pos - = std::find_if(m_queue.rbegin(), m_queue.rend(), [](const queue_type::value_type& elem) { - return (elem.Type == LOK_CALLBACK_INVALIDATE_TILES); + = std::find_if(m_queue1.rbegin(), m_queue1.rend(), [](int elemType) { + return (elemType == LOK_CALLBACK_INVALIDATE_TILES); }); - if (pos != m_queue.rend()) + if (pos != m_queue1.rend()) { - const RectangleAndPart& rcOld = pos->getRectangleAndPart(); + auto pos2 = toQueue2(pos); + const RectangleAndPart& rcOld = pos2->getRectangleAndPart(); if (rcOld.isInfinite() && (rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart)) { SAL_INFO("lok", "Skipping queue [" << type << "]: [" << payload @@ -1707,11 +1777,11 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa { SAL_INFO("lok", "Have Empty [" << type << "]: [" << payload << "] so removing all with part " << rcNew.m_nPart << "."); - removeAll([&rcNew](const queue_type::value_type& elem) { - if (elem.Type == LOK_CALLBACK_INVALIDATE_TILES) + removeAll([&rcNew](int elemType, const CallbackData& elemData) { + if (elemType == LOK_CALLBACK_INVALIDATE_TILES) { // Remove exiting if new is all-encompassing, or if of the same part. - const RectangleAndPart rcOld = RectangleAndPart::Create(elem.PayloadString); + const RectangleAndPart rcOld = RectangleAndPart::Create(elemData.PayloadString); return (rcNew.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart); } @@ -1724,10 +1794,10 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa const auto rcOrig = rcNew; SAL_INFO("lok", "Have [" << type << "]: [" << payload << "] so merging overlapping."); - removeAll([&rcNew](const queue_type::value_type& elem) { - if (elem.Type == LOK_CALLBACK_INVALIDATE_TILES) + removeAll([&rcNew](int elemType, const CallbackData& elemData) { + if (elemType == LOK_CALLBACK_INVALIDATE_TILES) { - const RectangleAndPart& rcOld = elem.getRectangleAndPart(); + const RectangleAndPart& rcOld = elemData.getRectangleAndPart(); if (rcNew.m_nPart != -1 && rcOld.m_nPart != -1 && rcOld.m_nPart != rcNew.m_nPart) { SAL_INFO("lok", "Nothing to merge between new: " @@ -1796,10 +1866,9 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa return false; } -bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData) +bool CallbackFlushHandler::processWindowEvent(int type, CallbackData& aCallbackData) { const std::string& payload = aCallbackData.PayloadString; - const int type = aCallbackData.Type; boost::property_tree::ptree& aTree = aCallbackData.setJson(payload); const unsigned nLOKWindowId = aTree.get<unsigned>("id", 0); @@ -1811,10 +1880,10 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData) // remove all previous window part invalidations if (aRectStr.empty()) { - removeAll([&nLOKWindowId](const queue_type::value_type& elem) { - if (elem.Type == LOK_CALLBACK_WINDOW) + removeAll([&nLOKWindowId](int elemType, const CallbackData& elemData) { + if (elemType == LOK_CALLBACK_WINDOW) { - const boost::property_tree::ptree& aOldTree = elem.getJson(); + const boost::property_tree::ptree& aOldTree = elemData.getJson(); if (nLOKWindowId == aOldTree.get<unsigned>("id", 0) && aOldTree.get<std::string>("action", "") == "invalidate") { @@ -1828,17 +1897,22 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData) { // if we have to invalidate all of the window, ignore // any part invalidation message - const auto invAllExist = std::any_of(m_queue.rbegin(), m_queue.rend(), - [&nLOKWindowId] (const queue_type::value_type& elem) - { - if (elem.Type != LOK_CALLBACK_WINDOW) - return false; - - const boost::property_tree::ptree& aOldTree = elem.getJson(); - return nLOKWindowId == aOldTree.get<unsigned>("id", 0) - && aOldTree.get<std::string>("action", "") == "invalidate" - && aOldTree.get<std::string>("rectangle", "").empty(); - }); + bool invAllExist = false; + auto it1 = m_queue1.rbegin(); + auto it2 = m_queue2.rbegin(); + for (;it1 != m_queue1.rend(); ++it1, ++it2) + { + if (*it1 != LOK_CALLBACK_WINDOW) + continue; + const boost::property_tree::ptree& aOldTree = it2->getJson(); + if (nLOKWindowId == aOldTree.get<unsigned>("id", 0) + && aOldTree.get<std::string>("action", "") == "invalidate" + && aOldTree.get<std::string>("rectangle", "").empty()) + { + invAllExist = true; + break; + } + } // we found a invalidate-all window callback if (invAllExist) @@ -1856,11 +1930,11 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData) tools::Rectangle aNewRect(nLeft, nTop, nLeft + nWidth, nTop + nHeight); bool currentIsRedundant = false; removeAll([&aNewRect, &nLOKWindowId, - ¤tIsRedundant](const queue_type::value_type& elem) { - if (elem.Type != LOK_CALLBACK_WINDOW) + ¤tIsRedundant](int elemType, const CallbackData& elemData) { + if (elemType != LOK_CALLBACK_WINDOW) return false; - const boost::property_tree::ptree& aOldTree = elem.getJson(); + const boost::property_tree::ptree& aOldTree = elemData.getJson(); if (aOldTree.get<std::string>("action", "") == "invalidate") { // Not possible that we encounter an empty rectangle here; we already handled this case above. @@ -1931,10 +2005,10 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData) else if (aAction == "created") { // Remove all previous actions on same dialog, if we are creating it anew. - removeAll([&nLOKWindowId](const queue_type::value_type& elem) { - if (elem.Type == LOK_CALLBACK_WINDOW) + removeAll([&nLOKWindowId](int elemType, const CallbackData& elemData) { + if (elemType == LOK_CALLBACK_WINDOW) { - const boost::property_tree::ptree& aOldTree = elem.getJson(); + const boost::property_tree::ptree& aOldTree = elemData.getJson(); if (nLOKWindowId == aOldTree.get<unsigned>("id", 0)) return true; } @@ -1959,10 +2033,10 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData) { // A size change is practically re-creation of the window. // But at a minimum it's a full invalidation. - removeAll([&nLOKWindowId](const queue_type::value_type& elem) { - if (elem.Type == LOK_CALLBACK_WINDOW) + removeAll([&nLOKWindowId](int elemType, const CallbackData& elemData) { + if (elemType == LOK_CALLBACK_WINDOW) { - const boost::property_tree::ptree& aOldTree = elem.getJson(); + const boost::property_tree::ptree& aOldTree = elemData.getJson(); if (nLOKWindowId == aOldTree.get<unsigned>("id", 0)) { const std::string aOldAction = aOldTree.get<std::string>("action", ""); @@ -1986,12 +2060,14 @@ void CallbackFlushHandler::Invoke() { std::scoped_lock<std::mutex> lock(m_mutex); - SAL_INFO("lok", "Flushing " << m_queue.size() << " elements."); - for (const auto& rCallbackData : m_queue) + SAL_INFO("lok", "Flushing " << m_queue1.size() << " elements."); + auto it1 = m_queue1.begin(); + auto it2 = m_queue2.begin(); + for (; it1 != m_queue1.end(); ++it1, ++it2) { - const int type = rCallbackData.Type; - const auto& payload = rCallbackData.PayloadString; - const int viewId = lcl_isViewCallbackType(type) ? lcl_getViewId(rCallbackData) : -1; + const int type = *it1; + const auto& payload = it2->PayloadString; + const int viewId = lcl_isViewCallbackType(type) ? lcl_getViewId(*it2) : -1; if (viewId == -1) { @@ -2039,20 +2115,32 @@ void CallbackFlushHandler::Invoke() m_pCallback(type, payload.c_str(), m_pData); } - m_queue.clear(); + m_queue1.clear(); + m_queue2.clear(); + m_TimeoutIdle.Stop(); } } -bool CallbackFlushHandler::removeAll(const std::function<bool (const CallbackFlushHandler::queue_type::value_type&)>& rTestFunc) +bool CallbackFlushHandler::removeAll(const std::function<bool (int, const CallbackData&)>& rTestFunc) { - auto newEnd = std::remove_if(m_queue.begin(), m_queue.end(), rTestFunc); - if (newEnd != m_queue.end()) + bool bErased = false; + auto it1 = m_queue1.begin(); + auto it2 = m_queue2.begin(); + while (it1 != m_queue1.end()) { - m_queue.erase(newEnd, m_queue.end()); - return true; + if (rTestFunc(*it1, *it2)) + { + it1 = m_queue1.erase(it1); + it2 = m_queue2.erase(it2); + bErased = true; + } + else + { + ++it1; + ++it2; + } } - - return false; + return bErased; } void CallbackFlushHandler::addViewStates(int viewId) @@ -2292,7 +2380,7 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis, Application::SetDialogCancelMode(DialogCancelMode::LOKSilent); } - uno::Sequence<css::beans::PropertyValue> aFilterOptions(3); + uno::Sequence<css::beans::PropertyValue> aFilterOptions(4); aFilterOptions[0] = css::beans::PropertyValue( "FilterOptions", 0, uno::makeAny(aOptions), @@ -2339,6 +2427,13 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis, aFilterOptions[3].Value <<= nUpdateDoc; */ + // set this explicitly false to be able to load template files + // as regular files, otherwise we cannot save them; it will try + // to bring saveas dialog which cannot work with LOK case + aFilterOptions[3].Name = "AsTemplate"; + aFilterOptions[3].Value <<= false; + + const int nThisDocumentId = nDocumentIdCounter++; SfxViewShell::SetCurrentDocId(ViewShellDocId(nThisDocumentId)); uno::Reference<lang::XComponent> xComponent = xComponentLoader->loadComponentFromURL( @@ -2648,6 +2743,34 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const cha bool bFullSheetPreview = sFullSheetPreview == "true"; + // Select a pdf version if specified a valid one. If invalid then fail. + // If not specified then ignore. + sal_Int32 pdfVer = 0; + if ((aIndex = aFilterOptions.indexOf(",PDFVer=")) >= 0) + { + int bIndex = aFilterOptions.indexOf("PDFVEREND"); + OUString sPdfVer = aFilterOptions.copy(aIndex+8, bIndex-(aIndex+8)); + + OUString temp = aFilterOptions.copy(0, aIndex); + aFilterOptions = temp + aFilterOptions.copy(bIndex+9); + + if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-1b")) + pdfVer = 1; + else if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-2b")) + pdfVer = 2; + else if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-3b")) + pdfVer = 3; + else if (sPdfVer.equalsIgnoreAsciiCase("PDF-1.5")) + pdfVer = 15; + else if (sPdfVer.equalsIgnoreAsciiCase("PDF-1.6")) + pdfVer = 16; + else + { + SetLastExceptionMsg("wrong PDF version"); + return false; + } + } + // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document // gets a new name). When this is not provided, the meaning of // saveAs() is more like save-a-copy, which allows saving to any @@ -2684,6 +2807,9 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const cha if (bFullSheetPreview) aFilterDataMap["SinglePageSheets"] <<= true; + if (pdfVer) + aFilterDataMap["SelectPdfVersion"] <<= pdfVer; + if (!aFilterDataMap.empty()) { aSaveMediaDescriptor["FilterData"] <<= aFilterDataMap.getAsConstPropertyValueList(); @@ -2743,6 +2869,7 @@ static void doc_iniUnoCommands () OUString(".uno:IncrementIndent"), OUString(".uno:Italic"), OUString(".uno:JustifyPara"), + OUString(".uno:JumpToMark"), OUString(".uno:OutlineFont"), OUString(".uno:LeftPara"), OUString(".uno:LanguageStatus"), @@ -2759,6 +2886,9 @@ static void doc_iniUnoCommands () OUString(".uno:InsertPage"), OUString(".uno:DeletePage"), OUString(".uno:DuplicatePage"), + OUString(".uno:InsertSlide"), + OUString(".uno:DeleteSlide"), + OUString(".uno:DuplicateSlide"), OUString(".uno:Cut"), OUString(".uno:Copy"), OUString(".uno:Paste"), @@ -3331,6 +3461,7 @@ static void doc_paintPartTile(LibreOfficeKitDocument* pThis, int nOrigPart = 0; const bool isText = (doc_getDocumentType(pThis) == LOK_DOCTYPE_TEXT); int nViewId = nOrigViewId; + int nLastNonEditorView = nViewId; if (!isText) { // Check if just switching to another view is enough, that has @@ -3340,9 +3471,15 @@ static void doc_paintPartTile(LibreOfficeKitDocument* pThis, SfxViewShell* pViewShell = SfxViewShell::GetFirst(); while (pViewShell) { - if (pViewShell->getPart() == nPart) + bool bIsInEdit = pViewShell->GetDrawView() && + pViewShell->GetDrawView()->GetTextEditOutliner(); + if (!bIsInEdit) + nLastNonEditorView = pViewShell->GetViewShellId().get(); + + if (pViewShell->getPart() == nPart && !bIsInEdit) { nViewId = static_cast<sal_Int32>(pViewShell->GetViewShellId()); + nLastNonEditorView = nViewId; doc_setView(pThis, nViewId); break; } @@ -3350,6 +3487,14 @@ static void doc_paintPartTile(LibreOfficeKitDocument* pThis, } } + // if not found view with correct part - at least avoid rendering active textbox + SfxViewShell* pCurrentViewShell = SfxViewShell::Current(); + if (pCurrentViewShell && pCurrentViewShell->GetDrawView() && + pCurrentViewShell->GetDrawView()->GetTextEditOutliner()) + { + doc_setView(pThis, nLastNonEditorView); + } + nOrigPart = doc_getPart(pThis); if (nPart != nOrigPart) { @@ -3554,6 +3699,12 @@ static void doc_postKeyEvent(LibreOfficeKitDocument* pThis, int nType, int nChar } } +static void doc_setBlockedCommandList(LibreOfficeKitDocument* /*pThis*/, int nViewId, const char* bolckedCommandList) +{ + SolarMutexGuard aGuard; + SfxLokHelper::setBlockedCommandList(nViewId, bolckedCommandList); +} + static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis, unsigned nWindowId, int nType, const char* pText) { comphelper::ProfileZone aZone("doc_postWindowExtTextInputEvent"); @@ -3710,6 +3861,7 @@ static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOu } aMediaDescriptor["SelectionOnly"] <<= true; aMediaDescriptor["OutputStream"] <<= xOut; + aMediaDescriptor["IsPreview"] <<= true; // will down-scale graphics xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); @@ -3904,6 +4056,7 @@ static void lo_setOption(LibreOfficeKit* /*pThis*/, const char *pOption, const c { if (strcmp(pValue, "start") == 0) { + comphelper::TraceEvent::setBufferSizeAndCallback(100, TraceEventDumper::flushRecordings); comphelper::TraceEvent::startRecording(); if (traceEventDumper == nullptr) traceEventDumper = new TraceEventDumper(); @@ -4749,43 +4902,25 @@ static char* getFonts (const char* pCommand) static char* getFontSubset (const OString& aFontName) { OUString aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName, RTL_TEXTENCODING_UTF8), rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8)); - SfxObjectShell* pDocSh = SfxObjectShell::Current(); - const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>( - pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST)); - const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr; boost::property_tree::ptree aTree; aTree.put("commandName", ".uno:FontSubset"); boost::property_tree::ptree aValues; - if ( pList && !aFoundFont.isEmpty() ) + if (const vcl::Font* pFont = FindFont(aFoundFont)) { - sal_uInt16 nFontCount = pList->GetFontNameCount(); - sal_uInt16 nItFont = 0; - for (; nItFont < nFontCount; ++nItFont) - { - if (aFoundFont == pList->GetFontName(nItFont).GetFamilyName()) - { - break; - } - } + FontCharMapRef xFontCharMap (new FontCharMap()); + auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT)); - if ( nItFont < nFontCount ) - { - FontCharMapRef xFontCharMap (new FontCharMap()); - auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT)); - const vcl::Font& aFont(pList->GetFontName(nItFont)); + aDevice->SetFont(*pFont); + aDevice->GetFontCharMap(xFontCharMap); + SubsetMap aSubMap(xFontCharMap); - aDevice->SetFont(aFont); - aDevice->GetFontCharMap(xFontCharMap); - SubsetMap aSubMap(xFontCharMap); - - for (auto const& subset : aSubMap.GetSubsetMap()) - { - boost::property_tree::ptree aChild; - aChild.put("", static_cast<int>(ublock_getCode(subset.GetRangeMin()))); - aValues.push_back(std::make_pair("", aChild)); - } + for (auto const& subset : aSubMap.GetSubsetMap()) + { + boost::property_tree::ptree aChild; + aChild.put("", static_cast<int>(ublock_getCode(subset.GetRangeMin()))); + aValues.push_back(std::make_pair("", aChild)); } } @@ -5406,98 +5541,80 @@ unsigned char* doc_renderFontOrientation(SAL_UNUSED_PARAMETER LibreOfficeKitDocu SolarMutexGuard aGuard; SetLastExceptionMsg(); - OString aSearchedFontName(pFontName); - OUString aText(OStringToOUString(pChar, RTL_TEXTENCODING_UTF8)); - SfxObjectShell* pDocSh = SfxObjectShell::Current(); - const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>( - pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST)); - const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr; - const int nDefaultFontSize = 25; - if ( pList ) - { - sal_uInt16 nFontCount = pList->GetFontNameCount(); - for (sal_uInt16 i = 0; i < nFontCount; ++i) - { - const FontMetric& rFontMetric = pList->GetFontName(i); - const OUString& aFontName = rFontMetric.GetFamilyName(); - if (aSearchedFontName != aFontName.toUtf8()) - continue; - - if (aText.isEmpty()) - aText = rFontMetric.GetFamilyName(); + auto aFont = FindFont_FallbackToDefault(OStringToOUString(pFontName, RTL_TEXTENCODING_UTF8)); - auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT)); - ::tools::Rectangle aRect; - vcl::Font aFont(rFontMetric); - aFont.SetFontSize(Size(0, nDefaultFontSize)); - aFont.SetOrientation(pOrientation); - aDevice->SetFont(aFont); - aDevice->GetTextBoundRect(aRect, aText); - if (aRect.IsEmpty()) - break; + OUString aText(OStringToOUString(pChar, RTL_TEXTENCODING_UTF8)); + if (aText.isEmpty()) + aText = aFont.GetFamilyName(); + + auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT)); + ::tools::Rectangle aRect; + aFont.SetFontSize(Size(0, nDefaultFontSize)); + aFont.SetOrientation(pOrientation); + aDevice->SetFont(aFont); + aDevice->GetTextBoundRect(aRect, aText); + if (aRect.IsEmpty()) + return nullptr; - int nFontWidth = aRect.BottomRight().X() + 1; - int nFontHeight = aRect.BottomRight().Y() + 1; + int nFontWidth = aRect.BottomRight().X() + 1; + int nFontHeight = aRect.BottomRight().Y() + 1; - if (!(nFontWidth > 0 && nFontHeight > 0)) - break; + if (!(nFontWidth > 0 && nFontHeight > 0)) + return nullptr; - if (*pFontWidth > 0 && *pFontHeight > 0) - { - double fScaleX = *pFontWidth / static_cast<double>(nFontWidth) / 1.5; - double fScaleY = *pFontHeight / static_cast<double>(nFontHeight) / 1.5; + if (*pFontWidth > 0 && *pFontHeight > 0) + { + double fScaleX = *pFontWidth / static_cast<double>(nFontWidth) / 1.5; + double fScaleY = *pFontHeight / static_cast<double>(nFontHeight) / 1.5; - double fScale = std::min(fScaleX, fScaleY); + double fScale = std::min(fScaleX, fScaleY); - if (fScale >= 1.0) - { - int nFontSize = fScale * nDefaultFontSize; - aFont.SetFontSize(Size(0, nFontSize)); - aDevice->SetFont(aFont); - } + if (fScale >= 1.0) + { + int nFontSize = fScale * nDefaultFontSize; + aFont.SetFontSize(Size(0, nFontSize)); + aDevice->SetFont(aFont); + } - aRect = tools::Rectangle(0, 0, *pFontWidth, *pFontHeight); + aRect = tools::Rectangle(0, 0, *pFontWidth, *pFontHeight); - nFontWidth = *pFontWidth; - nFontHeight = *pFontHeight; + nFontWidth = *pFontWidth; + nFontHeight = *pFontHeight; - } + } - unsigned char* pBuffer = static_cast<unsigned char*>(malloc(4 * nFontWidth * nFontHeight)); - if (!pBuffer) - break; + unsigned char* pBuffer = static_cast<unsigned char*>(malloc(4 * nFontWidth * nFontHeight)); + if (!pBuffer) + return nullptr; - memset(pBuffer, 0, nFontWidth * nFontHeight * 4); - aDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); - aDevice->SetOutputSizePixelScaleOffsetAndBuffer( - Size(nFontWidth, nFontHeight), Fraction(1.0), Point(), - pBuffer); + memset(pBuffer, 0, nFontWidth * nFontHeight * 4); + aDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); + aDevice->SetOutputSizePixelScaleOffsetAndBuffer( + Size(nFontWidth, nFontHeight), Fraction(1.0), Point(), + pBuffer); - if (*pFontWidth > 0 && *pFontHeight > 0) - { - DrawTextFlags const nStyle = - DrawTextFlags::Center - | DrawTextFlags::VCenter - | DrawTextFlags::MultiLine - | DrawTextFlags::WordBreak;// | DrawTextFlags::WordBreakHyphenation ; + if (*pFontWidth > 0 && *pFontHeight > 0) + { + DrawTextFlags const nStyle = + DrawTextFlags::Center + | DrawTextFlags::VCenter + | DrawTextFlags::MultiLine + | DrawTextFlags::WordBreak;// | DrawTextFlags::WordBreakHyphenation ; - aDevice->DrawText(aRect, aText, nStyle); - } - else - { - *pFontWidth = nFontWidth; - *pFontHeight = nFontHeight; + aDevice->DrawText(aRect, aText, nStyle); + } + else + { + *pFontWidth = nFontWidth; + *pFontHeight = nFontHeight; - aDevice->DrawText(Point(0,0), aText); - } + aDevice->DrawText(Point(0,0), aText); + } - return pBuffer; - } - } - return nullptr; + return pBuffer; } @@ -6042,7 +6159,7 @@ static void lo_runLoop(LibreOfficeKit* /*pThis*/, static bool bInitialized = false; -static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent) +static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent, const char* pText) { LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(data); @@ -6052,7 +6169,7 @@ static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit: switch (type) { case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start: - pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START, nullptr, pLib->mpCallbackData); + pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START, pText, pLib->mpCallbackData); break; case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue: pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE, @@ -6173,6 +6290,25 @@ static void activateNotebookbar(const OUString& rApp) aAppNode.commit(); } } +void setCertificateDir() +{ + const char* pEnvVarString = ::getenv("LO_CERTIFICATE_DATABASE_PATH"); + if (pEnvVarString) + { + OUString aCertificateDatabasePath = OStringToOUString(pEnvVarString, RTL_TEXTENCODING_UTF8); + try + { + std::shared_ptr<comphelper::ConfigurationChanges> pBatch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Security::Scripting::CertDir::set(aCertificateDatabasePath, pBatch); + officecfg::Office::Common::Security::Scripting::ManualCertDir::set(aCertificateDatabasePath, pBatch); + pBatch->commit(); + } + catch (uno::Exception const& rException) + { + SAL_WARN("lok", "Failed to set the NSS certificate database directory: " << rException.Message); + } + } +} static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char* pUserProfileUrl) { @@ -6481,6 +6617,8 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char } #endif + setCertificateDir(); + if (bNotebookbar) { activateNotebookbar("Writer"); |