put writer numbering graphics under link control

Change-Id: I343f1b182c50769291e72b7216b864e15165d82a
Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2388
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit e768c62b2140dd59910ce029cf82b2763ebad0ef)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205494
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Caolán McNamara
2026-05-22 09:36:43 +02:00
committed by Xisco Fauli
parent 0fc4bfb611
commit e7595c8ec6
7 changed files with 225 additions and 2 deletions
+7
View File
@@ -23,6 +23,7 @@
#include <rtl/ustring.hxx>
#include <editeng/numitem.hxx>
#include <i18nlangtag/lang.h>
#include <tools/ref.hxx>
#include "swdllapi.h"
#include "swtypes.hxx"
#include "calbck.hxx"
@@ -38,6 +39,7 @@ class SwTextFormatColl;
class IDocumentListsAccess;
class SwNodeNum;
namespace vcl { class Font; }
namespace sfx2 { class SvBaseLink; }
class SfxGrabBagItem;
class SwDoc;
class SwTextNode;
@@ -141,6 +143,8 @@ private:
OUString msDefaultListId;
std::shared_ptr<SfxGrabBagItem> mpGrabBagItem; ///< Style InteropGrabBag.
tools::SvRef<sfx2::SvBaseLink> maGrfLinks[ MAXLEVEL ];
public:
/// add parameter <eDefaultNumberFormatPositionAndSpaceMode>
SW_DLLPUBLIC SwNumRule( UIName aNm,
@@ -275,6 +279,9 @@ public:
void dumpAsXml(xmlTextWriterPtr w) const;
SW_DLLPUBLIC void GetGrabBagItem(css::uno::Any& rVal) const;
void SetGrabBagItem(const css::uno::Any& rVal);
void RegisterGrfLinks(SwDoc& rDoc);
void RemoveGrfLinks(SwDoc& rDoc);
};
/// namespace for static functions and methods for numbering and bullets
+7
View File
@@ -14,6 +14,7 @@
#include <vcl/gdimtf.hxx>
#include <svx/svdpage.hxx>
#include <o3tl/string_view.hxx>
#include <sfx2/linkmgr.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <editeng/frmdiritem.hxx>
@@ -23,6 +24,7 @@
#include <unotxdoc.hxx>
#include <drawdoc.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentLinksAdministration.hxx>
#include <IDocumentState.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <rootfrm.hxx>
@@ -545,6 +547,11 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testLinkedBullet)
// Given a document with a graphic bullet, where the image is a linked one:
createSwDoc("linked-bullet.odt");
SwDocShell* pShell = getSwDocShell();
// allow link updates and trigger fetch so the linked bullet image
// is loaded before rendering
pShell->getEmbeddedObjectContainer().setUserAllowsLinkUpdate(true);
sfx2::LinkManager& rLinkMgr = getSwDoc()->getIDocumentLinksAdministration().GetLinkManager();
rLinkMgr.UpdateAllLinks(false, nullptr, u""_ustr);
// When rendering that document:
std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text: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.2"
office:mimetype="application/vnd.oasis.opendocument.text">
<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:show="embed"
xlink:actuate="onLoad">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment"
fo:width="0.4cm" fo:height="0.4cm">
<style:list-level-label-alignment text:label-followed-by="listtab"
fo:text-indent="-0.635cm" fo:margin-left="1.27cm"/>
</style:list-level-properties>
</text:list-level-style-image>
</text:list-style>
</office:automatic-styles>
<office:body>
<office:text>
<text:list text:style-name="L1">
<text:list-item>
<text:p>Bullet item</text:p>
</text:list-item>
</text:list>
</office:text>
</office:body>
</office:document>
@@ -29,10 +29,14 @@
#include <comphelper/scopeguard.hxx>
#include <sfx2/dispatch.hxx>
#include <tools/json_writer.hxx>
#include <vcl/virdev.hxx>
#include <unotxdoc.hxx>
#include <com/sun/star/document/UpdateDocMode.hpp>
#include <sfx2/linkmgr.hxx>
#include <view.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentLinksAdministration.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <docsh.hxx>
@@ -836,6 +840,38 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testIdleLayoutPageDelete)
// i.e. the priority was TaskPriority::HIGH_IDLE instead of TaskPriority::DEFAULT_IDLE.
CPPUNIT_ASSERT_GREATER(TaskPriority::REPAINT, rBindingsTimer.GetPriority());
}
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testImageBulletRemoteNotFetched)
{
// text:list-level-style-image with a remote xlink:href must not fetch
// the URL during paint when link updates are not allowed.
comphelper::LibreOfficeKit::setActive(false);
comphelper::ScopeGuard aLOKitGuard([] { comphelper::LibreOfficeKit::setActive(true); });
uno::Sequence<beans::PropertyValue> aParams = {
comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
};
loadFromFile(u"image-bullet-link.fodt", aParams);
SwDocShell* pDocShell = getSwDocShell();
SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
// the bullet image link should be registered in the link manager
sfx2::LinkManager& rLinkMgr
= pDocShell->GetDoc()->getIDocumentLinksAdministration().GetLinkManager();
CPPUNIT_ASSERT_MESSAGE("bullet image link should be registered", !rLinkMgr.GetLinks().empty());
pWrtShell->CalcLayout();
// render through SwViewShell::Paint which exercises the full text paint
// path including SwGrfNumPortion::Paint -> DrawGraphic -> lcl_DrawGraphic.
// The getUserAllowsLinkUpdate guard blocks the fetch.
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();
@@ -38,6 +38,7 @@
#include <section.hxx>
#include <docary.hxx>
#include <frmfmt.hxx>
#include <numrule.hxx>
#include <fmtcntnt.hxx>
#include <swtable.hxx>
#include <ndtxt.hxx>
@@ -199,6 +200,12 @@ void DocumentLinksAdministrationManager::UpdateLinks()
return;
if (pShell->IsPreview())
return;
// Register links for numbering rules with remote bullet images
// before checking whether the link list is empty
for (SwNumRuleTable::size_type n = 0; n < m_rDoc.GetNumRuleTable().size(); ++n)
m_rDoc.GetNumRuleTable()[n]->RegisterGrfLinks(m_rDoc);
if (GetLinkManager().GetLinks().empty())
return;
sal_uInt16 nLinkMode = m_rDoc.GetDocumentSettingManager().getLinkUpdateMode(true);
+121
View File
@@ -39,6 +39,11 @@
#include <numrule.hxx>
#include <SwNodeNum.hxx>
#include <sfx2/lnkbase.hxx>
#include <sfx2/linkmgr.hxx>
#include <vcl/graph.hxx>
#include <vcl/GraphicObject.hxx>
#include <IDocumentLinksAdministration.hxx>
#include <list.hxx>
@@ -558,6 +563,122 @@ SwNumRule::~SwNumRule()
maParagraphStyleList.clear();
}
namespace {
class SwNumRuleLink final : public sfx2::SvBaseLink
{
SwNumRule* m_pRule;
SwDoc* m_pDoc;
sal_uInt16 m_nLevel;
public:
SwNumRuleLink(SwNumRule* pRule, SwDoc* pDoc, sal_uInt16 nLevel)
: SvBaseLink(SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB)
, m_pRule(pRule)
, m_pDoc(pDoc)
, m_nLevel(nLevel)
{
}
virtual UpdateResult DataChanged(const OUString& rMimeType,
const css::uno::Any& rValue) override
{
if (!m_pRule || !m_pDoc)
return ERROR_GENERAL;
Graphic aGrf;
sfx2::LinkManager& rLinkMgr
= m_pDoc->getIDocumentLinksAdministration().GetLinkManager();
if (!rLinkMgr.GetGraphicFromAny(rMimeType, rValue, aGrf, nullptr))
return ERROR_GENERAL;
if (aGrf.GetType() == GraphicType::Default)
return ERROR_GENERAL;
const SwNumFormat* pFmt = m_pRule->GetNumFormat(m_nLevel);
if (!pFmt)
return SUCCESS;
const SvxBrushItem* pBrush = pFmt->GetBrush();
if (!pBrush)
return SUCCESS;
SvxBrushItem aNewBrush(OUString(), OUString(), GPOS_AREA, RES_BACKGROUND);
aNewBrush.SetGraphic(aGrf);
Size aSize = pFmt->GetGraphicSize();
if (!aSize.Width() || !aSize.Height())
{
Size aPixelSize = aGrf.GetSizePixel();
if (aPixelSize.Width() && aPixelSize.Height())
aSize = OutputDevice::LogicToLogic(aPixelSize,
MapMode(MapUnit::MapPixel),
MapMode(MapUnit::MapTwip));
}
sal_Int16 eOrient = pFmt->GetVertOrient();
SwNumFormat aNewFmt(*pFmt);
aNewFmt.SetGraphicBrush(&aNewBrush, &aSize, &eOrient);
m_pRule->Set(m_nLevel, aNewFmt);
SwNumRule::tTextNodeList aTextNodeList;
m_pRule->GetTextNodeList(aTextNodeList);
for (SwTextNode* pNode : aTextNodeList)
pNode->NumRuleChgd();
return SUCCESS;
}
};
}
void SwNumRule::RegisterGrfLinks(SwDoc& rDoc)
{
sfx2::LinkManager& rLinkMgr
= rDoc.getIDocumentLinksAdministration().GetLinkManager();
for (sal_uInt16 n = 0; n < MAXLEVEL; ++n)
{
if (maGrfLinks[n])
continue;
const SwNumFormat* pFmt = GetNumFormat(n);
if (!pFmt)
continue;
const SvxBrushItem* pBrush = pFmt->GetBrush();
if (!pBrush)
continue;
const Graphic* pGrf = pBrush->GetGraphicObject()
? &pBrush->GetGraphicObject()->GetGraphic()
: nullptr;
if (!pGrf)
continue;
if (pGrf->GetType() != GraphicType::Default)
continue;
OUString aOriginURL = pGrf->getOriginURL();
if (aOriginURL.isEmpty())
continue;
maGrfLinks[n] = new SwNumRuleLink(this, &rDoc, n);
rLinkMgr.InsertFileLink(*maGrfLinks[n],
sfx2::SvBaseLinkObjectType::ClientGraphic,
aOriginURL);
}
}
void SwNumRule::RemoveGrfLinks(SwDoc& rDoc)
{
sfx2::LinkManager& rLinkMgr
= rDoc.getIDocumentLinksAdministration().GetLinkManager();
for (auto& rLink : maGrfLinks)
{
if (rLink)
{
rLinkMgr.Remove(rLink.get());
rLink.clear();
}
}
}
void SwNumRule::CheckCharFormats( SwDoc& rDoc )
{
for(auto& rpNumFormat : maFormats)
+14 -2
View File
@@ -18,6 +18,7 @@
*/
#include <utility>
#include <o3tl/test_info.hxx>
#include <vcl/alpha.hxx>
#include <vcl/canvastools.hxx>
#include <tools/lazydelete.hxx>
@@ -1667,11 +1668,22 @@ static void lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext &rOu
GraphicObject *pGrf = const_cast<GraphicObject*>(rBrush.GetGraphicObject());
// If a graphic with a URL reaches paint without being loaded, only fetch
// it when link updates are allowed.
// Once all URLs as GraphicExternalLink are brought under link manager
// control (bullet images, background images, etc.), this block should
// become unreachable and can be removed.
OUString aOriginURL = pGrf->GetGraphic().getOriginURL();
if (pGrf->GetGraphic().GetType() == GraphicType::Default && !aOriginURL.isEmpty())
{
Graphic aGraphic = vcl::graphic::loadFromURL(aOriginURL);
pGrf->SetGraphic(aGraphic);
SfxObjectShell* pSh = rSh.GetDoc()->GetPersist();
if (pSh && pSh->getEmbeddedObjectContainer().getUserAllowsLinkUpdate())
{
assert(!o3tl::IsRunningUnitTest()
&& "lcl_DrawGraphic: unexpected remote graphic fetch during unit test");
Graphic aGraphic = vcl::graphic::loadFromURL(aOriginURL);
pGrf->SetGraphic(aGraphic);
}
}
// Outsource drawing of background with a background color