desktop/source/lib/init.cxx | 24 +++++++++++++++++++++--- include/vcl/ITiledRenderable.hxx | 9 +++++++++ sc/inc/docuno.hxx | 3 +++ sc/inc/scextopt.hxx | 1 + sc/qa/unit/tiledrendering/tiledrendering.cxx | 18 ++++++++++++++++++ sc/source/filter/excel/xeview.cxx | 4 +++- sc/source/ui/inc/viewdata.hxx | 5 +++++ sc/source/ui/unoobj/docuno.cxx | 13 +++++++++++++ sc/source/ui/view/viewdata.cxx | 11 +++++++++++ xmloff/source/core/xmlexp.cxx | 7 +++++++ 10 files changed, 91 insertions(+), 4 deletions(-)
New commits: commit 22dbeb3505af9cf7e7d4a07412616652ade67dcd Author: Mohit Marathe <mohit.mara...@collabora.com> AuthorDate: Thu Jul 31 19:48:12 2025 +0530 Commit: Pedro Silva <pedro.si...@collabora.com> CommitDate: Tue Aug 12 13:35:00 2025 +0200 cool#4250 LOK calc export: use LOK Zoom via ScViewData Justin Luth's comment on the original patch (to which I made some minor tweaks to adapt to the new simplified API): "The zoom values set in the view properties by LibreOfficeKit are technical zoom levels that depend on the current screen DPI. They do not reflect the logical zoom level that the user sees. This has been especially problematic for high DPI screens, where the technical-zoom-level is completely different from the human-zoom-level - and thus a weird value is exported. Instead, export the zoom value that LOK presents to the human. Since LOK doc_setClientZoom always calls setZoom for bAll sheets, it is sufficient to only have a single export zoom variable. COOL doesn't have a "View - Page break" view, so PageZoomValue is irrelevant. Of course, even in desktop mode it seems irrelevant to me... I'm rather worried about the "IsLOKExport" flag interferring with normal, synchronous operations during a background/download ODT save. Those WriteUserDataSequence are not at all limited to file-save operations. They just fill in property values for 'whatever' wants to capture the view settings. So if some other process runs in parallel with the save, then it will get the export zoom values, rather than the operational zoom values it was expecting. But I don't see any way around it since xmloff just dumps properties as the way that it saves an ODS. make CppunitTest_sc_tiledrendering \ CPPUNIT_TEST_NAME=testCellInvalidationDocWithExistingZoom" Signed-off-by: Mohit Marathe <mohit.mara...@collabora.com> Co-authored-by: Justin Luth <justin.l...@collabora.com> Change-Id: I54282e4d28dbe489ca0ea7c080036391faa4704c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188674 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@collabora.com> diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index a4b63b1861df..ff66953c032e 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -3897,7 +3897,6 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const cha aSaveMediaDescriptor[MediaDescriptor::PROP_INTERACTIONHANDLER] <<= uno::Reference<task::XInteractionHandler2>(pInteraction); } - if (bTakeOwnership) xStorable->storeAsURL(aURL, aSaveMediaDescriptor.getAsConstPropertyValueList()); else @@ -5821,9 +5820,28 @@ static bool doc_renderNextSlideLayer( return bDone; } -static void doc_setViewOption(LibreOfficeKitDocument* /*pDoc*/, const char* /*pOption*/, const char* /*pValue*/) +static void doc_setViewOption(LibreOfficeKitDocument* pThis, const char* pOption, const char* pValue) { - // placeholder for now + comphelper::ProfileZone aZone("doc_setViewOption"); + + ITiledRenderable* pDoc = getTiledRenderable(pThis); + if (!pDoc) + { + SetLastExceptionMsg(u"Document doesn't support tiled rendering"_ustr); + return; + } + + SolarMutexGuard aGuard; + SetLastExceptionMsg(); + + const OUString sOption = getUString(pOption); + if (sOption == "zoom") + { + const int nZoom = getUString(pValue).toInt32(); + + if (nZoom) + pDoc->setExportZoom(nZoom); + } } static bool getFromTransferable( diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx index fa42c077df5f..3e02f1506a0a 100644 --- a/include/vcl/ITiledRenderable.hxx +++ b/include/vcl/ITiledRenderable.hxx @@ -257,6 +257,15 @@ public: int /*nTileTwipHeight*/) {} + /** + * Provide the zoom level that will used during save/export + * + * @param nExportZoom - the zoom level as a percent + */ + virtual void setExportZoom(int /*nExportZoom*/) + { + } + /// @see lok::Document::setClientVisibleArea(). virtual void setClientVisibleArea(const tools::Rectangle& /*rRectangle*/) { diff --git a/sc/inc/docuno.hxx b/sc/inc/docuno.hxx index 94b6044b2951..5d62c5a13a35 100644 --- a/sc/inc/docuno.hxx +++ b/sc/inc/docuno.hxx @@ -364,6 +364,9 @@ public: /// @see vcl::ITiledRenderable::setClientZoom(). virtual void setClientZoom(int nTilePixelWidth, int nTilePixelHeight, int nTileTwipWidth, int nTileTwipHeight) override; + /// @see vcl::ITiledRenderable::setExportZoom(). + virtual void setExportZoom(int nExportZoom) override; + /// @see vcl::ITiledRenderable::setOutlineState(). virtual void setOutlineState(bool bColumn, int nLevel, int nIndex, bool bHidden) override; diff --git a/sc/inc/scextopt.hxx b/sc/inc/scextopt.hxx index 843dfa6ebab0..4a71fdd7dd30 100644 --- a/sc/inc/scextopt.hxx +++ b/sc/inc/scextopt.hxx @@ -57,6 +57,7 @@ struct ScExtTabSettings Color maGridColor; ///< Grid color. tools::Long mnNormalZoom; ///< Zoom in percent for normal view. tools::Long mnPageZoom; ///< Zoom in percent for pagebreak preview. + std::optional<sal_uInt16> moExportZoom; ///< Zoom in percent - use when NormalZoom isn't accurate bool mbSelected; ///< true = Sheet is selected. bool mbFrozenPanes; ///< true = Frozen panes; false = Normal splits. bool mbPageMode; ///< true = Pagebreak mode; false = Normal view mode. diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx index 282bfeee1cf5..90a68ae7d49a 100644 --- a/sc/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx @@ -18,6 +18,7 @@ #include <comphelper/processfactory.hxx> #include <comphelper/propertysequence.hxx> #include <comphelper/servicehelper.hxx> +#include <comphelper/SetFlagContextHelper.hxx> #include <sfx2/dispatch.hxx> #include <sfx2/viewfrm.hxx> #include <svl/stritem.hxx> @@ -3105,6 +3106,23 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testCellInvalidationDocWithExistingZo CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aView2.m_aInvalidations[0], aView1.m_aInvalidations[0], 50); + // cool#4250: zoom values + pModelObj->setExportZoom(150); + + { + uno::ContextLayer aLayer(comphelper::NewFlagContext(u"IsLOKExport"_ustr)); + save(u"calc8"_ustr); // .ODS + } + xmlDocUniquePtr pSettingsXml = parseExport(u"settings.xml"_ustr); + // Multi-user export: don't save every user's view into the exported file + // assertXPath(pSettingsXml, "//config:config-item[@config:name='ViewId']", 1); + // Use view's logic (not technical) zoom level for export + assertXPathContent(pSettingsXml, "//config:config-item[@config:name='ZoomValue'][1]", u"150"); + + save(u"Calc Office Open XML"_ustr); // .XLSX + xmlDocUniquePtr pSheet1Xml = parseExport(u"xl/worksheets/sheet1.xml"_ustr); + // Use view's logic (not technical) zoom level for export + assertXPath(pSheet1Xml, "//x:sheetViews/x:sheetView", "zoomScale", u"150"); } CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testInputHandlerSyncedZoom) diff --git a/sc/source/filter/excel/xeview.cxx b/sc/source/filter/excel/xeview.cxx index 5280f234eed8..eb73aa67af96 100644 --- a/sc/source/filter/excel/xeview.cxx +++ b/sc/source/filter/excel/xeview.cxx @@ -383,7 +383,9 @@ XclExpTabViewSettings::XclExpTabViewSettings( const XclExpRoot& rRoot, SCTAB nSc // view mode and zoom maData.mbPageMode = (GetBiff() == EXC_BIFF8) && rTabSett.mbPageMode; - maData.mnNormalZoom = lclGetXclZoom( rTabSett.mnNormalZoom, EXC_WIN2_NORMALZOOM_DEF ); + const tools::Long nNormalZoom + = rTabSett.moExportZoom ? *rTabSett.moExportZoom : rTabSett.mnNormalZoom; + maData.mnNormalZoom = lclGetXclZoom(nNormalZoom, EXC_WIN2_NORMALZOOM_DEF); maData.mnPageZoom = lclGetXclZoom( rTabSett.mnPageZoom, EXC_WIN2_PAGEZOOM_DEF ); maData.mnCurrentZoom = maData.mbPageMode ? maData.mnPageZoom : maData.mnNormalZoom; } diff --git a/sc/source/ui/inc/viewdata.hxx b/sc/source/ui/inc/viewdata.hxx index 0fccba0d64d1..de7d910c1756 100644 --- a/sc/source/ui/inc/viewdata.hxx +++ b/sc/source/ui/inc/viewdata.hxx @@ -290,6 +290,8 @@ private: Fraction aDefZoomY; Fraction aDefPageZoomX; // zoom in page break preview mode Fraction aDefPageZoomY; + // If the actual zoom values are for implemention-only purposes, then provide a value for export + std::optional<sal_uInt16> oExportZoom; // used for all sheets ScRefType eRefType; @@ -457,6 +459,9 @@ public: const Fraction& GetZoomX() const { return bPagebreak ? pThisTab->aPageZoomX : pThisTab->aZoomX; } const Fraction& GetZoomY() const { return bPagebreak ? pThisTab->aPageZoomY : pThisTab->aZoomY; } + void SetExportZoom(sal_uInt16 nExportZoom) { oExportZoom = nExportZoom; } + const std::optional<sal_uInt16>& GetExportZoom() const { return oExportZoom; } + void SetShowGrid( bool bShow ); bool GetShowGrid() const { return pThisTab->bShowGrid; } diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx index 9d38d1b080ec..4f376e9d7041 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -1117,6 +1117,19 @@ void ScModelObj::setClientZoom(int nTilePixelWidth_, int nTilePixelHeight_, int pDrawView->resetGridOffsetsForAllSdrPageViews(); } +void ScModelObj::setExportZoom(int nExportZoom) +{ + ScViewData* pViewData = ScDocShell::GetViewData(); + if (!pViewData) + return; + + if (pViewData->GetZoomType() != SvxZoomType::PERCENT) + return; + + assert(nExportZoom > 0 && nExportZoom <= SAL_MAX_UINT16); + pViewData->SetExportZoom(nExportZoom); +} + void ScModelObj::getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter) { ScViewData* pViewData = ScDocShell::GetViewData(); diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx index 7fa3e8f0f6ea..a00ba92a0036 100644 --- a/sc/source/ui/view/viewdata.cxx +++ b/sc/source/ui/view/viewdata.cxx @@ -64,6 +64,7 @@ #include <comphelper/flagguard.hxx> #include <comphelper/lok.hxx> #include <comphelper/processfactory.hxx> +#include <comphelper/SetFlagContextHelper.hxx> #include <comphelper/string.hxx> #include <vcl/uitest/logger.hxx> @@ -594,6 +595,11 @@ void ScViewDataTable::WriteUserDataSequence(uno::Sequence <beans::PropertyValue> sal_Int32 nPageZoomValue = tools::Long(aPageZoomY * 100); pSettings[SC_TABLE_ZOOM_TYPE].Name = SC_ZOOMTYPE; pSettings[SC_TABLE_ZOOM_TYPE].Value <<= sal_Int16(eZoomType); + + const std::optional<sal_uInt16>& oExportZoom = rViewData.GetExportZoom(); + if (oExportZoom && comphelper::IsContextFlagActive(u"IsLOKExport"_ustr)) + nZoomValue = *oExportZoom; + pSettings[SC_TABLE_ZOOM_VALUE].Name = SC_ZOOMVALUE; pSettings[SC_TABLE_ZOOM_VALUE].Value <<= nZoomValue; pSettings[SC_TABLE_PAGE_VIEW_ZOOM_VALUE].Name = SC_PAGEVIEWZOOMVALUE; @@ -3561,6 +3567,7 @@ void ScViewData::WriteExtOptions( ScExtDocOptions& rDocOpt ) const rTabSett.mbPageMode = bPagebreak; rTabSett.mnNormalZoom = static_cast< tools::Long >( pViewTab->aZoomY * Fraction( 100.0 ) ); rTabSett.mnPageZoom = static_cast< tools::Long >( pViewTab->aPageZoomY * Fraction( 100.0 ) ); + rTabSett.moExportZoom = GetExportZoom(); } } } @@ -3777,6 +3784,10 @@ void ScViewData::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rSe sal_Int32 nPageZoomValue = tools::Long(pThisTab->aPageZoomY * 100); pSettings[SC_ZOOM_TYPE].Name = SC_ZOOMTYPE; pSettings[SC_ZOOM_TYPE].Value <<= sal_Int16(pThisTab->eZoomType); + + if (oExportZoom && comphelper::IsContextFlagActive(u"IsLOKExport"_ustr)) + nZoomValue = *oExportZoom; + pSettings[SC_ZOOM_VALUE].Name = SC_ZOOMVALUE; pSettings[SC_ZOOM_VALUE].Value <<= nZoomValue; pSettings[SC_PAGE_VIEW_ZOOM_VALUE].Name = SC_PAGEVIEWZOOMVALUE; diff --git a/xmloff/source/core/xmlexp.cxx b/xmloff/source/core/xmlexp.cxx index b3f21d60e8ef..66b33ab3840c 100644 --- a/xmloff/source/core/xmlexp.cxx +++ b/xmloff/source/core/xmlexp.cxx @@ -45,6 +45,7 @@ #include <comphelper/processfactory.hxx> #include <comphelper/propertysetinfo.hxx> #include <comphelper/propertyvalue.hxx> +#include <comphelper/lok.hxx> #include <xmloff/namespacemap.hxx> #include <xmloff/xmluconv.hxx> #include <xmloff/xmlnamespace.hxx> @@ -1782,6 +1783,12 @@ void SvXMLExport::GetViewSettingsAndViews(uno::Sequence<beans::PropertyValue>& r if(!xViewDataSupplier.is()) return; + std::optional<css::uno::ContextLayer> oLayer; + if (comphelper::LibreOfficeKit::isActive()) + { + oLayer.emplace(comphelper::NewFlagContext(u"IsLOKExport"_ustr)); + } + uno::Reference<container::XIndexAccess> xIndexAccess; xViewDataSupplier->setViewData( xIndexAccess ); // make sure we get a newly created sequence {