summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2023-01-18 20:19:51 +0100
committerRegina Henschel <rb.henschel@t-online.de>2023-01-22 10:39:27 +0000
commit7eac3e78abcdece849b8bac61545b0d3ddf5800c (patch)
tree1f8338714b48f9eaa35b4141b4a3f24054e4b989
parenta00556ada3214d7584bebd4d6ac33bf5c25a3467 (diff)
tdf#128568 Improve export to docx of Fontwork with bitmap fill
The modern 'abc transform' in Word is not able to use bitmap fill, but it is possible in legacy VML. Thus use VML in such cases. A WordArt shape in VML has the text not in a <txbxContent> element but as string='...' attribute in the <v:textpath> element. To detect whether a custom shape is a Fontwork in an easy way without cast, I have added the already for custom shapes existing method IsTextPath() to the basis class SdrObject. Using VML for Fontwork with bitmap fill, errors in the VML code become visible: * Using <v:imagedata> element results in Word in a picture of the shape. The shape itself was lost. A bitmap fill of a shape has to be written with the <v:fill> element. * Mode 'stretched' in LO UI becomes type='frame' attribute in VML. I have adapted the unit test NoFillAttrInImagedata in ooxmlexport2.cxx in sw. The source file has the background image in a v:fill element. If you replace the 'wps' namespace with a 'my' namespace in the file generated by LO and so force Word to use the Fallback, you will see that with v:imagedata Word does not show a background image. Thus the assumption in the test was wrong, that there has to be a v:imagedata element. Change-Id: I6b2b5b8bb19adcee3b41e536419556465e85d135 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145823 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
-rw-r--r--include/svx/svdoashp.hxx2
-rw-r--r--include/svx/svdobj.hxx1
-rw-r--r--oox/qa/unit/data/tdf128568_FontworkBitmapFill.odtbin0 -> 17770 bytes
-rw-r--r--oox/qa/unit/export.cxx30
-rw-r--r--oox/source/export/vmlexport.cxx9
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport2.cxx8
-rw-r--r--sw/source/filter/ww8/docxsdrexport.cxx21
7 files changed, 58 insertions, 13 deletions
diff --git a/include/svx/svdoashp.hxx b/include/svx/svdoashp.hxx
index 1a7521a2c764..ef84beeb50e2 100644
--- a/include/svx/svdoashp.hxx
+++ b/include/svx/svdoashp.hxx
@@ -117,7 +117,7 @@ public:
const SdrObject* GetSdrObjectFromCustomShape() const;
const SdrObject* GetSdrObjectShadowFromCustomShape() const;
bool GetTextBounds( tools::Rectangle& rTextBound ) const;
- bool IsTextPath() const;
+ virtual bool IsTextPath() const override;
basegfx::B2DPolyPolygon GetLineGeometry( const bool bBezierAllowed ) const;
protected:
diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx
index 2404060e5936..3efddc78ac0d 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -763,6 +763,7 @@ public:
void SetMarkProtect(bool bProt);
bool IsMarkProtect() const { return m_bMarkProt;}
virtual bool IsSdrTextObj() const { return false; }
+ virtual bool IsTextPath() const { return false ; }
/// Whether the aspect ratio should be kept by default when resizing.
virtual bool shouldKeepAspectRatio() const { return false; }
diff --git a/oox/qa/unit/data/tdf128568_FontworkBitmapFill.odt b/oox/qa/unit/data/tdf128568_FontworkBitmapFill.odt
new file mode 100644
index 000000000000..30a0730a10e7
--- /dev/null
+++ b/oox/qa/unit/data/tdf128568_FontworkBitmapFill.odt
Binary files differ
diff --git a/oox/qa/unit/export.cxx b/oox/qa/unit/export.cxx
index fdf97b328f45..7c312798270a 100644
--- a/oox/qa/unit/export.cxx
+++ b/oox/qa/unit/export.cxx
@@ -768,6 +768,36 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf151008VertAnchor)
assertXPath(pXmlDoc, "//p:spTree/p:sp[6]/p:txBody/a:bodyPr", "anchor", "b");
assertXPath(pXmlDoc, "//p:spTree/p:sp[6]/p:txBody/a:bodyPr", "anchorCtr", "1");
}
+
+CPPUNIT_TEST_FIXTURE(Test, testFontworkBitmapFill)
+{
+ // The document has a Fontwork shape with bitmap fill.
+ loadFromURL(u"tdf128568_FontworkBitmapFill.odt");
+
+ // FIXME: validation error in OOXML export: Errors: 1
+ // Attribute ID is not allowed in element v:shape
+ skipValidation();
+
+ // Saving that to DOCX:
+ save("Office Open XML Text");
+
+ // Make sure it is exported to VML and has no txbxContent but a textpath element. Without fix it
+ // was exported as DML 'abc transform', but that is not able to use bitmap fill in Word.
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ assertXPath(pXmlDoc, "//mc:alternateContent", 0);
+ assertXPath(pXmlDoc, "//v:shape/v:textbox/v:txbxContent", 0);
+ assertXPath(pXmlDoc, "//v:shape/v:textpath", 1);
+
+ // Without fix the bitmap was referenced by v:imagedata element. But that produces a picture
+ // in Word not a WordArt shape. Instead a v:fill has to be used.
+ assertXPath(pXmlDoc, "//v:shape/v:imagedata", 0);
+ assertXPath(pXmlDoc, "//v:shape/v:fill", 1);
+ assertXPath(pXmlDoc, "//v:shape/v:fill[@r:id]", 1);
+
+ // The fill is set to 'stretched' in LO, that is type="frame" in VML. That was not implemented
+ // in VML export.
+ assertXPath(pXmlDoc, "//v:shape/v:fill", "type", "frame");
+}
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 06f1745ab5b6..339187fbe4d2 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -739,7 +739,8 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle&
if (rProps.GetOpt(ESCHER_Prop_fNoFillHitTest, nValue))
impl_AddBool(pAttrList.get(), FSNS(XML_o, XML_detectmouseclick), nValue != 0);
- if (imageData)
+ if (imageData && ((pSdrGrafObj && pSdrGrafObj->isSignatureLine())
+ || m_nShapeType == ESCHER_ShpInst_PictureFrame))
m_pSerializer->singleElementNS( XML_v, XML_imagedata, pAttrList );
else
{
@@ -751,7 +752,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle&
case ESCHER_FillSolid: pFillType = "solid"; break;
// TODO case ESCHER_FillPattern: pFillType = ""; break;
case ESCHER_FillTexture: pFillType = "tile"; break;
- // TODO case ESCHER_FillPicture: pFillType = ""; break;
+ case ESCHER_FillPicture: pFillType = "frame"; break;
// TODO case ESCHER_FillShade: pFillType = ""; break;
// TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
// TODO case ESCHER_FillShadeShape: pFillType = ""; break;
@@ -774,7 +775,6 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle&
if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
impl_AddColor( pAttrList.get(), XML_color2, nValue );
-
if (rProps.GetOpt(ESCHER_Prop_fillOpacity, nValue))
// Partly undo the transformation at the end of EscherPropertyContainer::CreateFillProperties(): VML opacity is 0..1.
pAttrList->add(XML_opacity, OString::number(double((nValue * 100) >> 16) / 100));
@@ -1397,7 +1397,8 @@ sal_Int32 VMLExport::StartShape()
// now check if we have some editeng text (not associated textbox) and we have a text exporter registered
const SdrTextObj* pTxtObj = DynCastSdrTextObj( m_pSdrObject );
- if (pTxtObj && m_pTextExport && msfilter::util::HasTextBoxContent(m_nShapeType) && !IsWaterMarkShape(m_pSdrObject->GetName()) && !lcl_isTextBox(m_pSdrObject))
+ if (pTxtObj && m_pTextExport && !m_pSdrObject->IsTextPath()
+ && !IsWaterMarkShape(m_pSdrObject->GetName()) && !lcl_isTextBox(m_pSdrObject))
{
std::optional<OutlinerParaObject> pParaObj;
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
index 5b47a78aa7e6..1dd6123588ac 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
@@ -1176,11 +1176,13 @@ DECLARE_OOXMLEXPORT_TEST(testTransparentShadow, "transparent-shadow.docx")
CPPUNIT_TEST_FIXTURE(Test, NoFillAttrInImagedata)
{
loadAndSave("NoFillAttrInImagedata.docx");
- //problem was that type and color2 which are v:fill attributes were written in 'v:imagedata'
+ //problem was that type and color2 which are v:fill attributes were written in 'v:imagedata'. The
+ //source file has v:fill and no v:imagedata. Same should be in the file written by LO.
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
- assertXPathNoAttribute(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[2]/mc:Fallback/w:pict/v:rect/v:imagedata", "type");
- assertXPathNoAttribute(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[2]/mc:Fallback/w:pict/v:rect/v:imagedata", "color2");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[2]/mc:Fallback/w:pict/v:rect/v:imagedata", 0);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[2]/mc:Fallback/w:pict/v:rect/v:fill", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[2]/mc:Fallback/w:pict/v:rect/v:fill", "type", "tile");
}
DECLARE_OOXMLEXPORT_TEST(testBnc837302, "bnc837302.docx")
diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx
index c73418df7254..95f7957db5e1 100644
--- a/sw/source/filter/ww8/docxsdrexport.cxx
+++ b/sw/source/filter/ww8/docxsdrexport.cxx
@@ -490,7 +490,8 @@ public:
/// Writes wp wrapper code around an SdrObject, which itself is written using drawingML syntax.
void textFrameShadow(const SwFrameFormat& rFrameFormat);
- static bool isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape);
+ static bool isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape,
+ const SdrObject* pSdrObject);
void setSerializer(const sax_fastparser::FSHelperPtr& pSerializer)
{
@@ -1379,7 +1380,7 @@ void DocxSdrExport::writeDMLDrawing(const SdrObject* pSdrObject, const SwFrameFo
int nAnchorId)
{
uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pSdrObject)->getUnoShape());
- if (!Impl::isSupportedDMLShape(xShape))
+ if (!Impl::isSupportedDMLShape(xShape, pSdrObject))
return;
m_pImpl->getExport().DocxAttrOutput().GetSdtEndBefore(pSdrObject);
@@ -1539,23 +1540,33 @@ void DocxSdrExport::Impl::textFrameShadow(const SwFrameFormat& rFrameFormat)
XML_offset, aOffset);
}
-bool DocxSdrExport::Impl::isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape)
+bool DocxSdrExport::Impl::isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape,
+ const SdrObject* pSdrObject)
{
uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
if (xServiceInfo->supportsService("com.sun.star.drawing.PolyPolygonShape")
|| xServiceInfo->supportsService("com.sun.star.drawing.PolyLineShape"))
return false;
+ uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
// For signature line shapes, we don't want DML, just the VML shape.
if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
{
- uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
bool bIsSignatureLineShape = false;
xShapeProperties->getPropertyValue("IsSignatureLine") >>= bIsSignatureLineShape;
if (bIsSignatureLineShape)
return false;
}
+ // A FontWork shape with bitmap fill cannot be expressed as a modern 'abc transform'
+ // in Word. Only the legacy VML WordArt allows bitmap fill.
+ if (pSdrObject->IsTextPath())
+ {
+ css::drawing::FillStyle eFillStyle = css::drawing::FillStyle_SOLID;
+ xShapeProperties->getPropertyValue("FillStyle") >>= eFillStyle;
+ if (eFillStyle == css::drawing::FillStyle_BITMAP)
+ return false;
+ }
return true;
}
@@ -1575,7 +1586,7 @@ void DocxSdrExport::writeDMLAndVMLDrawing(const SdrObject* sdrObj,
// In case we are already inside a DML block, then write the shape only as VML, turn out that's allowed to do.
// A common service created in util to check for VML shapes which are allowed to have textbox in content
- if ((msfilter::util::HasTextBoxContent(eShapeType)) && Impl::isSupportedDMLShape(xShape)
+ if ((msfilter::util::HasTextBoxContent(eShapeType)) && Impl::isSupportedDMLShape(xShape, sdrObj)
&& (!bDMLAndVMLDrawingOpen || lcl_isLockedCanvas(xShape))) // Locked canvas is OK inside DML
{
m_pImpl->getSerializer()->startElementNS(XML_mc, XML_AlternateContent);