oox/qa/unit/data/tdf125085_WordArtFontText.pptx |binary oox/qa/unit/data/tdf125085_WordArtFontTheme.pptx |binary oox/qa/unit/drawingml.cxx | 47 ++ oox/source/drawingml/shape.cxx | 405 +++++++++++++++-------- sd/qa/unit/export-tests-ooxml3.cxx | 15 5 files changed, 329 insertions(+), 138 deletions(-)
New commits: commit bd7f1270cf58eba7600d1b4c6c8ca9a901a04f66 Author: Regina Henschel <rb.hensc...@t-online.de> AuthorDate: Tue Nov 8 10:28:08 2022 +0100 Commit: Regina Henschel <rb.hensc...@t-online.de> CommitDate: Sat Nov 12 12:45:03 2022 +0100 tdf#125085 PPTX WordArt import: get shape font from run PPTX uses the settings at the run for the text in a WordArt shape. LO uses the settings of the shape. The patch copies the run font and language properties to the shape. In addition I have split the old method lcl_createPresetShape and renamed the parts. Now the method lcl_putCustomShapeIntoTextPathMode contains the geometry changes to put a CustomShape into text path mode and to adapt the OOXML values to the values needed for our preset Fontwork shapes, which are based on binary MS Office. MS Office has the style of the characters of a WordArt as properties of the run. LibreOffice ignores most of the properties specified in the style of a span element, when the text is displayed as Fontwork. Instead LO uses the properties defined for the shape for styling the text. Copying the text properties to the shape is now done in method lcl_copyCharPropsToShape. The values in testTdf125573_FontWorkScaleX depend on the used Font. Since on creation time wrong Fonts were used and now correct Fonts are imported, the values have to be updated. Import of fill and stroke of the characters is still missing, only a rudimentary import of color for solid fill exists. Change-Id: I6f31fe07fb0656b2ce8581e7123265fa598ac9c1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142421 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.hensc...@t-online.de> diff --git a/oox/qa/unit/data/tdf125085_WordArtFontText.pptx b/oox/qa/unit/data/tdf125085_WordArtFontText.pptx new file mode 100644 index 000000000000..a9dab6d1ccf8 Binary files /dev/null and b/oox/qa/unit/data/tdf125085_WordArtFontText.pptx differ diff --git a/oox/qa/unit/data/tdf125085_WordArtFontTheme.pptx b/oox/qa/unit/data/tdf125085_WordArtFontTheme.pptx new file mode 100644 index 000000000000..f4c37692afcd Binary files /dev/null and b/oox/qa/unit/data/tdf125085_WordArtFontTheme.pptx differ diff --git a/oox/qa/unit/drawingml.cxx b/oox/qa/unit/drawingml.cxx index 5c0b17e192f6..e25d980f09cb 100644 --- a/oox/qa/unit/drawingml.cxx +++ b/oox/qa/unit/drawingml.cxx @@ -27,6 +27,7 @@ #include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/drawing/TextHorizontalAdjust.hpp> #include <com/sun/star/drawing/XMasterPageTarget.hpp> +#include <com/sun/star/lang/Locale.hpp> #include <com/sun/star/text/XTextRange.hpp> #include <com/sun/star/table/XCellRange.hpp> @@ -549,6 +550,52 @@ CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testTdf113187ConstantArcTo) CPPUNIT_ASSERT_EQUAL(sal_Int32(3600000), aViewBox.Height); } +CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testTdf125085WordArtFontTheme) +{ + // The font info for the shape is in the theme, the text run has no font settings. + loadFromURL(u"tdf125085_WordArtFontTheme.pptx"); + + // Get shape and its properties + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + + // Make sure shape has correct font and local. + // Without the fix some application defaults were used. + OUString sFontName; + xShapeProps->getPropertyValue("CharFontNameComplex") >>= sFontName; + CPPUNIT_ASSERT_EQUAL(OUString(u"Noto Serif Hebrew"), sFontName); + css::lang::Locale aLocal; + xShapeProps->getPropertyValue("CharLocaleComplex") >>= aLocal; + CPPUNIT_ASSERT_EQUAL(OUString(u"IL"), aLocal.Country); + CPPUNIT_ASSERT_EQUAL(OUString(u"he"), aLocal.Language); +} + +CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testTdf125085WordArtFontText) +{ + // The font info for the shape is in the text run inside the shape. + loadFromURL(u"tdf125085_WordArtFontText.pptx"); + + // Get shape and its properties + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + + // Make sure shape has correct font and local. + // Without the fix some application defaults were used. + OUString sFontName; + xShapeProps->getPropertyValue("CharFontNameComplex") >>= sFontName; + CPPUNIT_ASSERT_EQUAL(OUString(u"Noto Serif Hebrew"), sFontName); + css::lang::Locale aLocal; + xShapeProps->getPropertyValue("CharLocaleComplex") >>= aLocal; + CPPUNIT_ASSERT_EQUAL(OUString(u"IL"), aLocal.Country); + CPPUNIT_ASSERT_EQUAL(OUString(u"he"), aLocal.Language); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 99c1c5a979a5..a9b869e86af2 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -86,6 +86,8 @@ #include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> #include <basegfx/point/b2dpoint.hxx> #include <basegfx/polygon/b2dpolygon.hxx> @@ -107,6 +109,8 @@ #include <sal/log.hxx> #include <svx/sdtaitm.hxx> #include <oox/drawingml/diagram/diagram.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <i18nlangtag/mslangid.hxx> using namespace ::oox::core; using namespace ::com::sun::star; @@ -553,31 +557,31 @@ static SdrTextHorzAdjust lcl_convertAdjust( ParagraphAdjust eAdjust ) return SDRTEXTHORZADJUST_LEFT; } -static void lcl_createPresetShape(const uno::Reference<drawing::XShape>& xShape, - const OUString& rClass, const OUString& rPresetType, - const CustomShapePropertiesPtr& pCustomShapePropertiesPtr, - const TextBodyPtr& pTextBody, - const GraphicHelper& rGraphicHelper) +static void +lcl_putCustomShapeIntoTextPathMode(const uno::Reference<drawing::XShape>& xShape, + const CustomShapePropertiesPtr& pCustomShapePropertiesPtr, + const TextBodyPtr& pTextBody) { if (!xShape.is() || !pCustomShapePropertiesPtr || !pTextBody) return; - uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter( xShape, - uno::UNO_QUERY ); - - if (!xDefaulter.is() || rClass.isEmpty()) + uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY); + if (!xDefaulter.is()) return; - Reference<XPropertySet> xSet( xShape, UNO_QUERY ); + Reference<XPropertySet> xSet(xShape, UNO_QUERY); if (!xSet.is()) return; + const OUString sMSPresetType = pTextBody->getTextProperties().msPrst; + const OUString sFontworkType = PresetGeometryTypeNames::GetFontworkType(sMSPresetType); + // The DrawingML shapes from the presetTextWarpDefinitions are mapped to the definitions // in svx/../EnhancedCustomShapeGeometry.cxx, which are used for WordArt shapes from // binary MS Office. Therefore all adjustment values need to be adapted. auto aAdjGdList = pCustomShapePropertiesPtr->getAdjustmentGuideList(); Sequence<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustment( - !aAdjGdList.empty() ? aAdjGdList.size() : 1 ); + !aAdjGdList.empty() ? aAdjGdList.size() : 1); auto pAdjustment = aAdjustment.getArray(); int nIndex = 0; for (const auto& aEntry : aAdjGdList) @@ -585,14 +589,14 @@ static void lcl_createPresetShape(const uno::Reference<drawing::XShape>& xShape, double fValue = aEntry.maFormula.toDouble(); // then: polar-handle, else: XY-handle // There exist only 8 polar-handles at all in presetTextWarp. - if ((rClass == "fontwork-arch-down-curve") - || (rClass == "fontwork-arch-down-pour" && aEntry.maName == "adj1") - || (rClass == "fontwork-arch-up-curve") - || (rClass == "fontwork-arch-up-pour" && aEntry.maName == "adj1") - || (rClass == "fontwork-open-circle-curve") - || (rClass == "fontwork-open-circle-pour" && aEntry.maName == "adj1") - || (rClass == "fontwork-circle-curve") - || (rClass == "fontwork-circle-pour" && aEntry.maName == "adj1")) + if ((sFontworkType == "fontwork-arch-down-curve") + || (sFontworkType == "fontwork-arch-down-pour" && aEntry.maName == "adj1") + || (sFontworkType == "fontwork-arch-up-curve") + || (sFontworkType == "fontwork-arch-up-pour" && aEntry.maName == "adj1") + || (sFontworkType == "fontwork-open-circle-curve") + || (sFontworkType == "fontwork-open-circle-pour" && aEntry.maName == "adj1") + || (sFontworkType == "fontwork-circle-curve") + || (sFontworkType == "fontwork-circle-pour" && aEntry.maName == "adj1")) { // DrawingML has 1/60000 degree unit, but WordArt simple degree. Range [0..360[ // or range ]-180..180] doesn't matter, because only cos(angle) and @@ -606,20 +610,20 @@ static void lcl_createPresetShape(const uno::Reference<drawing::XShape>& xShape, // so scale with 21600/100000 = 0.216, with two exceptions: // X-handles of waves describe increase/decrease relative to horizontal center. // The gdRefR of pour-shapes is not relative to viewBox but to radius. - if ((rClass == "mso-spt158" && aEntry.maName == "adj2") // textDoubleWave1 - || (rClass == "fontwork-wave" && aEntry.maName == "adj2") // textWave1 - || (rClass == "mso-spt157" && aEntry.maName == "adj2") // textWave2 - || (rClass == "mso-spt159" && aEntry.maName == "adj2")) // textWave4 + if ((sFontworkType == "mso-spt158" && aEntry.maName == "adj2") // textDoubleWave1 + || (sFontworkType == "fontwork-wave" && aEntry.maName == "adj2") // textWave1 + || (sFontworkType == "mso-spt157" && aEntry.maName == "adj2") // textWave2 + || (sFontworkType == "mso-spt159" && aEntry.maName == "adj2")) // textWave4 { fValue = (fValue + 50000.0) * 0.216; } - else if ( (rClass == "fontwork-arch-down-pour" && aEntry.maName == "adj2") - || (rClass == "fontwork-arch-up-pour" && aEntry.maName == "adj2") - || (rClass == "fontwork-open-circle-pour" && aEntry.maName == "adj2") - || (rClass == "fontwork-circle-pour" && aEntry.maName == "adj2")) - { - fValue *= 0.108; - } + else if ((sFontworkType == "fontwork-arch-down-pour" && aEntry.maName == "adj2") + || (sFontworkType == "fontwork-arch-up-pour" && aEntry.maName == "adj2") + || (sFontworkType == "fontwork-open-circle-pour" && aEntry.maName == "adj2") + || (sFontworkType == "fontwork-circle-pour" && aEntry.maName == "adj2")) + { + fValue *= 0.108; + } else { fValue *= 0.216; @@ -630,119 +634,255 @@ static void lcl_createPresetShape(const uno::Reference<drawing::XShape>& xShape, pAdjustment[nIndex++].State = css::beans::PropertyState_DIRECT_VALUE; } - // Set properties - xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::Any( false ) ); - xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWWIDTH, uno::Any( false ) ); - xSet->setPropertyValue( UNO_NAME_FILLSTYLE, uno::Any( drawing::FillStyle_SOLID ) ); - - // ToDo: Old binary WordArt does not allow different styles for different paragraphs, so it - // was not necessary to examine all paragraphs. Solution for DrawingML is needed. - // Currently different alignment of paragraphs are lost, for example. - const TextParagraphVector& rParagraphs = pTextBody->getParagraphs(); - if (!rParagraphs.empty() && !rParagraphs[0]->getRuns().empty()) - { - std::shared_ptr<TextParagraph> pParagraph = rParagraphs[0]; - std::shared_ptr<TextRun> pRun = pParagraph->getRuns()[0]; - TextCharacterProperties& pProperties = pRun->getTextCharacterProperties(); - - if (pProperties.moBold.has_value() && pProperties.moBold.value()) - { - xSet->setPropertyValue( UNO_NAME_CHAR_WEIGHT, uno::Any( css::awt::FontWeight::BOLD ) ); - } - if (pProperties.moItalic.has_value() && pProperties.moItalic.value()) - { - xSet->setPropertyValue( UNO_NAME_CHAR_POSTURE, uno::Any( css::awt::FontSlant::FontSlant_ITALIC ) ); - } - if (pProperties.moHeight.has_value()) - { - sal_Int32 nHeight = pProperties.moHeight.value() / 100; - xSet->setPropertyValue( UNO_NAME_CHAR_HEIGHT, uno::Any( nHeight ) ); - } - if (pProperties.maFillProperties.maFillColor.isUsed()) - { - const sal_Int32 aFillColor = static_cast<sal_Int32>( - pProperties.maFillProperties.maFillColor.getColor( rGraphicHelper ).GetRGBColor() ); - xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::Any( aFillColor ) ); - } - else - { - // Set default color - xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::Any( COL_BLACK ) ); - } - { - ParagraphAdjust eAdjust = ParagraphAdjust_LEFT; - if (pParagraph->getProperties().getParaAdjust()) - eAdjust = *pParagraph->getProperties().getParaAdjust(); - xSet->setPropertyValue( "ParaAdjust", uno::Any( eAdjust ) ); - SdrObject* pShape = SdrObject::getSdrObjectFromXShape( xShape ); - assert(pShape); - SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust( eAdjust ); - pShape->SetMergedItem( SdrTextHorzAdjustItem( eHorzAdjust ) ); - } - } - - // Apply vertical adjustment for text on arc - // ToDo: The property is currently not evaluated. - SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape); - assert(pShape); - if (rClass == "fontwork-arch-up-curve" || rClass == "fontwork-circle-curve") - pShape->SetMergedItem( SdrTextVertAdjustItem( SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM ) ); - else if (rClass == "fontwork-arch-down-curve") - pShape->SetMergedItem( SdrTextVertAdjustItem( SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP ) ); - - // Apply preset shape - xDefaulter->createCustomShapeDefaults( rClass ); + // Set attributes in CustomShapeGeometry + xDefaulter->createCustomShapeDefaults(sFontworkType); - auto aGeomPropSeq = xSet->getPropertyValue( "CustomShapeGeometry" ) - .get<uno::Sequence<beans::PropertyValue>>(); + auto aGeomPropSeq + = xSet->getPropertyValue("CustomShapeGeometry").get<uno::Sequence<beans::PropertyValue>>(); auto aGeomPropVec - = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>( - aGeomPropSeq ); + = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>(aGeomPropSeq); // Reset old properties - static const OUStringLiteral sTextPath( u"TextPath" ); - static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" ); - static const OUStringLiteral sPresetTextWarp( u"PresetTextWarp" ); + static const OUStringLiteral sTextPath(u"TextPath"); + static const OUStringLiteral sAdjustmentValues(u"AdjustmentValues"); + static const OUStringLiteral sPresetTextWarp(u"PresetTextWarp"); - lcl_resetPropertyValue( aGeomPropVec, "CoordinateSize" ); - lcl_resetPropertyValue( aGeomPropVec, "Equations" ); - lcl_resetPropertyValue( aGeomPropVec, "Path" ); - lcl_resetPropertyValue( aGeomPropVec, sAdjustmentValues); + lcl_resetPropertyValue(aGeomPropVec, "CoordinateSize"); + lcl_resetPropertyValue(aGeomPropVec, "Equations"); + lcl_resetPropertyValue(aGeomPropVec, "Path"); + lcl_resetPropertyValue(aGeomPropVec, sAdjustmentValues); bool bFromWordArt(false); pTextBody->getTextProperties().maPropertyMap.getProperty(PROP_FromWordArt) >>= bFromWordArt; bool bScaleX(false); if (!bFromWordArt - && (rPresetType == "textArchDown" || rPresetType == "textArchUp" - || rPresetType == "textCircle" || rPresetType == "textButton")) + && (sMSPresetType == "textArchDown" || sMSPresetType == "textArchUp" + || sMSPresetType == "textCircle" || sMSPresetType == "textButton")) { bScaleX = true; } - // Apply geometry properties - uno::Sequence<beans::PropertyValue> aPropertyValues( - comphelper::InitPropertySequence( - { { sTextPath, uno::Any( true ) }, - { "TextPathMode", - uno::Any( drawing::EnhancedCustomShapeTextPathMode_PATH ) }, - { "ScaleX", uno::Any(bScaleX) } } ) ); + // Apply new properties + uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence( + { { sTextPath, uno::Any(true) }, + { "TextPathMode", uno::Any(drawing::EnhancedCustomShapeTextPathMode_PATH) }, + { "ScaleX", uno::Any(bScaleX) } })); - lcl_setPropertyValue( aGeomPropVec, sTextPath, - comphelper::makePropertyValue( sTextPath, aPropertyValues ) ); + lcl_setPropertyValue(aGeomPropVec, sTextPath, + comphelper::makePropertyValue(sTextPath, aPropertyValues)); - lcl_setPropertyValue( aGeomPropVec, sPresetTextWarp, - comphelper::makePropertyValue( sPresetTextWarp, rPresetType ) ); + lcl_setPropertyValue(aGeomPropVec, sPresetTextWarp, + comphelper::makePropertyValue(sPresetTextWarp, sMSPresetType)); if (!aAdjGdList.empty()) { - lcl_setPropertyValue( aGeomPropVec, sAdjustmentValues, - comphelper::makePropertyValue( sAdjustmentValues, aAdjustment ) ); + lcl_setPropertyValue(aGeomPropVec, sAdjustmentValues, + comphelper::makePropertyValue(sAdjustmentValues, aAdjustment)); } - xSet->setPropertyValue( - "CustomShapeGeometry", - uno::Any(comphelper::containerToSequence(aGeomPropVec))); + xSet->setPropertyValue("CustomShapeGeometry", + uno::Any(comphelper::containerToSequence(aGeomPropVec))); +} + +// LO does not interpret properties in styles belonging to the text content of a FontWork shape, +// but only those in the shape style. This method copies properties from the text content styles to +// the shape style. +static void lcl_copyCharPropsToShape(const uno::Reference<drawing::XShape>& xShape, + const TextBodyPtr& pTextBody, + const ::oox::core::XmlFilterBase& rFilter) +{ + if (!xShape.is() || !pTextBody) + return; + + Reference<XPropertySet> xSet(xShape, UNO_QUERY); + if (!xSet.is()) + return; + + // Content stretches or scales to given width and height, thus disable autogrow. + xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::Any(false)); + xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::Any(false)); + + // LibreOffice is not able (as of Nov 2022) to use different styles for the paragraphs or + // characters in FontWork, since that was not allowed in old binary WordArt. We use the + // properties of the first non empty paragraph for now. + const TextParagraphVector& rParagraphs = pTextBody->getParagraphs(); + auto aParaIt = std::find_if_not(rParagraphs.cbegin(), rParagraphs.cend(), + [](const std::shared_ptr<TextParagraph> pParagraph) { + return pParagraph->getRuns().empty(); + }); + if (aParaIt != rParagraphs.cend()) + { + std::shared_ptr<TextParagraph> pParagraph = *aParaIt; + const TextRunVector& rRuns = pParagraph->getRuns(); + auto aRunIt = std::find_if_not( + rRuns.cbegin(), rRuns.cend(), + [](const std::shared_ptr<TextRun> pRun) { return pRun->getText().isEmpty(); }); + if (aRunIt != rRuns.cend()) + { + std::shared_ptr<TextRun> pRun = *aRunIt; + TextCharacterProperties& rCharProps = pRun->getTextCharacterProperties(); + + // set language + if (rCharProps.moLang.has_value() && !rCharProps.moLang.value().isEmpty()) + { + LanguageTag aTag(rCharProps.moLang.value()); + css::lang::Locale aLocale(aTag.getLocale(false)); + switch (MsLangId::getScriptType(aTag.getLanguageType())) + { + case css::i18n::ScriptType::LATIN: + xSet->setPropertyValue(u"CharLocale", uno::Any(aLocale)); + break; + case css::i18n::ScriptType::ASIAN: + xSet->setPropertyValue(u"CharLocaleAsian", uno::Any(aLocale)); + break; + case css::i18n::ScriptType::COMPLEX: + xSet->setPropertyValue(u"CharLocaleComplex", uno::Any(aLocale)); + break; + default:; + } + } + + // Font Weight, Posture, Height + if (rCharProps.moBold.has_value() && rCharProps.moBold.value()) + { + xSet->setPropertyValue(UNO_NAME_CHAR_WEIGHT, uno::Any(css::awt::FontWeight::BOLD)); + } + if (rCharProps.moItalic.has_value() && rCharProps.moItalic.value()) + { + xSet->setPropertyValue(UNO_NAME_CHAR_POSTURE, + uno::Any(css::awt::FontSlant::FontSlant_ITALIC)); + } + if (rCharProps.moHeight.has_value()) + { + sal_Int32 nHeight = rCharProps.moHeight.value() / 100; + xSet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::Any(nHeight)); + } + + // Put theme fonts into shape properties + OUString sFontName; + sal_Int16 nFontPitch = 0; + sal_Int16 nFontFamily = 0; + bool bRet(false); + if (const Theme* pTheme = rFilter.getCurrentTheme()) + { + // minor Latin + if (const TextFont* pFont = pTheme->resolveFont(u"+mn-lt")) + { + bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, rFilter); + if (bRet) + { + xSet->setPropertyValue(u"CharFontName", uno::Any(sFontName)); + xSet->setPropertyValue(u"CharFontPitch", uno::Any(nFontPitch)); + xSet->setPropertyValue(u"CharFontFamily", uno::Any(nFontFamily)); + } + } + // minor Asian + if (const TextFont* pFont = pTheme->resolveFont(u"+mn-ea")) + { + bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, rFilter); + if (bRet) + { + xSet->setPropertyValue(u"CharFontNameAsian", uno::Any(sFontName)); + xSet->setPropertyValue(u"CharFontPitchAsian", uno::Any(nFontPitch)); + xSet->setPropertyValue(u"CharFontFamilyAsian", uno::Any(nFontFamily)); + } + } + // minor Complex + if (const TextFont* pFont = pTheme->resolveFont(u"+mn-cs")) + { + bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, rFilter); + if (bRet) + { + xSet->setPropertyValue(u"CharFontNameComplex", uno::Any(sFontName)); + xSet->setPropertyValue(u"CharFontPitchComplex", uno::Any(nFontPitch)); + xSet->setPropertyValue(u"CharFontFamilyComplex", uno::Any(nFontFamily)); + } + } + } + + // Replace theme fonts with formatting at run if any. ToDo: Inspect paragraph too? + // Latin + bRet = rCharProps.maLatinFont.getFontData(sFontName, nFontPitch, nFontFamily, rFilter); + if (!bRet) + // In case there is no direct font, try to look it up as a theme reference. + bRet = rCharProps.maLatinThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, + rFilter); + + if (bRet) + { + xSet->setPropertyValue(u"CharFontName", uno::Any(sFontName)); + xSet->setPropertyValue(u"CharFontPitch", uno::Any(nFontPitch)); + xSet->setPropertyValue(u"CharFontFamily", uno::Any(nFontFamily)); + } + // Asian + bRet = rCharProps.maAsianFont.getFontData(sFontName, nFontPitch, nFontFamily, rFilter); + if (!bRet) + // In case there is no direct font, try to look it up as a theme reference. + bRet = rCharProps.maAsianThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, + rFilter); + if (bRet) + { + xSet->setPropertyValue(u"CharFontNameAsian", uno::Any(sFontName)); + xSet->setPropertyValue(u"CharFontPitchAsian", uno::Any(nFontPitch)); + xSet->setPropertyValue(u"CharFontFamilyAsian", uno::Any(nFontFamily)); + } + // Complex + bRet + = rCharProps.maComplexFont.getFontData(sFontName, nFontPitch, nFontFamily, rFilter); + if (!bRet) + // In case there is no direct font, try to look it up as a theme reference. + bRet = rCharProps.maComplexThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, + rFilter); + if (bRet) + { + xSet->setPropertyValue(u"CharFontNameComplex", uno::Any(sFontName)); + xSet->setPropertyValue(u"CharFontPitchComplex", uno::Any(nFontPitch)); + xSet->setPropertyValue(u"CharFontFamilyComplex", uno::Any(nFontFamily)); + } + + // LO uses shape fill, MS Office character fill. Currently only this solid fill workaround + // is implemented. + // ToDo: Consider other fill styles + // ToDo: Consider Color Theme + xSet->setPropertyValue(UNO_NAME_FILLSTYLE, uno::Any(drawing::FillStyle_SOLID)); + sal_Int32 aFillColor(COL_BLACK); //default + if (rCharProps.maFillProperties.maFillColor.isUsed()) + { + aFillColor = static_cast<sal_Int32>( + rCharProps.maFillProperties.maFillColor.getColor(rFilter.getGraphicHelper()) + .GetRGBColor()); + } + xSet->setPropertyValue(UNO_NAME_FILLCOLOR, uno::Any(aFillColor)); + + // ToDo: copy character outline to shape stroke. + } + + // LO does not evaluate paragraph alignment in text path mode. Use text area anchor instead. + { + ParagraphAdjust eAdjust = ParagraphAdjust_LEFT; + if (pParagraph->getProperties().getParaAdjust()) + eAdjust = *pParagraph->getProperties().getParaAdjust(); + xSet->setPropertyValue("ParaAdjust", uno::Any(eAdjust)); + SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape); + assert(pShape); + SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust(eAdjust); + pShape->SetMergedItem(SdrTextHorzAdjustItem(eHorzAdjust)); + } + } + + // Vertical adjustment is only meaningful for OOXML WordArt shapes of 'Follow Path' kinds. We set + // it so, that text position is approximately same as in MS Office. + const OUString sMSPresetType = pTextBody->getTextProperties().msPrst; + const OUString sFontworkType = PresetGeometryTypeNames::GetFontworkType(sMSPresetType); + SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape); + assert(pShape); + if (sFontworkType == "fontwork-arch-up-curve" || sFontworkType == "fontwork-circle-curve") + pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM)); + else if (sFontworkType == "fontwork-arch-down-curve") + pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP)); + else + pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_CENTER)); } // Some helper methods for createAndInsert @@ -1766,19 +1906,14 @@ Reference< XShape > const & Shape::createAndInsert( // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs SAL_INFO("oox.cscode", "==cscode== shape name: '" << msName << "'"); SAL_INFO("oox.csdata", "==csdata== shape name: '" << msName << "'"); + mpCustomShapePropertiesPtr->pushToPropSet(xSet, maSize); - if (mpTextBody) + // Consider WordArt + if (mpTextBody && !mpTextBody->getTextProperties().msPrst.isEmpty() + && mpTextBody->getTextProperties().msPrst != u"textNoShape") { - bool bIsPresetShape = !mpTextBody->getTextProperties().msPrst.isEmpty(); - if (bIsPresetShape) - { - OUString sClass; - const OUString sPresetType = mpTextBody->getTextProperties().msPrst; - sClass = PresetGeometryTypeNames::GetFontworkType( sPresetType ); - - lcl_createPresetShape( mxShape, sClass, sPresetType, mpCustomShapePropertiesPtr, mpTextBody, rGraphicHelper ); - } + lcl_putCustomShapeIntoTextPathMode(mxShape, mpCustomShapePropertiesPtr, mpTextBody); } } else if( getTextBody() ) @@ -1847,6 +1982,14 @@ Reference< XShape > const & Shape::createAndInsert( aTextCharacterProps.pushToPropSet(aPropertySet, rFilterBase); } } + + // MS Office has e.g. fill and stroke of WordArt in the character properties, + // LibreOffice uses shape properties. + if (!mpTextBody->getTextProperties().msPrst.isEmpty() + && mpTextBody->getTextProperties().msPrst != u"textNoShape") + { + lcl_copyCharPropsToShape(mxShape, mpTextBody, rFilterBase); + } } } else if (mbTextBox) diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx index 415b801fb293..e5e8cee6c390 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -65,7 +65,7 @@ public: void testTdf145162(); void testZeroIndentExport(); void testTdf100348_convert_Fontwork2TextWarp(); - void testTdf1225573_FontWorkScaleX(); + void testTdf125573_FontWorkScaleX(); void testTdf99497_keepAppearanceOfCircleKind(); /// SmartArt animated elements void testTdf104792(); @@ -155,7 +155,7 @@ public: CPPUNIT_TEST(testTdf145162); CPPUNIT_TEST(testZeroIndentExport); CPPUNIT_TEST(testTdf100348_convert_Fontwork2TextWarp); - CPPUNIT_TEST(testTdf1225573_FontWorkScaleX); + CPPUNIT_TEST(testTdf125573_FontWorkScaleX); CPPUNIT_TEST(testTdf99497_keepAppearanceOfCircleKind); CPPUNIT_TEST(testTdf104792); CPPUNIT_TEST(testTdf90627); @@ -711,7 +711,7 @@ void SdOOXMLExportTest3::testTdf100348_convert_Fontwork2TextWarp() CPPUNIT_ASSERT_EQUAL(9180.0, fAdj2); } -void SdOOXMLExportTest3::testTdf1225573_FontWorkScaleX() +void SdOOXMLExportTest3::testTdf125573_FontWorkScaleX() { loadFromURL(u"pptx/tdf125573_FontWorkScaleX.pptx"); save("Impress Office Open XML"); @@ -722,19 +722,20 @@ void SdOOXMLExportTest3::testTdf1225573_FontWorkScaleX() assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[1]/p:txBody/a:bodyPr[@fromWordArt='1']"); + // State of Nov 2022. It needs to be updated, when import of fill and stroke is implemented. // Error was, that text in legacy shapes of category "Follow Path" was not scaled to the path. uno::Reference<beans::XPropertySet> xShapeArchProps(getShapeFromPage(0, 0)); awt::Rectangle aBoundRectArch; xShapeArchProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectArch; - // difference should be zero, but allow some range for stroke thickness - CPPUNIT_ASSERT_LESS(sal_Int32(50), std::abs(aBoundRectArch.Width - 13081)); + // BoundRect is DPI dependent, thus allow some range. + CPPUNIT_ASSERT_LESS(sal_Int32(50), std::abs(aBoundRectArch.Width - 13038)); // Error was, that text in shapes of category "Warp" was not scaled to the path. uno::Reference<beans::XPropertySet> xShapeWaveProps(getShapeFromPage(0, 1)); awt::Rectangle aBoundRectWave; xShapeWaveProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectWave; - // difference should be zero, but allow some range for stroke thickness - CPPUNIT_ASSERT_LESS(sal_Int32(50), std::abs(aBoundRectWave.Width - 11514)); + // BoundRect is DPI dependent, thus allow some range. + CPPUNIT_ASSERT_LESS(sal_Int32(50), std::abs(aBoundRectWave.Width - 11576)); } void SdOOXMLExportTest3::testTdf99497_keepAppearanceOfCircleKind()