diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2019-06-14 19:10:36 +0200 |
---|---|---|
committer | Regina Henschel <rb.henschel@t-online.de> | 2019-06-17 18:48:14 +0200 |
commit | 2be2c914ed48823304c2e95a836ee93a08853628 (patch) | |
tree | 310fb25c47b2cf6bc07b640cfc54b199cb34b845 /oox | |
parent | 04d37a2151cdab801fff7229c2624a8e21be8c4b (diff) |
tdf#51195, tdf#100348 Convert Fontwork to TextWarp on export
LibreOffice has Fontwork as property text-path in enhanced-custom-
geometry. OOXML has the similar TextWarp as property of a textbox. The
patch converts the custom shape to a textbox and sets the attribute
prstTxWarp. Fill and outline of the Fontwork is lost. The import and
export of fill and outline is tracked in tdf#119221 and still needs
to be fixed.
Change-Id: I8ea7b305d7d0a8367d61c1789f22b56d274a311d
Reviewed-on: https://gerrit.libreoffice.org/74057
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
Diffstat (limited to 'oox')
-rw-r--r-- | oox/inc/drawingml/presetgeometrynames.hxx | 1 | ||||
-rw-r--r-- | oox/source/drawingml/presetgeometrynames.cxx | 21 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 62 | ||||
-rw-r--r-- | oox/source/export/shapes.cxx | 73 |
4 files changed, 139 insertions, 18 deletions
diff --git a/oox/inc/drawingml/presetgeometrynames.hxx b/oox/inc/drawingml/presetgeometrynames.hxx index 51721e41febd..358fc9acefb6 100644 --- a/oox/inc/drawingml/presetgeometrynames.hxx +++ b/oox/inc/drawingml/presetgeometrynames.hxx @@ -16,6 +16,7 @@ namespace PresetGeometryTypeNames { OOX_DLLPUBLIC OUString GetFontworkType(const OUString& rMsoType); +OOX_DLLPUBLIC OUString GetMsoName(const OUString& rFontworkType); } #endif diff --git a/oox/source/drawingml/presetgeometrynames.cxx b/oox/source/drawingml/presetgeometrynames.cxx index 272094dd7ef6..dea972dc1476 100644 --- a/oox/source/drawingml/presetgeometrynames.cxx +++ b/oox/source/drawingml/presetgeometrynames.cxx @@ -91,4 +91,25 @@ OUString PresetGeometryTypeNames::GetFontworkType(const OUString& rMsoType) return OUString(pRetValue, strlen(pRetValue), RTL_TEXTENCODING_ASCII_US); } +OUString PresetGeometryTypeNames::GetMsoName(const OUString& rFontworkType) +{ + static const PresetGeometryHashMap s_HashMapInv = []() { + PresetGeometryHashMap aHInv; + for (const auto& item : pPresetGeometryNameArray) + aHInv[item.pFontworkType] = item.pMsoName; + return aHInv; + }(); + const char* pRetValue = ""; + int i, nLen = rFontworkType.getLength(); + std::unique_ptr<char[]> pBuf(new char[nLen + 1]); + for (i = 0; i < nLen; i++) + pBuf[i] = static_cast<char>(rFontworkType[i]); + pBuf[i] = 0; + PresetGeometryHashMap::const_iterator aHashIter(s_HashMapInv.find(pBuf.get())); + if (aHashIter != s_HashMapInv.end()) + pRetValue = (*aHashIter).second; + + return OUString(pRetValue, strlen(pRetValue), RTL_TEXTENCODING_ASCII_US); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index c87cb3a1f617..575878a11171 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -2544,6 +2544,7 @@ void DrawingML::WriteText( const Reference< XInterface >& rXIface, const OUStrin return; sal_Int32 nTextRotateAngle = 0; + bool bIsFontworkShape(presetWarp.startsWith("text") && (presetWarp != "textNoShape")); #define DEFLRINS 254 #define DEFTBINS 127 @@ -2582,6 +2583,8 @@ void DrawingML::WriteText( const Reference< XInterface >& rXIface, const OUStrin } } + Sequence<drawing::EnhancedCustomShapeAdjustmentValue>aAdjustmentSeq; + if (GetProperty(rXPropSet, "CustomShapeGeometry")) { Sequence< PropertyValue > aProps; @@ -2601,8 +2604,11 @@ void DrawingML::WriteText( const Reference< XInterface >& rXIface, const OUStrin sWritingMode = "vert270"; bVertical = true; } - break; + if (!bIsFontworkShape) + break; } + else if (aProps[i].Name == "AdjustmentValues") + aProps[i].Value >>= aAdjustmentSeq; } } } @@ -2647,10 +2653,60 @@ void DrawingML::WriteText( const Reference< XInterface >& rXIface, const OUStrin XML_anchorCtr, bHorizontalCenter ? "1" : nullptr, XML_vert, sWritingMode, XML_rot, (nTextRotateAngle != 0) ? oox::drawingml::calcRotationValue( nTextRotateAngle * 100 ).getStr() : nullptr ); - if( !presetWarp.isEmpty()) + if (bIsFontworkShape) { - mpFS->singleElementNS(XML_a, XML_prstTxWarp, XML_prst, presetWarp.toUtf8()); + if (aAdjustmentSeq.getLength() > 0) + { + mpFS->startElementNS(XML_a, XML_prstTxWarp, XML_prst, presetWarp.toUtf8()); + mpFS->startElementNS(XML_a, XML_avLst); + for (sal_Int32 i = 0, nElems = aAdjustmentSeq.getLength(); i < nElems; ++i ) + { + OString sName = OString("adj") + (( nElems > 1 ) ? OString::number(i + 1) : OString()); + double fValue(0.0); + if (aAdjustmentSeq[i].Value.getValueTypeClass() == TypeClass_DOUBLE) + aAdjustmentSeq[i].Value >>= fValue; + else + { + sal_Int32 nNumber(0); + aAdjustmentSeq[i].Value >>= nNumber; + fValue = static_cast<double>(nNumber); + } + // Convert from binary coordinate system with viewBox "0 0 21600 21600" and simple degree + // to DrawingML with coordinate range 0..100000 and angle in 1/60000 degree. + // Reverse to conversion in lcl_createPresetShape in drawingml/shape.cxx on import. + if (presetWarp == "textArchDown" || presetWarp == "textArchUp" + || presetWarp == "textButton" || presetWarp == "textCircle" + || ((i == 0) && (presetWarp == "textArchDownPour" || presetWarp == "textArchUpPour" + || presetWarp == "textButtonPour" || presetWarp == "textCirclePour"))) + { + fValue *= 60000.0; + } + else if ((i == 1) && (presetWarp == "textDoubleWave1" || presetWarp == "textWave1" + || presetWarp == "textWave2" || presetWarp == "textWave4")) + { + fValue = fValue / 0.216 - 50000.0; + } + else if ((i == 1) && (presetWarp == "textArchDownPour" || presetWarp == "textArchUpPour" + || presetWarp == "textButtonPour" || presetWarp == "textCirclePour")) + { + fValue /= 0.108; + } + else + { + fValue /= 0.216; + } + OString sFmla = OString("val ") + OString::number(std::lround(fValue)); + mpFS->singleElementNS(XML_a, XML_gd, XML_name, sName, XML_fmla, sFmla); + } + mpFS->endElementNS( XML_a, XML_avLst ); + mpFS->endElementNS(XML_a, XML_prstTxWarp); + } + else + { + mpFS->singleElementNS(XML_a, XML_prstTxWarp, XML_prst, presetWarp.toUtf8()); + } } + if (GetDocumentType() == DOCUMENT_DOCX || GetDocumentType() == DOCUMENT_XLSX) { bool bTextAutoGrowHeight = false; diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx index d441406ae95f..14e5b848558f 100644 --- a/oox/source/export/shapes.cxx +++ b/oox/source/export/shapes.cxx @@ -101,6 +101,7 @@ #include <svx/unoapi.hxx> #include <oox/export/chartexport.hxx> #include <oox/mathml/export.hxx> +#include <drawingml/presetgeometrynames.hxx> using namespace ::css; using namespace ::css::beans; @@ -698,13 +699,56 @@ static sal_Int32 lcl_NormalizeAngle( sal_Int32 nAngle ) ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape ) { + // First check, if this is a Fontwork-shape. For DrawingML, such a shape is a + // TextBox shape with body property prstTxWarp. SAL_INFO("oox.shape", "write custom shape"); - Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY ); + bool bIsFontworkShape(false); + bool bHasGeometrySeq(false); + Sequence< PropertyValue > aGeometrySeq; + OUString sShapeType; + if (GETA(CustomShapeGeometry)) + { + SAL_INFO("oox.shape", "got custom shape geometry"); + if (mAny >>= aGeometrySeq) + { + bHasGeometrySeq = true; + SAL_INFO("oox.shape", "got custom shape geometry sequence"); + for (int i = 0; i < aGeometrySeq.getLength(); i++) + { + const PropertyValue& rProp = aGeometrySeq[i]; + SAL_INFO("oox.shape", "geometry property: " << rProp.Name); + if (rProp.Name == "TextPath") + { + uno::Sequence<beans::PropertyValue> aTextPathSeq; + rProp.Value >>= aTextPathSeq; + for (int k = 0; k < aTextPathSeq.getLength(); k++) + { + const PropertyValue& rTextProp = aTextPathSeq[k]; + if (rTextProp.Name == "TextPath") + { + rTextProp.Value >>= bIsFontworkShape; + } + } + } + else if (rProp.Name == "Type") + rProp.Value >>= sShapeType; + } + } + } + if (bIsFontworkShape) + { + // write the correct type to m_presetWarp, WriteTextShape() needs it + // to set TextWarp. + m_presetWarp = PresetGeometryTypeNames::GetMsoName(sShapeType); + ShapeExport::WriteTextShape(xShape); // qualifier to prevent PowerPointShapeExport + return *this; + } + + bool bPredefinedHandlesUsed = true; bool bHasHandles = false; - OUString sShapeType; ShapeFlag nMirrorFlags = ShapeFlag::NONE; MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( xShape, nMirrorFlags, sShapeType ); OSL_ENSURE(nullptr != dynamic_cast< SdrObjCustomShape* >(GetSdrObjectFromXShape(xShape)), "Not a SdrObjCustomShape (!)"); @@ -715,7 +759,7 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape ) eShapeType)); const char* sPresetShape = msfilter::util::GetOOXMLPresetGeometry(sShapeType.toUtf8().getStr()); SAL_INFO("oox.shape", "custom shape type: " << sShapeType << " ==> " << sPresetShape); - Sequence< PropertyValue > aGeometrySeq; + sal_Int32 nAdjustmentValuesIndex = -1; awt::Rectangle aViewBox; uno::Sequence<beans::PropertyValues> aHandles; @@ -726,12 +770,10 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape ) // Avoid interference of preset type to the next shape m_presetWarp = ""; - if( GETA( CustomShapeGeometry ) ) { - SAL_INFO("oox.shape", "got custom shape geometry"); - if( mAny >>= aGeometrySeq ) { - - SAL_INFO("oox.shape", "got custom shape geometry sequence"); - for( int i = 0; i < aGeometrySeq.getLength(); i++ ) { + if (bHasGeometrySeq) + { + for (int i = 0; i < aGeometrySeq.getLength(); i++) + { const PropertyValue& rProp = aGeometrySeq[ i ]; SAL_INFO("oox.shape", "geometry property: " << rProp.Name); @@ -757,7 +799,6 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape ) } else if ( rProp.Name == "ViewBox" ) rProp.Value >>= aViewBox; - } } } @@ -986,9 +1027,7 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape ) } if( rXPropSet.is() ) { - // Preset shape with text has no fill - if( m_presetWarp.isEmpty() || !m_presetWarp.startsWith( "text" ) || m_presetWarp == "textNoShape" ) - WriteFill( rXPropSet ); + WriteFill( rXPropSet ); WriteOutline( rXPropSet ); WriteShapeEffects( rXPropSet ); WriteShape3DEffects( rXPropSet ); @@ -1793,6 +1832,7 @@ ShapeExport& ShapeExport::WriteTableShape( const Reference< XShape >& xShape ) ShapeExport& ShapeExport::WriteTextShape( const Reference< XShape >& xShape ) { + bool bIsFontworkShape(m_presetWarp.startsWith("text") && m_presetWarp != "textNoShape"); FSHelperPtr pFS = GetFS(); Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY); pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp)); @@ -1831,8 +1871,11 @@ ShapeExport& ShapeExport::WriteTextShape( const Reference< XShape >& xShape ) WriteShapeTransformation( xShape, XML_a ); WritePresetShape( "rect" ); uno::Reference<beans::XPropertySet> xPropertySet(xShape, UNO_QUERY); - WriteBlipOrNormalFill(xPropertySet, "Graphic"); - WriteOutline(xPropertySet); + if (!bIsFontworkShape) // Fontwork needs fill and outline on char instead. + { + WriteBlipOrNormalFill(xPropertySet, "Graphic"); + WriteOutline(xPropertySet); + } WriteShapeEffects(xPropertySet); pFS->endElementNS( mnXmlNamespace, XML_spPr ); |