put calc background images under link control

Change-Id: I5adbbaf7e4860732dad2375dcbee541198ef6fab
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2393
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 6ebc3fb5db211b6c9de96dcf3ba14b6b7f37c203)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206342
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Caolán McNamara
2026-06-11 21:42:21 +02:00
committed by Xisco Fauli
parent eb04a45568
commit 23ea1663b7
13 changed files with 375 additions and 15 deletions
+9
View File
@@ -14,6 +14,7 @@
#include <svx/svxdllapi.h>
#include <functional>
class SdrModel;
class SfxItemPool;
namespace sfx2
@@ -21,6 +22,10 @@ namespace sfx2
class LinkManager;
}
// Returns true if the pool contains any XATTR_FILLBITMAP items with
// unresolved remote URLs (GraphicType::Default with non-empty originURL).
SVXCORE_DLLPUBLIC bool hasDeferredFillBitmapLinks(const SfxItemPool& rPool);
// Scan pool surrogates for XATTR_FILLBITMAP items with unresolved remote
// URLs (GraphicType::Default with non-empty originURL) and register an
// sfx2::SvBaseLink for each. When the link is updated, the fetched graphic
@@ -28,6 +33,10 @@ class LinkManager;
SVXCORE_DLLPUBLIC void registerFillBitmapLinks(SfxItemPool& rPool, sfx2::LinkManager& rLinkMgr,
std::function<void()> fnInvalidate);
// Convenience overload for the drawing layer: registers fill bitmap links
// and flushes all ViewObjectContacts on all pages when the graphic arrives.
SVXCORE_DLLPUBLIC void registerFillBitmapLinks(SdrModel& rModel, sfx2::LinkManager& rLinkMgr);
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
office:version="1.3"
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
<office:automatic-styles>
<text:list-style style:name="L1">
<text:list-level-style-image text:level="1"
xlink:href="http://192.0.2.1:12345/bullet.png"
xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed">
<style:list-level-properties text:space-before="0.6cm"
text:min-label-width="0.6cm"
fo:width="0.6cm" fo:height="0.6cm"/>
</text:list-level-style-image>
</text:list-style>
</office:automatic-styles>
<office:body>
<office:spreadsheet>
<table:table table:name="Sheet1">
<table:table-column/>
<table:table-row>
<table:table-cell>
<text:p>Cell content.</text:p>
</table:table-cell>
</table:table-row>
<table:shapes>
<draw:frame svg:x="2cm" svg:y="2cm"
svg:width="10cm" svg:height="5cm">
<draw:text-box>
<text:list text:style-name="L1">
<text:list-item>
<text:p>First bullet with remote image</text:p>
</text:list-item>
<text:list-item>
<text:p>Second bullet with remote image</text:p>
</text:list-item>
</text:list>
</draw:text-box>
</draw:frame>
</table:shapes>
</table:table>
</office:spreadsheet>
</office:body>
</office:document>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
office:version="1.3"
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
<office:automatic-styles>
<style:page-layout style:name="pm1">
<style:page-layout-properties>
<style:background-image
xlink:href="http://192.0.2.1:12345/background.png"
xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"
style:position="center" style:repeat="no-repeat"/>
</style:page-layout-properties>
</style:page-layout>
</office:automatic-styles>
<office:master-styles>
<style:master-page style:name="Default" style:page-layout-name="pm1"/>
</office:master-styles>
<office:body>
<office:spreadsheet>
<table:table table:name="Sheet1">
<table:table-column/>
<table:table-row>
<table:table-cell>
<text:p>Sheet with remote page background image.</text:p>
</table:table-cell>
</table:table-row>
</table:table>
</office:spreadsheet>
</office:body>
</office:document>
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
office:version="1.3"
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
<office:styles>
<draw:fill-image draw:name="remote_bg"
xlink:href="http://192.0.2.1:12345/background.png"
xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"/>
</office:styles>
<office:automatic-styles>
<style:style style:name="gr1" style:family="graphic">
<style:graphic-properties
draw:fill="bitmap"
draw:fill-image-name="remote_bg"
style:repeat="stretch"/>
</style:style>
</office:automatic-styles>
<office:body>
<office:spreadsheet>
<table:table table:name="Sheet1">
<table:table-column/>
<table:table-row>
<table:table-cell>
<text:p>Sheet with shape using remote fill image.</text:p>
</table:table-cell>
</table:table-row>
<table:shapes>
<draw:rect draw:style-name="gr1"
svg:x="2cm" svg:y="2cm"
svg:width="10cm" svg:height="5cm">
<text:p>Rectangle with remote fill.</text:p>
</draw:rect>
</table:shapes>
</table:table>
</office:spreadsheet>
</office:body>
</office:document>
@@ -10,6 +10,7 @@
#include <sctiledrenderingtest.hxx>
#include <com/sun/star/datatransfer/XTransferable2.hpp>
#include <com/sun/star/document/UpdateDocMode.hpp>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/propertysequence.hxx>
@@ -258,6 +259,65 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testBreakPageView)
CPPUNIT_ASSERT_EQUAL(Color(255, 255, 255), aColor);
}
CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testPageBackgroundRemoteNotFetched)
{
// Page background image with a remote URL must not fetch
// the URL during paint when link updates are not allowed.
uno::Sequence<beans::PropertyValue> aParams = {
comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
};
loadFromFile(u"page-background-link.fods", aParams);
ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>(mxComponent);
CPPUNIT_ASSERT(pModelObj);
pModelObj->initializeForTiledRendering({});
ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
pDevice->SetOutputSizePixel(Size(1024, 768));
pModelObj->paintTile(*pDevice, 1024, 768, 0, 0, 15360, 7680);
}
CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testShapeBackgroundRemoteNotFetched)
{
// Shape fill bitmap with a remote URL must not fetch
// the URL during paint when link updates are not allowed.
// The assert in createNewSdrFillGraphicAttribute will fire if
// a remote fetch is attempted.
uno::Sequence<beans::PropertyValue> aParams = {
comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
};
loadFromFile(u"shape-background-link.fods", aParams);
ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>(mxComponent);
CPPUNIT_ASSERT(pModelObj);
pModelObj->initializeForTiledRendering({});
ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
pDevice->SetOutputSizePixel(Size(1024, 768));
pModelObj->paintTile(*pDevice, 1024, 768, 0, 0, 15360, 7680);
}
CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testBulletImageRemoteNotFetched)
{
// text:list-level-style-image with a remote URL must not fetch
// the URL during paint when link updates are not allowed.
// Currently the editeng rendering path silently skips unresolved
// GraphicExternalLink graphics. If someone adds fetching here,
// this test should catch it.
uno::Sequence<beans::PropertyValue> aParams = {
comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
};
loadFromFile(u"bullet-image-link.fods", aParams);
ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>(mxComponent);
CPPUNIT_ASSERT(pModelObj);
pModelObj->initializeForTiledRendering({});
ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
pDevice->SetOutputSizePixel(Size(1024, 768));
pModelObj->paintTile(*pDevice, 1024, 768, 0, 0, 15360, 7680);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+6
View File
@@ -94,6 +94,8 @@
#include <chartpos.hxx>
#include <tablink.hxx>
#include <drwlayer.hxx>
#include <svx/fillbitmaplink.hxx>
#include <svx/svdpage.hxx>
#include <docoptio.hxx>
#include <undostyl.hxx>
#include <rangeseq.hxx>
@@ -214,6 +216,10 @@ void ScDocShell::ReloadAllLinks()
// update linked graphics from the draw layer
if (sfx2::LinkManager* pLinkMgr = m_pDocument->GetDocLinkManager().getLinkManager(false))
{
if (ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer())
{
registerFillBitmapLinks(*pDrawLayer, *pLinkMgr);
}
pLinkMgr->UpdateAllLinks(false, nullptr, u""_ustr);
}
}
+5 -1
View File
@@ -92,6 +92,8 @@
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
#include <sfx2/sidebar/SidebarController.hxx>
#include <svx/fillbitmaplink.hxx>
#include <docpool.hxx>
using namespace com::sun::star;
using namespace sfx2::sidebar;
@@ -1690,7 +1692,9 @@ void ScTabViewShell::Construct( TriState nForceDesignMode )
if (!bLink)
{
const sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
if (rDoc.HasLinkFormulaNeedingCheck() || rDoc.HasAreaLinks() || rMgr.hasExternalLinks())
if (rDoc.HasLinkFormulaNeedingCheck() || rDoc.HasAreaLinks()
|| rMgr.hasExternalLinks()
|| hasDeferredFillBitmapLinks(*rDoc.GetPool()))
bLink = true;
}
if (bLink)
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
office:version="1.3"
office:mimetype="application/vnd.oasis.opendocument.presentation">
<office:styles>
<draw:fill-image draw:name="remote_bg"
xlink:href="http://192.0.2.1:12345/background.png"
xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"/>
</office:styles>
<office:automatic-styles>
<style:style style:name="gr1" style:family="graphic">
<style:graphic-properties
draw:fill="bitmap"
draw:fill-image-name="remote_bg"
style:repeat="stretch"/>
</style:style>
</office:automatic-styles>
<office:body>
<office:presentation>
<draw:page draw:name="Slide1">
<draw:rect draw:style-name="gr1"
svg:x="3cm" svg:y="3cm"
svg:width="18cm" svg:height="12cm">
<text:p>Shape with remote fill image.</text:p>
</draw:rect>
</draw:page>
</office:presentation>
</office:body>
</office:document>
@@ -219,6 +219,26 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testBulletImageRemoteNotFetched)
pImpressDocument->paintTile(*pDevice, 1024, 768, 0, 0, 15360, 7680);
}
CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testShapeFillRemoteNotFetched)
{
// draw:fill-image with a remote URL on a shape must not fetch
// the URL during paint when link updates are not allowed.
// The assert in createNewSdrFillGraphicAttribute will fire if
// a remote fetch is attempted.
uno::Sequence<beans::PropertyValue> aParams = {
comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
};
loadFromFile(u"shape-fill-link.fodp", aParams);
SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pImpressDocument);
pImpressDocument->initializeForTiledRendering({});
ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
pDevice->SetOutputSizePixel(Size(1024, 768));
pImpressDocument->paintTile(*pDevice, 1024, 768, 0, 0, 15360, 7680);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+1 -8
View File
@@ -993,14 +993,7 @@ void SdDrawDocument::UpdateAllLinks()
// Register links for fill bitmap items (e.g. slide background images)
// with unresolved remote URLs, before checking whether the link list is empty.
registerFillBitmapLinks(GetItemPool(), *m_pLinkManager,
[this]()
{
for (sal_uInt16 i = 0; i < GetPageCount(); ++i)
GetPage(i)->ActionChanged();
for (sal_uInt16 i = 0; i < GetMasterPageCount(); ++i)
GetMasterPage(i)->ActionChanged();
});
registerFillBitmapLinks(*this, *m_pLinkManager);
if (m_pLinkManager->GetLinks().empty())
return;
+35 -6
View File
@@ -12,7 +12,9 @@
#include <svx/fillbitmaplink.hxx>
#include <sfx2/lnkbase.hxx>
#include <sfx2/linkmgr.hxx>
#include <sot/formats.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svl/itempool.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/xdef.hxx>
@@ -74,16 +76,33 @@ public:
};
}
namespace
{
OUString getDeferredOriginURL(const XFillBitmapItem& rItem)
{
const Graphic& rGrf = rItem.GetGraphicObject().GetGraphic();
if (rGrf.GetType() == GraphicType::Default)
return rGrf.getOriginURL();
return OUString();
}
}
bool hasDeferredFillBitmapLinks(const SfxItemPool& rPool)
{
for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(XATTR_FILLBITMAP))
{
if (!getDeferredOriginURL(static_cast<const XFillBitmapItem&>(*pItem)).isEmpty())
return true;
}
return false;
}
void registerFillBitmapLinks(SfxItemPool& rPool, sfx2::LinkManager& rLinkMgr,
std::function<void()> fnInvalidate)
{
for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(XATTR_FILLBITMAP))
{
auto* pBmpItem = static_cast<const XFillBitmapItem*>(pItem);
const Graphic& rGrf = pBmpItem->GetGraphicObject().GetGraphic();
if (rGrf.GetType() != GraphicType::Default)
continue;
OUString aURL = rGrf.getOriginURL();
OUString aURL = getDeferredOriginURL(static_cast<const XFillBitmapItem&>(*pItem));
if (aURL.isEmpty())
continue;
tools::SvRef<sfx2::SvBaseLink> xLink(new FillBitmapLink(rPool, rLinkMgr, fnInvalidate));
@@ -91,4 +110,14 @@ void registerFillBitmapLinks(SfxItemPool& rPool, sfx2::LinkManager& rLinkMgr,
}
}
void registerFillBitmapLinks(SdrModel& rModel, sfx2::LinkManager& rLinkMgr)
{
registerFillBitmapLinks(rModel.GetItemPool(), rLinkMgr, [&rModel]() {
for (sal_uInt16 nPage = 0; nPage < rModel.GetPageCount(); ++nPage)
rModel.GetPage(nPage)->GetViewContact().flushViewObjectContacts();
for (sal_uInt16 nPage = 0; nPage < rModel.GetMasterPageCount(); ++nPage)
rModel.GetMasterPage(nPage)->GetViewContact().flushViewObjectContacts();
});
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
office:version="1.3"
office:mimetype="application/vnd.oasis.opendocument.text">
<office:styles>
<draw:fill-image draw:name="remote_bg"
xlink:href="http://192.0.2.1:12345/background.png"
xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"/>
</office:styles>
<office:automatic-styles>
<style:style style:name="gr1" style:family="graphic">
<style:graphic-properties
draw:fill="bitmap"
draw:fill-image-name="remote_bg"
style:repeat="stretch"
style:wrap="none"
style:vertical-pos="top"
style:vertical-rel="paragraph"
style:horizontal-pos="from-left"
style:horizontal-rel="paragraph"/>
</style:style>
</office:automatic-styles>
<office:body>
<office:text>
<text:p>
<draw:custom-shape draw:style-name="gr1" text:anchor-type="paragraph"
draw:z-index="0"
svg:x="2cm" svg:y="1cm"
svg:width="12cm" svg:height="6cm">
<text:p>Shape with remote fill image.</text:p>
<draw:enhanced-geometry svg:viewBox="0 0 21600 21600"
draw:type="rectangle"
draw:enhanced-path="M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N"/>
</draw:custom-shape>
</text:p>
</office:text>
</office:body>
</office:document>
@@ -930,6 +930,31 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testPageBackgroundImageRemoteNotFetch
*pDevice, tools::Rectangle(Point(0, 0), pWrtShell->GetLayout()->getFrameArea().SSize()));
}
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testShapeFillRemoteNotFetched)
{
// draw:fill-image with a remote URL on a shape must not fetch
// the URL during paint when link updates are not allowed.
// The assert in createNewSdrFillGraphicAttribute will fire if
// a remote fetch is attempted.
comphelper::LibreOfficeKit::setActive(false);
uno::Sequence<beans::PropertyValue> aParams = {
comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
};
loadFromFile(u"shape-fill-link.fodt", aParams);
SwDocShell* pDocShell = getSwDocShell();
SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
pWrtShell->CalcLayout();
ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
pDevice->SetOutputSizePixel(Size(1024, 1024));
static_cast<SwViewShell*>(pWrtShell)->Paint(
*pDevice, tools::Rectangle(Point(0, 0), pWrtShell->GetLayout()->getFrameArea().SSize()));
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */