include/docmodel/theme/FormatScheme.hxx | 132 ++++- include/docmodel/theme/Theme.hxx | 23 include/oox/export/ThemeExport.hxx | 4 include/oox/export/drawingml.hxx | 94 +++ oox/source/export/ThemeExport.cxx | 757 ++++++++++++++++++++++++++++--- oox/source/export/drawingml.cxx | 90 +-- sc/source/filter/excel/xestream.cxx | 7 sd/qa/filter/eppt/eppt.cxx | 85 ++- sd/source/filter/eppt/epptooxml.hxx | 7 sd/source/filter/eppt/pptx-epptooxml.cxx | 324 ------------- svx/source/svdraw/svdpage.cxx | 4 sw/source/filter/ww8/docxexport.cxx | 7 12 files changed, 1028 insertions(+), 506 deletions(-)
New commits: commit 0ee38e7e061f764b5e21487da090620ed93bb260 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Apr 10 12:15:19 2023 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Mon Apr 24 23:50:05 2023 +0200 oox: combine graphic cache into GraphicExportCache class We cache graphics to not export the same graphic multiple times if this can be avoided. The cache was integrated into DrawingML but we need access to it in different places, so this change extracts it into its own class. Change-Id: I71e3b67906f2948ca00c2ef7ca857bf80ab6a737 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150258 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index 946afbf5d57b..8fb8d6ba2e52 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -139,16 +139,99 @@ protected: virtual ~DMLTextExport() {} }; +class OOX_DLLPUBLIC GraphicExportCache +{ +private: + std::stack<sal_Int32> mnImageCounter; + std::stack<std::unordered_map<BitmapChecksum, OUString>> maExportGraphics; + std::stack<sal_Int32> mnWdpImageCounter; + std::stack<std::map<OUString, OUString>> maWdpCache; + + GraphicExportCache() = default; +public: + static GraphicExportCache& get(); + + void push() + { + mnImageCounter.push(1); + maExportGraphics.emplace(); + mnWdpImageCounter.push(1); + maWdpCache.emplace(); + } + + void pop() + { + mnImageCounter.pop(); + maExportGraphics.pop(); + mnWdpImageCounter.pop(); + maWdpCache.pop(); + } + + bool hasExportGraphics() + { + return !maExportGraphics.empty(); + } + + void addExportGraphics(BitmapChecksum aChecksum, OUString const& sPath) + { + maExportGraphics.top()[aChecksum] = sPath; + } + + OUString findExportGraphics(BitmapChecksum aChecksum) + { + OUString sPath; + if (!hasExportGraphics()) + return sPath; + + auto aIterator = maExportGraphics.top().find(aChecksum); + if (aIterator != maExportGraphics.top().end()) + sPath = aIterator->second; + return sPath; + } + + sal_Int32 nextImageCount() + { + sal_Int32 nCount = mnImageCounter.top(); + mnImageCounter.top()++; + return nCount; + } + + bool hasWdpCache() + { + return !maWdpCache.empty(); + } + + OUString findWdpID(OUString const& rFileId) + { + OUString aPath; + if (!hasWdpCache()) + return aPath; + auto aCachedItem = maWdpCache.top().find(rFileId); + if (aCachedItem != maWdpCache.top().end()) + aPath = aCachedItem->second; + return aPath; + } + + void addToWdpCache(OUString const& rFileId, OUString const& rId) + { + if (hasWdpCache()) + maWdpCache.top()[rFileId] = rId; + } + + sal_Int32 nextWdpImageCount() + { + sal_Int32 nCount = mnWdpImageCounter.top(); + mnWdpImageCounter.top()++; + return nCount; + } +}; + class OOX_DLLPUBLIC DrawingML { private: - static std::stack<sal_Int32> mnImageCounter; - static std::stack<sal_Int32> mnWdpImageCounter; - static std::stack<std::map<OUString, OUString>> maWdpCache; static sal_Int32 mnDrawingMLCount; static sal_Int32 mnVmlCount; - static std::stack<std::unordered_map<BitmapChecksum, OUString>> maExportGraphics; /// To specify where write eg. the images to (like 'ppt', or 'word' - according to the OPC). DocumentType meDocumentType; @@ -371,9 +454,6 @@ public: static void ResetMlCounters(); - static void PushExportGraphics(); - static void PopExportGraphics(); - static sal_Int32 getNewDrawingUniqueId() { return ++mnDrawingMLCount; } static sal_Int32 getNewVMLUniqueId() { return ++mnVmlCount; } static sal_Int32 getNewChartUniqueId() { return ++mnChartCount; } diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 75541b084e3b..773aa6c4ae0c 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -209,6 +209,12 @@ bool URLTransformer::isExternalURL(const OUString& rURL) const return bExternal; } +GraphicExportCache& GraphicExportCache::get() +{ + static GraphicExportCache staticGraphicExportCache; + return staticGraphicExportCache; +} + static css::uno::Any getLineDash( const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rDashName ) { css::uno::Reference<css::lang::XMultiServiceFactory> xFact(xModel, css::uno::UNO_QUERY); @@ -253,13 +259,9 @@ void WriteGradientPath(const awt::Gradient2& rGradient, const FSHelperPtr& pFS, } // not thread safe -std::stack<sal_Int32> DrawingML::mnImageCounter; -std::stack<sal_Int32> DrawingML::mnWdpImageCounter; -std::stack<std::map<OUString, OUString>> DrawingML::maWdpCache; sal_Int32 DrawingML::mnDrawingMLCount = 0; sal_Int32 DrawingML::mnVmlCount = 0; sal_Int32 DrawingML::mnChartCount = 0; -std::stack<std::unordered_map<BitmapChecksum, OUString>> DrawingML::maExportGraphics; sal_Int16 DrawingML::GetScriptType(const OUString& rStr) { @@ -292,24 +294,6 @@ void DrawingML::ResetMlCounters() mnChartCount = 0; } -void DrawingML::PushExportGraphics() -{ - mnImageCounter.push(1); - maExportGraphics.emplace(); - - mnWdpImageCounter.push(1); - maWdpCache.emplace(); -} - -void DrawingML::PopExportGraphics() -{ - mnImageCounter.pop(); - maExportGraphics.pop(); - - mnWdpImageCounter.pop(); - maWdpCache.pop(); -} - bool DrawingML::GetProperty( const Reference< XPropertySet >& rXPropertySet, const OUString& aName ) { try @@ -1515,12 +1499,8 @@ OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia ) OUString sPath; // tdf#74670 tdf#91286 Save image only once - if (!maExportGraphics.empty()) - { - auto aIterator = maExportGraphics.top().find(aChecksum); - if (aIterator != maExportGraphics.top().end()) - sPath = aIterator->second; - } + GraphicExportCache& rGraphicExportCache = GraphicExportCache::get(); + sPath = rGraphicExportCache.findExportGraphics(aChecksum); if (sPath.isEmpty()) { @@ -1605,10 +1585,11 @@ OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia ) } } + sal_Int32 nImageCount = rGraphicExportCache.nextImageCount(); Reference<XOutputStream> xOutStream = mpFB->openFragmentStream( OUStringBuffer() .appendAscii(GetComponentDir()) - .append("/media/image" + OUString::number(mnImageCounter.top())) + .append("/media/image" + OUString::number(nImageCount)) .appendAscii(pExtension) .makeStringAndClear(), sMediaType); @@ -1624,12 +1605,11 @@ OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia ) sPath = OUStringBuffer() .appendAscii(sRelationCompPrefix.getStr()) .appendAscii(sRelPathToMedia.getStr()) - .append(static_cast<sal_Int32>(mnImageCounter.top()++)) + .append(nImageCount) .appendAscii(pExtension) .makeStringAndClear(); - if (!maExportGraphics.empty()) - maExportGraphics.top()[aChecksum] = sPath; + rGraphicExportCache.addExportGraphics(aChecksum, sPath); } sRelId = mpFB->addRelation( mpFS->getOutputStream(), @@ -1704,14 +1684,15 @@ void DrawingML::WriteMediaNonVisualProperties(const css::uno::Reference<css::dra if (bEmbed) { + sal_Int32 nImageCount = GraphicExportCache::get().nextImageCount(); + + OUString sFileName = OUStringBuffer() + .appendAscii(GetComponentDir()) + .append("/media/media" + OUString::number(nImageCount) + aExtension) + .makeStringAndClear(); + // copy the video stream - Reference<XOutputStream> xOutStream = mpFB->openFragmentStream(OUStringBuffer() - .appendAscii(GetComponentDir()) - .append("/media/media" + - OUString::number(mnImageCounter.top()) + - aExtension) - .makeStringAndClear(), - aMimeType); + Reference<XOutputStream> xOutStream = mpFB->openFragmentStream(sFileName, aMimeType); uno::Reference<io::XInputStream> xInputStream(pMediaObj->GetInputStream()); comphelper::OStorageHelper::CopyInputToOutput(xInputStream, xOutStream); @@ -1720,7 +1701,7 @@ void DrawingML::WriteMediaNonVisualProperties(const css::uno::Reference<css::dra // create the relation OUString aPath = OUStringBuffer().appendAscii(GetRelationCompPrefix()) - .append("media/media" + OUString::number(mnImageCounter.top()++) + aExtension) + .append("media/media" + OUString::number(nImageCount) + aExtension) .makeStringAndClear(); aVideoFileRelId = mpFB->addRelation(mpFS->getOutputStream(), oox::getRelationship(eMediaType), aPath); aMediaRelId = mpFB->addRelation(mpFS->getOutputStream(), oox::getRelationship(Relationship::MEDIA), aPath); @@ -6212,33 +6193,28 @@ void DrawingML::WriteArtisticEffect( const Reference< XPropertySet >& rXPropSet OString DrawingML::WriteWdpPicture( const OUString& rFileId, const Sequence< sal_Int8 >& rPictureData ) { - if (!maWdpCache.empty()) - { - std::map<OUString, OUString>::iterator aCachedItem = maWdpCache.top().find(rFileId); - if (aCachedItem != maWdpCache.top().end()) - return OUStringToOString(aCachedItem->second, RTL_TEXTENCODING_UTF8); - } + auto& rGraphicExportCache = GraphicExportCache::get(); + + OUString aId = rGraphicExportCache.findWdpID(rFileId); + if (!aId.isEmpty()) + return OUStringToOString(aId, RTL_TEXTENCODING_UTF8); - OUString sFileName = "media/hdphoto" + OUString::number( mnWdpImageCounter.top()++ ) + ".wdp"; - Reference< XOutputStream > xOutStream = mpFB->openFragmentStream( OUStringBuffer() - .appendAscii( GetComponentDir() ) - .append( "/" + sFileName ) - .makeStringAndClear(), - "image/vnd.ms-photo" ); - OUString sId; + sal_Int32 nWdpImageCount = rGraphicExportCache.nextWdpImageCount(); + OUString sFileName = "media/hdphoto" + OUString::number(nWdpImageCount) + ".wdp"; + OUString sFragment = OUStringBuffer().appendAscii(GetComponentDir()).append( "/" + sFileName).makeStringAndClear(); + Reference< XOutputStream > xOutStream = mpFB->openFragmentStream(sFragment, "image/vnd.ms-photo"); xOutStream->writeBytes( rPictureData ); xOutStream->closeOutput(); - sId = mpFB->addRelation( mpFS->getOutputStream(), + aId = mpFB->addRelation( mpFS->getOutputStream(), oox::getRelationship(Relationship::HDPHOTO), OUStringBuffer() .appendAscii( GetRelationCompPrefix() ) .append( sFileName ) ); - if (!maWdpCache.empty()) - maWdpCache.top()[rFileId] = sId; + rGraphicExportCache.addToWdpCache(rFileId, aId); - return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 ); + return OUStringToOString(aId, RTL_TEXTENCODING_UTF8); } void DrawingML::WriteDiagram(const css::uno::Reference<css::drawing::XShape>& rXShape, int nDiagramId) diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 75f03dfde94d..8d31023e4a57 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -1026,7 +1026,10 @@ bool XclExpXmlStream::exportDocument() // Instead, write via XOutputStream instance. tools::SvRef<SotStorage> rStorage = static_cast<SotStorage*>(nullptr); drawingml::DrawingML::ResetMlCounters(); - drawingml::DrawingML::PushExportGraphics(); + + auto& rGraphicExportCache = drawingml::GraphicExportCache::get(); + + rGraphicExportCache.push(); XclExpRootData aData( EXC_BIFF8, *pShell->GetMedium (), rStorage, rDoc, @@ -1145,7 +1148,7 @@ bool XclExpXmlStream::exportDocument() xStatusIndicator->end(); mpRoot = nullptr; - drawingml::DrawingML::PopExportGraphics(); + rGraphicExportCache.pop(); return true; } diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index 9e207baf1be6..a8dca7463fdd 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -431,7 +431,10 @@ bool PowerPointExport::importDocument() noexcept bool PowerPointExport::exportDocument() { drawingml::DrawingML::ResetMlCounters(); - DrawingML::PushExportGraphics(); + auto& rGraphicExportCache = drawingml::GraphicExportCache::get(); + + rGraphicExportCache.push(); + maShapeMap.clear(); mXModel = getModel(); @@ -515,7 +518,8 @@ bool PowerPointExport::exportDocument() commitStorage(); - DrawingML::PopExportGraphics(); + rGraphicExportCache.pop(); + maShapeMap.clear(); maAuthors.clear(); maRelId.clear(); diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 2fdcadce6dd9..59b91603acc1 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -526,8 +526,10 @@ ErrCode DocxExport::ExportDocument_Impl() // init sections m_pSections.reset(new MSWordSections( *this )); + auto& rGraphicExportCache = oox::drawingml::GraphicExportCache::get(); + // Make sure images are counted from one, even when exporting multiple documents. - oox::drawingml::DrawingML::PushExportGraphics(); + rGraphicExportCache.push(); WriteMainText(); @@ -555,7 +557,8 @@ ErrCode DocxExport::ExportDocument_Impl() m_aLinkedTextboxesHelper.clear(); //final cleanup m_pStyles.reset(); m_pSections.reset(); - oox::drawingml::DrawingML::PopExportGraphics(); + + rGraphicExportCache.pop(); return ERRCODE_NONE; } commit c3f7720ff13c34b9cf2c90d9c9b6dcc3d8f4c7a5 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Thu Mar 23 11:37:40 2023 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Mon Apr 24 23:49:57 2023 +0200 oox: extend ThemeExport to export font and format scheme of a theme Also use the ThemeExport when exporting PPTX documents and remove all the hard-coded theme bits. Change-Id: I03791e23d6ac4023748b5a553e4824b72ed63a93 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149363 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/include/docmodel/theme/FormatScheme.hxx b/include/docmodel/theme/FormatScheme.hxx index feec16ee187f..420d5c1b7584 100644 --- a/include/docmodel/theme/FormatScheme.hxx +++ b/include/docmodel/theme/FormatScheme.hxx @@ -79,6 +79,8 @@ struct DOCMODEL_DLLPUBLIC ColorDefinition ThemeColorType meSchemeType = ThemeColorType::Unknown; std::vector<Transformation> maTransformations; + Color getRGBColor() const { return Color(mnComponent1, mnComponent2, mnComponent3); } + void setCRGB(sal_Int32 nR, sal_Int32 nG, sal_Int32 nB) { mnComponent1 = nR; @@ -436,9 +438,9 @@ enum class LineEndLength struct DOCMODEL_DLLPUBLIC LineEnd { - LineEndType meType; - LineEndWidth meWidth; - LineEndLength meLength; + LineEndType meType = LineEndType::None; + LineEndWidth meWidth = LineEndWidth::Unset; + LineEndLength meLength = LineEndLength::Unset; }; struct DOCMODEL_DLLPUBLIC DashStop @@ -527,6 +529,42 @@ public: const OUString& getName() const { return maName; } + std::vector<FillStyle> const& getFillStyleList() const { return maFillStyleList; } + + FillStyle* addFillStyle() + { + if (maFillStyleList.size() > 3) + return nullptr; + auto& rFillStyle = maFillStyleList.emplace_back(); + return &rFillStyle; + } + + void ensureFillStyleList() const + { + if (!maFillStyleList.empty()) + return; + + auto* pThis = const_cast<FormatScheme*>(this); + { + FillStyle* pFillStyle = pThis->addFillStyle(); + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pFillStyle->mpFill = pFill; + } + { + FillStyle* pFillStyle = pThis->addFillStyle(); + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pFillStyle->mpFill = pFill; + } + { + FillStyle* pFillStyle = pThis->addFillStyle(); + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pFillStyle->mpFill = pFill; + } + } + std::vector<LineStyle> const& getLineStyleList() const { return maLineStyleList; } LineStyle* addLineStyle() @@ -537,6 +575,51 @@ public: return &rLineStyle; } + void ensureLineStyleList() const + { + if (!maLineStyleList.empty()) + return; + + auto* pThis = const_cast<FormatScheme*>(this); + + { + LineStyle* pLineStyle = pThis->addLineStyle(); + pLineStyle->mnWidth = 6350; + pLineStyle->meCapType = CapType::Flat; + pLineStyle->mePenAlignment = PenAlignmentType::Center; + pLineStyle->meCompoundLineType = CompoundLineType::Single; + pLineStyle->maLineDash.mePresetType = PresetDashType::Solid; + pLineStyle->maLineJoin.meType = LineJoinType::Miter; + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pLineStyle->maLineFillStyle.mpFill = pFill; + } + { + LineStyle* pLineStyle = pThis->addLineStyle(); + pLineStyle->mnWidth = 6350; + pLineStyle->meCapType = CapType::Flat; + pLineStyle->mePenAlignment = PenAlignmentType::Center; + pLineStyle->meCompoundLineType = CompoundLineType::Single; + pLineStyle->maLineDash.mePresetType = PresetDashType::Solid; + pLineStyle->maLineJoin.meType = LineJoinType::Miter; + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pLineStyle->maLineFillStyle.mpFill = pFill; + } + { + LineStyle* pLineStyle = pThis->addLineStyle(); + pLineStyle->mnWidth = 6350; + pLineStyle->meCapType = CapType::Flat; + pLineStyle->mePenAlignment = PenAlignmentType::Center; + pLineStyle->meCompoundLineType = CompoundLineType::Single; + pLineStyle->maLineDash.mePresetType = PresetDashType::Solid; + pLineStyle->maLineJoin.meType = LineJoinType::Miter; + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pLineStyle->maLineFillStyle.mpFill = pFill; + } + } + std::vector<EffectStyle> const& getEffectStyleList() const { return maEffectStyleList; } EffectStyle* addEffectStyle() @@ -547,14 +630,16 @@ public: return &rEffectStyle; } - std::vector<FillStyle> const& getFillStyleList() const { return maFillStyleList; } - - FillStyle* addFillStyle() + void ensureEffectStyleList() const { - if (maFillStyleList.size() > 3) - return nullptr; - auto& rFillStyle = maFillStyleList.emplace_back(); - return &rFillStyle; + if (!maEffectStyleList.empty()) + return; + + auto* pThis = const_cast<FormatScheme*>(this); + + pThis->addEffectStyle(); + pThis->addEffectStyle(); + pThis->addEffectStyle(); } std::vector<FillStyle> const& getBackgroundFillStyleList() const @@ -569,6 +654,33 @@ public: auto& rBackgroundFillStyle = maBackgroundFillStyleList.emplace_back(); return &rBackgroundFillStyle; } + + void ensureBackgroundFillStyleList() const + { + if (!maBackgroundFillStyleList.empty()) + return; + + auto* pThis = const_cast<FormatScheme*>(this); + + { + FillStyle* pFillStyle = pThis->addBackgroundFillStyle(); + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pFillStyle->mpFill = pFill; + } + { + FillStyle* pFillStyle = pThis->addBackgroundFillStyle(); + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pFillStyle->mpFill = pFill; + } + { + FillStyle* pFillStyle = pThis->addBackgroundFillStyle(); + auto pFill = std::make_shared<SolidFill>(); + pFill->maColorDefinition.meType = model::ColorType::Placeholder; + pFillStyle->mpFill = pFill; + } + } }; } // end of namespace svx diff --git a/include/docmodel/theme/Theme.hxx b/include/docmodel/theme/Theme.hxx index 70766a8488ae..9a5c9fe6ed5a 100644 --- a/include/docmodel/theme/Theme.hxx +++ b/include/docmodel/theme/Theme.hxx @@ -37,7 +37,7 @@ struct DOCMODEL_DLLPUBLIC ThemeFont OUString maPanose; sal_Int16 maPitch = 0; sal_Int16 maFamily = 0; - sal_Int32 maCharset = 0; + sal_Int32 maCharset = 1; sal_Int16 getPitchFamily() const { return (maPitch & 0x0F) | (maFamily & 0x0F) << 4; } }; @@ -59,12 +59,29 @@ private: std::vector<ThemeSupplementalFont> maMajorSupplementalFontList; public: - FontScheme() = default; + FontScheme() + : maName("Office") + { + } + FontScheme(OUString const& rName) : maName(rName) { } + static FontScheme getDefault() + { + FontScheme aDefault; + aDefault.maMinorLatin.maTypeface = "Arial"; + aDefault.maMinorAsian.maTypeface = "DejaVu Sans"; + aDefault.maMinorComplex.maTypeface = "DejaVu Sans"; + + aDefault.maMajorLatin.maTypeface = "Arial"; + aDefault.maMajorAsian.maTypeface = "DejaVu Sans"; + aDefault.maMajorComplex.maTypeface = "DejaVu Sans"; + return aDefault; + } + const OUString& getName() const { return maName; } ThemeFont const& getMinorLatin() const { return maMinorLatin; } @@ -143,7 +160,7 @@ private: OUString maName; std::unique_ptr<model::ColorSet> mpColorSet; - FontScheme maFontScheme; + FontScheme maFontScheme = FontScheme::getDefault(); FormatScheme maFormatScheme; public: diff --git a/include/oox/export/ThemeExport.hxx b/include/oox/export/ThemeExport.hxx index 1889709ab352..8e35b80ca09a 100644 --- a/include/oox/export/ThemeExport.hxx +++ b/include/oox/export/ThemeExport.hxx @@ -17,6 +17,7 @@ namespace model { class Theme; class FontScheme; +class FormatScheme; } namespace oox @@ -35,7 +36,8 @@ private: static bool writeColorSet(sax_fastparser::FSHelperPtr pFS, model::Theme const& rTheme); static bool writeFontScheme(sax_fastparser::FSHelperPtr pFS, model::FontScheme const& rFontScheme); - static bool writeFormatScheme(sax_fastparser::FSHelperPtr pFS); + static bool writeFormatScheme(sax_fastparser::FSHelperPtr pFS, + model::FormatScheme const& rFormatScheme); }; } // end namespace oox diff --git a/oox/source/export/ThemeExport.cxx b/oox/source/export/ThemeExport.cxx index 3abc2cb1adb6..b198aae62fe2 100644 --- a/oox/source/export/ThemeExport.cxx +++ b/oox/source/export/ThemeExport.cxx @@ -14,6 +14,7 @@ #include <oox/token/tokens.hxx> #include <oox/export/utils.hxx> #include <docmodel/theme/Theme.hxx> +#include <docmodel/theme/FormatScheme.hxx> #include <sax/fshelper.hxx> #include <sax/fastattribs.hxx> #include <unordered_map> @@ -49,8 +50,9 @@ void ThemeExport::write(OUString const& rPath, model::Theme const& rTheme) writeFontScheme(pFS, rFontScheme); pFS->endElementNS(XML_a, XML_fontScheme); + model::FormatScheme const& rFormatScheme = rTheme.getFormatScheme(); pFS->startElementNS(XML_a, XML_fmtScheme); - writeFormatScheme(pFS); + writeFormatScheme(pFS, rFormatScheme); pFS->endElementNS(XML_a, XML_fmtScheme); pFS->endElementNS(XML_a, XML_themeElements); @@ -64,8 +66,14 @@ namespace void fillAttrList(rtl::Reference<sax_fastparser::FastAttributeList> const& pAttrList, model::ThemeFont const& rThemeFont) { + if (rThemeFont.maTypeface.isEmpty()) + return; + pAttrList->add(XML_typeface, rThemeFont.maTypeface); - pAttrList->add(XML_panose, rThemeFont.maPanose); + + if (!rThemeFont.maPanose.isEmpty()) + pAttrList->add(XML_panose, rThemeFont.maPanose); + pAttrList->add(XML_pitchFamily, OString::number(rThemeFont.getPitchFamily())); pAttrList->add(XML_charset, OString::number(rThemeFont.maCharset)); } @@ -118,105 +126,714 @@ bool ThemeExport::writeFontScheme(sax_fastparser::FSHelperPtr pFS, return true; } -bool ThemeExport::writeFormatScheme(sax_fastparser::FSHelperPtr pFS) +namespace { - // Format Scheme: 3 or more per list but only 3 will be used currently - pFS->startElementNS(XML_a, XML_fillStyleLst); +void writeColorTransformations(sax_fastparser::FSHelperPtr pFS, + std::vector<model::Transformation> const& rTransformations) +{ + static std::unordered_map<model::TransformationType, sal_Int32> constTransformationTypeTokenMap + = { + { model::TransformationType::Tint, XML_tint }, + { model::TransformationType::Shade, XML_shade }, + { model::TransformationType::LumMod, XML_lumMod }, + { model::TransformationType::LumOff, XML_lumOff }, + }; + + for (model::Transformation const& rTransformation : rTransformations) { - pFS->startElementNS(XML_a, XML_solidFill); - pFS->singleElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->endElementNS(XML_a, XML_solidFill); + auto iterator = constTransformationTypeTokenMap.find(rTransformation.meType); + if (iterator != constTransformationTypeTokenMap.end()) + { + sal_Int32 nToken = iterator->second; + pFS->singleElementNS(XML_a, nToken, XML_val, + OString::number(rTransformation.mnValue * 10)); + } + } +} - pFS->startElementNS(XML_a, XML_solidFill); - pFS->singleElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->endElementNS(XML_a, XML_solidFill); +void writeColorRGB(sax_fastparser::FSHelperPtr pFS, model::ColorDefinition const& rColorDefinition) +{ + auto aColor = rColorDefinition.getRGBColor(); + pFS->startElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(sal_Int32(aColor))); + pFS->endElementNS(XML_a, XML_srgbClr); +} - pFS->startElementNS(XML_a, XML_solidFill); - pFS->singleElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->endElementNS(XML_a, XML_solidFill); +void writeColorCRGB(sax_fastparser::FSHelperPtr pFS, model::ColorDefinition const& rColorDefinition) +{ + pFS->startElementNS(XML_a, XML_scrgbClr, XML_r, OString::number(rColorDefinition.mnComponent1), + XML_g, OString::number(rColorDefinition.mnComponent2), XML_b, + OString::number(rColorDefinition.mnComponent3)); + writeColorTransformations(pFS, rColorDefinition.maTransformations); + pFS->endElementNS(XML_a, XML_scrgbClr); +} + +void writeColorHSL(sax_fastparser::FSHelperPtr pFS, model::ColorDefinition const& rColorDefinition) +{ + pFS->startElementNS(XML_a, XML_hslClr, XML_hue, OString::number(rColorDefinition.mnComponent1), + XML_sat, OString::number(rColorDefinition.mnComponent2), XML_lum, + OString::number(rColorDefinition.mnComponent3)); + writeColorTransformations(pFS, rColorDefinition.maTransformations); + pFS->endElementNS(XML_a, XML_hslClr); +} + +void writeColorScheme(sax_fastparser::FSHelperPtr pFS, + model::ColorDefinition const& rColorDefinition) +{ + static std::unordered_map<model::ThemeColorType, const char*> constThemeColorTypeTokenMap + = { { model::ThemeColorType::Dark1, "dk1" }, + { model::ThemeColorType::Light1, "lt1" }, + { model::ThemeColorType::Dark2, "dk2" }, + { model::ThemeColorType::Light2, "lt2" }, + { model::ThemeColorType::Accent1, "accent1" }, + { model::ThemeColorType::Accent2, "accent2" }, + { model::ThemeColorType::Accent3, "accent3" }, + { model::ThemeColorType::Accent4, "accent4" }, + { model::ThemeColorType::Accent5, "accent5" }, + { model::ThemeColorType::Accent6, "accent6" }, + { model::ThemeColorType::Hyperlink, "hlink" }, + { model::ThemeColorType::FollowedHyperlink, "folHlink" } }; + auto iterator = constThemeColorTypeTokenMap.find(rColorDefinition.meSchemeType); + if (iterator != constThemeColorTypeTokenMap.end()) + { + const char* sValue = iterator->second; + pFS->startElementNS(XML_a, XML_schemeClr, XML_val, sValue); + writeColorTransformations(pFS, rColorDefinition.maTransformations); + pFS->endElementNS(XML_a, XML_schemeClr); } - pFS->endElementNS(XML_a, XML_fillStyleLst); +} - pFS->startElementNS(XML_a, XML_lnStyleLst); +void writeColorSystem(sax_fastparser::FSHelperPtr pFS, + model::ColorDefinition const& rColorDefinition) +{ + static std::unordered_map<model::SystemColorType, const char*> constThemeColorTypeTokenMap = { + { model::SystemColorType::DarkShadow3D, "3dDkShadow" }, + { model::SystemColorType::Light3D, "3dLight" }, + { model::SystemColorType::ActiveBorder, "activeBorder" }, + { model::SystemColorType::ActiveCaption, "activeCaption" }, + { model::SystemColorType::AppWorkspace, "appWorkspace" }, + { model::SystemColorType::Background, "background" }, + { model::SystemColorType::ButtonFace, "btnFace" }, + { model::SystemColorType::ButtonHighlight, "btnHighlight" }, + { model::SystemColorType::ButtonShadow, "btnShadow" }, + { model::SystemColorType::ButtonText, "btnText" }, + { model::SystemColorType::CaptionText, "captionText" }, + { model::SystemColorType::GradientActiveCaption, "gradientActiveCaption" }, + { model::SystemColorType::GradientInactiveCaption, "gradientInactiveCaption" }, + { model::SystemColorType::GrayText, "grayText" }, + { model::SystemColorType::Highlight, "highlight" }, + { model::SystemColorType::HighlightText, "highlightText" }, + { model::SystemColorType::HotLight, "hotLight" }, + { model::SystemColorType::InactiveBorder, "inactiveBorder" }, + { model::SystemColorType::InactiveCaption, "inactiveCaption" }, + { model::SystemColorType::InactiveCaptionText, "inactiveCaptionText" }, + { model::SystemColorType::InfoBack, "infoBk" }, + { model::SystemColorType::InfoText, "infoText" }, + { model::SystemColorType::Menu, "menu" }, + { model::SystemColorType::MenuBar, "menuBar" }, + { model::SystemColorType::MenuHighlight, "menuHighlight" }, + { model::SystemColorType::MenuText, "menuText" }, + { model::SystemColorType::ScrollBar, "scrollBar" }, + { model::SystemColorType::Window, "window" }, + { model::SystemColorType::WindowFrame, "windowFrame" }, + { model::SystemColorType::WindowText, "windowText" }, + }; + auto iterator = constThemeColorTypeTokenMap.find(rColorDefinition.meSystemColorType); + if (iterator != constThemeColorTypeTokenMap.end()) { - pFS->startElementNS(XML_a, XML_ln, XML_w, "6350", XML_cap, "flat", XML_cmpd, "sng", - XML_algn, "ctr"); - { - pFS->startElementNS(XML_a, XML_solidFill); - pFS->startElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->singleElementNS(XML_a, XML_shade, XML_val, "95000"); - pFS->endElementNS(XML_a, XML_schemeClr); - pFS->endElementNS(XML_a, XML_solidFill); + const char* sValue = iterator->second; + pFS->startElementNS(XML_a, XML_sysClr, XML_val, sValue); + //XML_lastClr + writeColorTransformations(pFS, rColorDefinition.maTransformations); + pFS->endElementNS(XML_a, XML_schemeClr); + } +} + +void writeColorPlaceholder(sax_fastparser::FSHelperPtr pFS, + model::ColorDefinition const& rColorDefinition) +{ + pFS->startElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); + writeColorTransformations(pFS, rColorDefinition.maTransformations); + pFS->endElementNS(XML_a, XML_schemeClr); +} + +void writeColorDefinition(sax_fastparser::FSHelperPtr pFS, + model::ColorDefinition const& rColorDefinition) +{ + switch (rColorDefinition.meType) + { + case model::ColorType::Unused: + break; + case model::ColorType::RGB: + writeColorRGB(pFS, rColorDefinition); + break; + case model::ColorType::CRGB: + writeColorCRGB(pFS, rColorDefinition); + break; + case model::ColorType::HSL: + writeColorHSL(pFS, rColorDefinition); + break; + case model::ColorType::Scheme: + writeColorScheme(pFS, rColorDefinition); + break; + case model::ColorType::Palette: + break; + case model::ColorType::System: + writeColorSystem(pFS, rColorDefinition); + break; + case model::ColorType::Placeholder: + writeColorPlaceholder(pFS, rColorDefinition); + break; + } +} + +void writeSolidFill(sax_fastparser::FSHelperPtr pFS, model::SolidFill const& rSolidFill) +{ + pFS->startElementNS(XML_a, XML_solidFill); + writeColorDefinition(pFS, rSolidFill.maColorDefinition); + pFS->endElementNS(XML_a, XML_solidFill); +} + +void writeRelativeRectangle(sax_fastparser::FSHelperPtr pFS, sal_Int32 nToken, + model::RelativeRectangle const& rRelativeRectangle) +{ + pFS->singleElementNS(XML_a, nToken, XML_l, OString::number(rRelativeRectangle.mnLeft), XML_t, + OString::number(rRelativeRectangle.mnTop), XML_r, + OString::number(rRelativeRectangle.mnRight), XML_b, + OString::number(rRelativeRectangle.mnBottom)); +} + +void writeGradientFill(sax_fastparser::FSHelperPtr pFS, model::GradientFill const& rGradientFill) +{ + pFS->startElementNS(XML_a, XML_gradFill); + pFS->startElementNS(XML_a, XML_gsLst); + for (auto const& rStop : rGradientFill.maGradientStops) + { + pFS->startElementNS(XML_a, XML_gs, XML_pos, + OString::number(sal_Int32(rStop.mfPosition * 100000.0))); + writeColorDefinition(pFS, rStop.maColor); + pFS->endElementNS(XML_a, XML_gs); + } + pFS->endElementNS(XML_a, XML_gsLst); - pFS->singleElementNS(XML_a, XML_prstDash, XML_val, "solid"); + if (rGradientFill.meGradientType == model::GradientType::Linear) + { + pFS->singleElementNS(XML_a, XML_lin, XML_ang, + OString::number(rGradientFill.maLinearGradient.mnAngle), XML_scaled, + rGradientFill.maLinearGradient.mbScaled ? "1" : "0"); + } + else + { + OString sPathType; + switch (rGradientFill.meGradientType) + { + case model::GradientType::Circle: + sPathType = "circle"; + break; + case model::GradientType::Rectangle: + sPathType = "rect"; + break; + case model::GradientType::Shape: + sPathType = "shape"; + break; + default: + break; + } - pFS->singleElementNS(XML_a, XML_miter); + if (!sPathType.isEmpty()) + { + pFS->startElementNS(XML_a, XML_path, XML_path, sPathType); + writeRelativeRectangle(pFS, XML_fillToRect, rGradientFill.maFillToRectangle); + pFS->endElementNS(XML_a, XML_path); } - pFS->endElementNS(XML_a, XML_ln); } + writeRelativeRectangle(pFS, XML_tileRect, rGradientFill.maTileRectangle); + pFS->endElementNS(XML_a, XML_gradFill); +} + +void writePatternFill(sax_fastparser::FSHelperPtr pFS, model::PatternFill const& rPatternFill) +{ + OString sPresetType; + switch (rPatternFill.mePatternPreset) + { + case model::PatternPreset::Percent_5: + sPresetType = "pct5"; + break; + case model::PatternPreset::Percent_10: + sPresetType = "pct10"; + break; + case model::PatternPreset::Percent_20: + sPresetType = "pct20"; + break; + case model::PatternPreset::Percent_25: + sPresetType = "pct25"; + break; + case model::PatternPreset::Percent_30: + sPresetType = "pct30"; + break; + case model::PatternPreset::Percent_40: + sPresetType = "pct40"; + break; + case model::PatternPreset::Percent_50: + sPresetType = "pct50"; + break; + case model::PatternPreset::Percent_60: + sPresetType = "pct60"; + break; + case model::PatternPreset::Percent_70: + sPresetType = "pct70"; + break; + case model::PatternPreset::Percent_75: + sPresetType = "pct75"; + break; + case model::PatternPreset::Percent_80: + sPresetType = "pct80"; + break; + case model::PatternPreset::Percent_90: + sPresetType = "pct90"; + break; + case model::PatternPreset::Horizontal: + sPresetType = "horz"; + break; + case model::PatternPreset::Vertical: + sPresetType = "vert"; + break; + case model::PatternPreset::LightHorizontal: + sPresetType = "ltHorz"; + break; + case model::PatternPreset::LightVertical: + sPresetType = "ltVert"; + break; + case model::PatternPreset::DarkHorizontal: + sPresetType = "dkHorz"; + break; + case model::PatternPreset::DarkVertical: + sPresetType = "dkVert"; + break; + case model::PatternPreset::NarrowHorizontal: + sPresetType = "narHorz"; + break; + case model::PatternPreset::NarrowVertical: + sPresetType = "narVert"; + break; + case model::PatternPreset::DashedHorizontal: + sPresetType = "dashHorz"; + break; + case model::PatternPreset::DashedVertical: + sPresetType = "dashVert"; + break; + case model::PatternPreset::Cross: + sPresetType = "cross"; + break; + case model::PatternPreset::DownwardDiagonal: + sPresetType = "dnDiag"; + break; + case model::PatternPreset::UpwardDiagonal: + sPresetType = "upDiag"; + break; + case model::PatternPreset::LightDownwardDiagonal: + sPresetType = "ltDnDiag"; + break; + case model::PatternPreset::LightUpwardDiagonal: + sPresetType = "ltUpDiag"; + break; + case model::PatternPreset::DarkDownwardDiagonal: + sPresetType = "dkDnDiag"; + break; + case model::PatternPreset::DarkUpwardDiagonal: + sPresetType = "dkUpDiag"; + break; + case model::PatternPreset::WideDownwardDiagonal: + sPresetType = "wdDnDiag"; + break; + case model::PatternPreset::WideUpwardDiagonal: + sPresetType = "wdUpDiag"; + break; + case model::PatternPreset::DashedDownwardDiagonal: + sPresetType = "dashDnDiag"; + break; + case model::PatternPreset::DashedUpwardDiagonal: + sPresetType = "dashUpDiag"; + break; + case model::PatternPreset::DiagonalCross: + sPresetType = "diagCross"; + break; + case model::PatternPreset::SmallCheckerBoard: + sPresetType = "smCheck"; + break; + case model::PatternPreset::LargeCheckerBoard: + sPresetType = "lgCheck"; + break; + case model::PatternPreset::SmallGrid: + sPresetType = "smGrid"; + break; + case model::PatternPreset::LargeGrid: + sPresetType = "lgGrid"; + break; + case model::PatternPreset::DottedGrid: + sPresetType = "dotGrid"; + break; + case model::PatternPreset::SmallConfetti: + sPresetType = "smConfetti"; + break; + case model::PatternPreset::LargeConfetti: + sPresetType = "lgConfetti"; + break; + case model::PatternPreset::HorizontalBrick: + sPresetType = "horzBrick"; + break; + case model::PatternPreset::DiagonalBrick: + sPresetType = "diagBrick"; + break; + case model::PatternPreset::SolidDiamond: + sPresetType = "solidDmnd"; + break; + case model::PatternPreset::OpenDiamond: + sPresetType = "openDmnd"; + break; + case model::PatternPreset::DottedDiamond: + sPresetType = "dotDmnd"; + break; + case model::PatternPreset::Plaid: + sPresetType = "plaid"; + break; + case model::PatternPreset::Sphere: + sPresetType = "sphere"; + break; + case model::PatternPreset::Weave: + sPresetType = "weave"; + break; + case model::PatternPreset::Divot: + sPresetType = "divot"; + break; + case model::PatternPreset::Shingle: + sPresetType = "shingle"; + break; + case model::PatternPreset::Wave: + sPresetType = "wave"; + break; + case model::PatternPreset::Trellis: + sPresetType = "trellis"; + break; + case model::PatternPreset::ZigZag: + sPresetType = "zigZag"; + break; + default: + break; + } + + if (!sPresetType.isEmpty()) + { + pFS->startElementNS(XML_a, XML_pattFill, XML_prst, sPresetType); + + pFS->startElementNS(XML_a, XML_fgClr); + writeColorDefinition(pFS, rPatternFill.maForegroundColor); + pFS->endElementNS(XML_a, XML_fgClr); + + pFS->startElementNS(XML_a, XML_bgClr); + writeColorDefinition(pFS, rPatternFill.maBackgroundColor); + pFS->endElementNS(XML_a, XML_bgClr); + + pFS->endElementNS(XML_a, XML_pattFill); + } +} + +OString convertFlipMode(model::FlipMode eFlipMode) +{ + switch (eFlipMode) + { + case model::FlipMode::X: + return "x"; + case model::FlipMode::Y: + return "y"; + case model::FlipMode::XY: + return "xy"; + case model::FlipMode::None: + return "none"; + } + return "none"; +} + +OString convertRectangleAlignment(model::RectangleAlignment eFlipMode) +{ + switch (eFlipMode) + { + case model::RectangleAlignment::TopLeft: + return "tl"; + case model::RectangleAlignment::Top: + return "t"; + case model::RectangleAlignment::TopRight: + return "tr"; + case model::RectangleAlignment::Left: + return "l"; + case model::RectangleAlignment::Center: + return "ctr"; + case model::RectangleAlignment::Right: + return "r"; + case model::RectangleAlignment::BottomLeft: + return "bl"; + case model::RectangleAlignment::Bottom: + return "b"; + case model::RectangleAlignment::BottomRight: + return "br"; + case model::RectangleAlignment::Unset: + break; + } + return {}; +} + +void writeBlip(sax_fastparser::FSHelperPtr pFS, model::BlipFill const& /*rBlipFill*/) +{ + // TODO - reuse WriteXGraphicBlip + pFS->startElementNS(XML_a, XML_blip); + pFS->endElementNS(XML_a, XML_blip); +} + +void writeBlipFill(sax_fastparser::FSHelperPtr pFS, model::BlipFill const& rBlipFill) +{ + pFS->startElementNS(XML_a, XML_blipFill, XML_rotWithShape, + rBlipFill.mbRotateWithShape ? "1" : "0" + /*XML_dpi*/); + + writeBlip(pFS, rBlipFill); + + writeRelativeRectangle(pFS, XML_srcRect, rBlipFill.maClipRectangle); + + if (rBlipFill.meMode == model::BitmapMode::Tile) + { + OString aFlipMode = convertFlipMode(rBlipFill.meTileFlipMode); + OString aAlignment = convertRectangleAlignment(rBlipFill.meTileAlignment); + + pFS->startElementNS(XML_a, XML_tile, XML_tx, OString::number(rBlipFill.mnTileOffsetX), + XML_ty, OString::number(rBlipFill.mnTileOffsetY), XML_sx, + OString::number(rBlipFill.mnTileScaleX), XML_sy, + OString::number(rBlipFill.mnTileScaleY), XML_flip, aFlipMode, XML_algn, + aAlignment); + pFS->endElementNS(XML_a, XML_tile); + } + else if (rBlipFill.meMode == model::BitmapMode::Stretch) { - pFS->startElementNS(XML_a, XML_ln, XML_w, "6350", XML_cap, "flat", XML_cmpd, "sng", - XML_algn, "ctr"); + pFS->startElementNS(XML_a, XML_stretch); + writeRelativeRectangle(pFS, XML_fillRect, rBlipFill.maFillRectangle); + pFS->endElementNS(XML_a, XML_stretch); + } + + pFS->endElementNS(XML_a, XML_blipFill); +} + +void writeFillStyle(sax_fastparser::FSHelperPtr pFS, model::FillStyle const& rFillStyle) +{ + switch (rFillStyle.mpFill->meType) + { + case model::FillType::None: + case model::FillType::Solid: { - pFS->startElementNS(XML_a, XML_solidFill); - pFS->startElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->singleElementNS(XML_a, XML_shade, XML_val, "95000"); - pFS->endElementNS(XML_a, XML_schemeClr); - pFS->endElementNS(XML_a, XML_solidFill); + auto* pSolidFill = static_cast<model::SolidFill*>(rFillStyle.mpFill.get()); + writeSolidFill(pFS, *pSolidFill); + } + break; + case model::FillType::Gradient: + { + auto* pGradientFill = static_cast<model::GradientFill*>(rFillStyle.mpFill.get()); + writeGradientFill(pFS, *pGradientFill); + } + break; + case model::FillType::Pattern: + { + auto* pPatternFill = static_cast<model::PatternFill*>(rFillStyle.mpFill.get()); + writePatternFill(pFS, *pPatternFill); + } + break; + case model::FillType::Blip: + { + auto* pBlipFill = static_cast<model::BlipFill*>(rFillStyle.mpFill.get()); + writeBlipFill(pFS, *pBlipFill); + } + break; + } +} + +void writeBackgroundFillStyle(sax_fastparser::FSHelperPtr pFS, model::FillStyle const& rFillStyle) +{ + writeFillStyle(pFS, rFillStyle); +} + +void writeLineStyle(sax_fastparser::FSHelperPtr pFS, model::LineStyle const& rLineStyle) +{ + OString sCap; + switch (rLineStyle.meCapType) + { + case model::CapType::Flat: + sCap = "flat"; + break; + case model::CapType::Round: + sCap = "rnd"; + break; + case model::CapType::Square: + sCap = "sq"; + break; + case model::CapType::Unset: + break; + } - pFS->singleElementNS(XML_a, XML_prstDash, XML_val, "solid"); + OString sPenAlign; + switch (rLineStyle.mePenAlignment) + { + case model::PenAlignmentType::Center: + sPenAlign = "ctr"; + break; + case model::PenAlignmentType::Inset: + sPenAlign = "in"; + break; + case model::PenAlignmentType::Unset: + break; + } - pFS->singleElementNS(XML_a, XML_miter); + OString sCompoundLine; + switch (rLineStyle.meCompoundLineType) + { + case model::CompoundLineType::Single: + sCompoundLine = "sng"; + break; + case model::CompoundLineType::Double: + sCompoundLine = "dbl"; + break; + case model::CompoundLineType::ThickThin_Double: + sCompoundLine = "thickThin"; + break; + case model::CompoundLineType::ThinThick_Double: + sCompoundLine = "thinThick"; + break; + case model::CompoundLineType::Triple: + sCompoundLine = "tri"; + break; + case model::CompoundLineType::Unset: + break; + } + + pFS->startElementNS(XML_a, XML_ln, XML_w, OString::number(rLineStyle.mnWidth), XML_cap, + sax_fastparser::UseIf(sCap, !sCap.isEmpty()), XML_cmpd, + sax_fastparser::UseIf(sCompoundLine, !sCompoundLine.isEmpty()), XML_algn, + sax_fastparser::UseIf(sPenAlign, !sPenAlign.isEmpty())); + + if (rLineStyle.maLineDash.mePresetType != model::PresetDashType::Unset) + { + OString sPresetType; + switch (rLineStyle.maLineDash.mePresetType) + { + case model::PresetDashType::Dot: + sPresetType = "dot"; + break; + case model::PresetDashType::Dash: + sPresetType = "dash"; + break; + case model::PresetDashType::LargeDash: + sPresetType = "lgDash"; + break; + case model::PresetDashType::DashDot: + sPresetType = "dashDot"; + break; + case model::PresetDashType::LargeDashDot: + sPresetType = "lgDashDot"; + break; + case model::PresetDashType::LargeDashDotDot: + sPresetType = "lgDashDotDot"; + break; + case model::PresetDashType::Solid: + sPresetType = "solid"; + break; + case model::PresetDashType::SystemDash: + sPresetType = "sysDash"; + break; + case model::PresetDashType::SystemDot: + sPresetType = "sysDot"; + break; + case model::PresetDashType::SystemDashDot: + sPresetType = "sysDashDot"; + break; + case model::PresetDashType::SystemDashDotDot: + sPresetType = "sysDashDotDot"; + break; + case model::PresetDashType::Unset: + break; } - pFS->endElementNS(XML_a, XML_ln); + pFS->singleElementNS(XML_a, XML_prstDash, XML_val, sPresetType); } + + if (rLineStyle.maLineJoin.meType != model::LineJoinType::Unset) { - pFS->startElementNS(XML_a, XML_ln, XML_w, "6350", XML_cap, "flat", XML_cmpd, "sng", - XML_algn, "ctr"); + switch (rLineStyle.maLineJoin.meType) { - pFS->startElementNS(XML_a, XML_solidFill); - pFS->startElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->singleElementNS(XML_a, XML_shade, XML_val, "95000"); - pFS->endElementNS(XML_a, XML_schemeClr); - pFS->endElementNS(XML_a, XML_solidFill); + case model::LineJoinType::Round: + pFS->singleElementNS(XML_a, XML_round); + break; + case model::LineJoinType::Bevel: + pFS->singleElementNS(XML_a, XML_bevel); + break; + case model::LineJoinType::Miter: + { + sal_Int32 nMiterLimit = rLineStyle.maLineJoin.mnMiterLimit; + pFS->singleElementNS( + XML_a, XML_miter, XML_lim, + sax_fastparser::UseIf(OString::number(nMiterLimit), nMiterLimit > 0)); + } + break; + case model::LineJoinType::Unset: + break; + } + } - pFS->singleElementNS(XML_a, XML_prstDash, XML_val, "solid"); + pFS->endElementNS(XML_a, XML_ln); +} - pFS->singleElementNS(XML_a, XML_miter); - } - pFS->endElementNS(XML_a, XML_ln); +void writeEffectStyle(sax_fastparser::FSHelperPtr pFS, model::EffectStyle const& /*rEffectStyle*/) +{ + pFS->startElementNS(XML_a, XML_effectStyle); + pFS->singleElementNS(XML_a, XML_effectLst); + pFS->endElementNS(XML_a, XML_effectStyle); +} + +} // end anonymous ns + +bool ThemeExport::writeFormatScheme(sax_fastparser::FSHelperPtr pFS, + model::FormatScheme const& rFormatScheme) +{ + // Format Scheme: 3 or more per list but only 3 will be used currently + + // Fill Style List + rFormatScheme.ensureFillStyleList(); + pFS->startElementNS(XML_a, XML_fillStyleLst); + for (auto const& rFillStyle : rFormatScheme.getFillStyleList()) + { + writeFillStyle(pFS, rFillStyle); + } + pFS->endElementNS(XML_a, XML_fillStyleLst); + + // Line Style List + rFormatScheme.ensureLineStyleList(); + pFS->startElementNS(XML_a, XML_lnStyleLst); + for (auto const& rLineStyle : rFormatScheme.getLineStyleList()) + { + writeLineStyle(pFS, rLineStyle); } pFS->endElementNS(XML_a, XML_lnStyleLst); + // Effect Style List + rFormatScheme.ensureEffectStyleList(); pFS->startElementNS(XML_a, XML_effectStyleLst); { - pFS->startElementNS(XML_a, XML_effectStyle); - pFS->singleElementNS(XML_a, XML_effectLst); - pFS->endElementNS(XML_a, XML_effectStyle); - - pFS->startElementNS(XML_a, XML_effectStyle); - pFS->singleElementNS(XML_a, XML_effectLst); - pFS->endElementNS(XML_a, XML_effectStyle); - - pFS->startElementNS(XML_a, XML_effectStyle); - pFS->singleElementNS(XML_a, XML_effectLst); - pFS->endElementNS(XML_a, XML_effectStyle); + for (auto const& rEffectStyle : rFormatScheme.getEffectStyleList()) + { + writeEffectStyle(pFS, rEffectStyle); + } } pFS->endElementNS(XML_a, XML_effectStyleLst); + // Background Fill Style List + rFormatScheme.ensureBackgroundFillStyleList(); pFS->startElementNS(XML_a, XML_bgFillStyleLst); + for (auto const& rFillStyle : rFormatScheme.getBackgroundFillStyleList()) { - pFS->startElementNS(XML_a, XML_solidFill); - pFS->singleElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->endElementNS(XML_a, XML_solidFill); - - pFS->startElementNS(XML_a, XML_solidFill); - pFS->singleElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->endElementNS(XML_a, XML_solidFill); - - pFS->startElementNS(XML_a, XML_solidFill); - pFS->singleElementNS(XML_a, XML_schemeClr, XML_val, "phClr"); - pFS->endElementNS(XML_a, XML_solidFill); + writeBackgroundFillStyle(pFS, rFillStyle); } pFS->endElementNS(XML_a, XML_bgFillStyleLst); diff --git a/sd/qa/filter/eppt/eppt.cxx b/sd/qa/filter/eppt/eppt.cxx index 32d9b330a1dc..f5420a637751 100644 --- a/sd/qa/filter/eppt/eppt.cxx +++ b/sd/qa/filter/eppt/eppt.cxx @@ -12,6 +12,8 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> #include <com/sun/star/drawing/XMasterPageTarget.hpp> +#include <com/sun/star/util/Color.hpp> +#include <com/sun/star/util/XTheme.hpp> #include <test/xmldocptr.hxx> #include <docmodel/uno/UnoTheme.hxx> @@ -56,40 +58,57 @@ CPPUNIT_TEST_FIXTURE(Test, testThemeExport) { // Given a document with a master slide and a theme, lt1 is set to 0x000002: mxComponent = loadFromDesktop("private:factory/simpress"); - uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); - uno::Reference<drawing::XMasterPageTarget> xDrawPage( - xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); - uno::Reference<beans::XPropertySet> xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY); - - auto pTheme = std::make_shared<model::Theme>("mytheme"); - std::unique_ptr<model::ColorSet> pColorSet(new model::ColorSet("mycolorscheme")); - pColorSet->add(model::ThemeColorType::Dark1, 0x1); - pColorSet->add(model::ThemeColorType::Light1, 0x2); - pColorSet->add(model::ThemeColorType::Dark2, 0x3); - pColorSet->add(model::ThemeColorType::Light2, 0x4); - pColorSet->add(model::ThemeColorType::Accent1, 0x5); - pColorSet->add(model::ThemeColorType::Accent2, 0x6); - pColorSet->add(model::ThemeColorType::Accent3, 0x7); - pColorSet->add(model::ThemeColorType::Accent4, 0x8); - pColorSet->add(model::ThemeColorType::Accent5, 0x9); - pColorSet->add(model::ThemeColorType::Accent6, 0xa); - pColorSet->add(model::ThemeColorType::Hyperlink, 0xb); - pColorSet->add(model::ThemeColorType::FollowedHyperlink, 0xc); - pTheme->SetColorSet(std::move(pColorSet)); - - xMasterPage->setPropertyValue("Theme", uno::Any(model::theme::createXTheme(pTheme))); - - // When exporting to PPTX: - save("Impress Office Open XML"); - - // Then verify that this color is not lost: + { + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XMasterPageTarget> xDrawPage( + xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY); + + auto pTheme = std::make_shared<model::Theme>("mytheme"); + std::unique_ptr<model::ColorSet> pColorSet(new model::ColorSet("mycolorscheme")); + pColorSet->add(model::ThemeColorType::Dark1, 0x111111); + pColorSet->add(model::ThemeColorType::Light1, 0x222222); + pColorSet->add(model::ThemeColorType::Dark2, 0x333333); + pColorSet->add(model::ThemeColorType::Light2, 0x444444); + pColorSet->add(model::ThemeColorType::Accent1, 0x555555); + pColorSet->add(model::ThemeColorType::Accent2, 0x666666); + pColorSet->add(model::ThemeColorType::Accent3, 0x777777); + pColorSet->add(model::ThemeColorType::Accent4, 0x888888); + pColorSet->add(model::ThemeColorType::Accent5, 0x999999); + pColorSet->add(model::ThemeColorType::Accent6, 0xaaaaaa); + pColorSet->add(model::ThemeColorType::Hyperlink, 0xbbbbbb); + pColorSet->add(model::ThemeColorType::FollowedHyperlink, 0xcccccc); + pTheme->SetColorSet(std::move(pColorSet)); + + xMasterPage->setPropertyValue("Theme", uno::Any(model::theme::createXTheme(pTheme))); + } + + // Export to PPTX and load again: + saveAndReload("Impress Office Open XML"); + + // Verify that this color is not lost: xmlDocUniquePtr pXmlDoc = parseExport("ppt/theme/theme1.xml"); - assertXPath(pXmlDoc, "//a:clrScheme/a:lt1/a:srgbClr", "val", "000002"); - // Without the fix in place, this test would have failed with: - // - Expected: 1 - // - Actual : 0 - // - XPath '//a:clrScheme/a:lt1/a:srgbClr' number of nodes is incorrect - // i.e. the RGB color was lost on export. + assertXPath(pXmlDoc, "//a:clrScheme/a:lt1/a:srgbClr", "val", + "222222"); // expected color 22-22-22 + + // Check the theme after loading again + { + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XMasterPageTarget> xDrawPage( + xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY); + uno::Reference<util::XTheme> xTheme(xMasterPage->getPropertyValue("Theme"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(true, xTheme.is()); + + auto* pUnoTheme = dynamic_cast<UnoTheme*>(xTheme.get()); + CPPUNIT_ASSERT(pUnoTheme); + auto pTheme = pUnoTheme->getTheme(); + + CPPUNIT_ASSERT_EQUAL(OUString("mytheme"), pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(OUString("mycolorscheme"), pTheme->GetColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(OUString("Office"), pTheme->getFontScheme().getName()); + CPPUNIT_ASSERT_EQUAL(OUString(""), pTheme->getFormatScheme().getName()); + } } CPPUNIT_TEST_FIXTURE(Test, testLoopingFromAnimation) diff --git a/sd/source/filter/eppt/epptooxml.hxx b/sd/source/filter/eppt/epptooxml.hxx index 48c928d60abb..0c7644c72b3d 100644 --- a/sd/source/filter/eppt/epptooxml.hxx +++ b/sd/source/filter/eppt/epptooxml.hxx @@ -90,13 +90,6 @@ private: virtual void ImplWriteNotes( sal_uInt32 nPageNum ) override; virtual void ImplWriteSlideMaster( sal_uInt32 nPageNum, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override; void ImplWritePPTXLayout( sal_Int32 nOffset, sal_uInt32 nMasterNum ); - - /// Export the color set part of a theme. - static bool WriteColorSets(const FSHelperPtr& pFS, model::Theme* pTheme); - - /// Same as WriteColorSets(), but works from a grab-bag. - bool WriteColorSchemes(const FSHelperPtr& pFS, const OUString& rThemePath); - static void WriteDefaultColorSchemes(const FSHelperPtr& pFS); void WriteTheme( sal_Int32 nThemeNum, model::Theme* pTheme ); diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index c0215ecca162..9e207baf1be6 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -56,6 +56,7 @@ #include <comphelper/diagnose_ex.hxx> #include <oox/export/utils.hxx> +#include <oox/export/ThemeExport.hxx> #include <docmodel/theme/Theme.hxx> #include "pptx-animations.hxx" @@ -1938,172 +1939,6 @@ ShapeExport& PowerPointShapeExport::WritePlaceholderReferenceTextBody( return *this; } -#define SYS_COLOR_SCHEMES " <a:dk1>\ - <a:sysClr val=\"windowText\" lastClr=\"000000\"/>\ - </a:dk1>\ - <a:lt1>\ - <a:sysClr val=\"window\" lastClr=\"FFFFFF\"/>\ - </a:lt1>" - -#define MINIMAL_THEME " <a:fontScheme name=\"Office\">\ - <a:majorFont>\ - <a:latin typeface=\"Arial\"/>\ - <a:ea typeface=\"DejaVu Sans\"/>\ - <a:cs typeface=\"DejaVu Sans\"/>\ - </a:majorFont>\ - <a:minorFont>\ - <a:latin typeface=\"Arial\"/>\ - <a:ea typeface=\"DejaVu Sans\"/>\ - <a:cs typeface=\"DejaVu Sans\"/>\ - </a:minorFont>\ - </a:fontScheme>\ - <a:fmtScheme name=\"Office\">\ - <a:fillStyleLst>\ - <a:solidFill>\ - <a:schemeClr val=\"phClr\"/>\ - </a:solidFill>\ - <a:gradFill rotWithShape=\"1\">\ - <a:gsLst>\ - <a:gs pos=\"0\">\ - <a:schemeClr val=\"phClr\">\ - <a:tint val=\"50000\"/>\ - <a:satMod val=\"300000\"/>\ - </a:schemeClr>\ - </a:gs>\ - <a:gs pos=\"35000\">\ - <a:schemeClr val=\"phClr\">\ - <a:tint val=\"37000\"/>\ - <a:satMod val=\"300000\"/>\ - </a:schemeClr>\ - </a:gs>\ - <a:gs pos=\"100000\">\ - <a:schemeClr val=\"phClr\">\ - <a:tint val=\"15000\"/>\ - <a:satMod val=\"350000\"/>\ - </a:schemeClr>\ - </a:gs>\ - </a:gsLst>\ - <a:lin ang=\"16200000\" scaled=\"1\"/>\ - </a:gradFill>\ - <a:gradFill rotWithShape=\"1\">\ - <a:gsLst>\ - <a:gs pos=\"0\">\ - <a:schemeClr val=\"phClr\">\ - <a:shade val=\"51000\"/>\ - <a:satMod val=\"130000\"/>\ - </a:schemeClr>\ - </a:gs>\ - <a:gs pos=\"80000\">\ - <a:schemeClr val=\"phClr\">\ - <a:shade val=\"93000\"/>\ - <a:satMod val=\"130000\"/>\ - </a:schemeClr>\ - </a:gs>\ - <a:gs pos=\"100000\">\ - <a:schemeClr val=\"phClr\">\ - <a:shade val=\"94000\"/>\ - <a:satMod val=\"135000\"/>\ - </a:schemeClr>\ - </a:gs>\ - </a:gsLst>\ - <a:lin ang=\"16200000\" scaled=\"0\"/>\ - </a:gradFill>\ - </a:fillStyleLst>\ - <a:lnStyleLst>\ - <a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\ - <a:solidFill>\ - <a:schemeClr val=\"phClr\">\ - <a:shade val=\"95000\"/>\ - <a:satMod val=\"105000\"/>\ - </a:schemeClr>\ - </a:solidFill>\ - <a:prstDash val=\"solid\"/>\ - <a:miter/>\ - </a:ln>\ - <a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\ - <a:solidFill>\ - <a:schemeClr val=\"phClr\"/>\ - </a:solidFill>\ - <a:prstDash val=\"solid\"/>\ - <a:miter/>\ - </a:ln>\ - <a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\ - <a:solidFill>\ - <a:schemeClr val=\"phClr\"/>\ - </a:solidFill>\ - <a:prstDash val=\"solid\"/>\ - <a:miter/>\ - </a:ln>\ - </a:lnStyleLst>\ - <a:effectStyleLst>\ - <a:effectStyle>\ - <a:effectLst/>\ - </a:effectStyle>\ - <a:effectStyle>\ - <a:effectLst/>\ - </a:effectStyle>\ - <a:effectStyle>\ - <a:effectLst>\ - <a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">\ - <a:srgbClr val=\"000000\">\ - <a:alpha val=\"35000\"/>\ - </a:srgbClr>\ - </a:outerShdw>\ - </a:effectLst>\ - </a:effectStyle>\ - </a:effectStyleLst>\ - <a:bgFillStyleLst>\ - <a:solidFill>\ - <a:schemeClr val=\"phClr\"/>\ - </a:solidFill>\ - <a:gradFill rotWithShape=\"1\">\ - <a:gsLst>\ - <a:gs pos=\"0\">\ - <a:schemeClr val=\"phClr\">\ - <a:tint val=\"40000\"/>\ - <a:satMod val=\"350000\"/>\ - </a:schemeClr>\ - </a:gs>\ - <a:gs pos=\"40000\">\ - <a:schemeClr val=\"phClr\">\ - <a:tint val=\"45000\"/>\ - <a:shade val=\"99000\"/>\ - <a:satMod val=\"350000\"/>\ - </a:schemeClr>\ - </a:gs>\ - <a:gs pos=\"100000\">\ - <a:schemeClr val=\"phClr\">\ - <a:shade val=\"20000\"/>\ - <a:satMod val=\"255000\"/>\ - </a:schemeClr>\ - </a:gs>\ - </a:gsLst>\ - <a:path path=\"circle\">\ - <a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/>\ - </a:path>\ - </a:gradFill>\ - <a:gradFill rotWithShape=\"1\">\ - <a:gsLst>\ - <a:gs pos=\"0\">\ - <a:schemeClr val=\"phClr\">\ - <a:tint val=\"80000\"/>\ - <a:satMod val=\"300000\"/>\ - </a:schemeClr>\ - </a:gs>\ - <a:gs pos=\"100000\">\ - <a:schemeClr val=\"phClr\">\ - <a:shade val=\"30000\"/>\ - <a:satMod val=\"200000\"/>\ - </a:schemeClr>\ - </a:gs>\ - </a:gsLst>\ - <a:path path=\"circle\">\ - <a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/>\ - </a:path>\ - </a:gradFill>\ - </a:bgFillStyleLst>\ - </a:fmtScheme>" - void PowerPointExport::WriteDefaultColorSchemes(const FSHelperPtr& pFS) { for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++) @@ -2155,155 +1990,15 @@ void PowerPointExport::WriteDefaultColorSchemes(const FSHelperPtr& pFS) } } -bool PowerPointExport::WriteColorSets(const FSHelperPtr& pFS, model::Theme* pTheme) -{ - static std::map<PredefinedClrSchemeId, sal_Int32> aPredefinedClrTokens = - { - { dk1, XML_dk1 }, - { lt1, XML_lt1 }, - { dk2, XML_dk2 }, - { lt2, XML_lt2 }, - { accent1, XML_accent1 }, - { accent2, XML_accent2 }, - { accent3, XML_accent3 }, - { accent4, XML_accent4 }, - { accent5, XML_accent5 }, - { accent6, XML_accent6 }, - { hlink, XML_hlink }, - { folHlink, XML_folHlink } - }; - - if (!pTheme) - { - return false; - } - - model::ColorSet* pColorSet = pTheme->GetColorSet(); - if (!pColorSet) - { - return false; - } - - for (int nId = PredefinedClrSchemeId::dk1; nId < PredefinedClrSchemeId::Count; nId++) - { - sal_Int32 nToken = aPredefinedClrTokens[static_cast<PredefinedClrSchemeId>(nId)]; - pFS->startElementNS(XML_a, nToken); - model::ThemeColorType eType = model::convertToThemeColorType(nId); - pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(static_cast<sal_Int32>(pColorSet->getColor(eType)))); - pFS->endElementNS(XML_a, nToken); - } - - return true; -} - -bool PowerPointExport::WriteColorSchemes(const FSHelperPtr& pFS, const OUString& rThemePath) -{ - try - { - uno::Reference<beans::XPropertySet> xDocProps(getModel(), uno::UNO_QUERY); - if (xDocProps.is()) - { - uno::Reference<beans::XPropertySetInfo> xPropsInfo = xDocProps->getPropertySetInfo(); - - static const OUStringLiteral aGrabBagPropName = u"InteropGrabBag"; - if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(aGrabBagPropName)) - { - comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(aGrabBagPropName)); - uno::Sequence<beans::PropertyValue> aCurrentTheme; - - aGrabBag.getValue(rThemePath) >>= aCurrentTheme; - - if (!aCurrentTheme.hasElements()) - return false; - - // Order is important - for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++) - { - OUString sName = PredefinedClrNames[static_cast<PredefinedClrSchemeId>(nId)]; - sal_Int32 nColor = 0; - - for (auto aIt = std::cbegin(aCurrentTheme); aIt != std::cend(aCurrentTheme); aIt++) - { - if (aIt->Name == sName) - { - aIt->Value >>= nColor; - break; - } - } - - OUString sOpenColorScheme ="<a:" + sName + ">"; - pFS->write(sOpenColorScheme); - - pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor)); - - OUString sCloseColorScheme = "</a:" + sName + ">"; - pFS->write(sCloseColorScheme); - } - - // TODO: write complete color schemes & only if successful, protection against partial export - return true; - } - } - } - catch (const uno::Exception&) - { - SAL_WARN("writerfilter", "Failed to save documents grab bag"); - } - - return false; -} - void PowerPointExport::WriteTheme(sal_Int32 nThemeNum, model::Theme* pTheme) { + if (!pTheme) + return; OUString sThemePath = "ppt/theme/theme" + OUString::number(nThemeNum + 1) + ".xml"; - FSHelperPtr pFS = openFragmentStreamWithSerializer(sThemePath, - "application/vnd.openxmlformats-officedocument.theme+xml"); - - OUString aThemeName("Office Theme"); - if (pTheme) - { - aThemeName = pTheme->GetName(); - } - pFS->startElementNS(XML_a, XML_theme, - FSNS(XML_xmlns, XML_a), this->getNamespaceURL(OOX_NS(dml)), - XML_name, aThemeName); - - pFS->startElementNS(XML_a, XML_themeElements); - OUString aColorSchemeName("Office"); - if (pTheme) - { - model::ColorSet* pColorSet = pTheme->GetColorSet(); - if (pColorSet) - { - aColorSchemeName = pColorSet->getName(); - } - } - pFS->startElementNS(XML_a, XML_clrScheme, XML_name, aColorSchemeName); + oox::ThemeExport aThemeExport(this); - if (!WriteColorSets(pFS, pTheme)) - { - pFS->write(SYS_COLOR_SCHEMES); - if (!WriteColorSchemes(pFS, sThemePath)) - { - // if style is not defined, try to use first one - if (!WriteColorSchemes(pFS, "ppt/theme/theme1.xml")) - { - // color schemes are required - use default values - WriteDefaultColorSchemes(pFS); - } - } - } - - pFS->endElementNS(XML_a, XML_clrScheme); - - // export remaining part - pFS->write(MINIMAL_THEME); - - pFS->endElementNS(XML_a, XML_themeElements); - pFS->endElementNS(XML_a, XML_theme); - - pFS->endDocument(); + aThemeExport.write(sThemePath, *pTheme); } bool PowerPointExport::ImplCreateDocument() @@ -2344,6 +2039,7 @@ void PowerPointExport::WriteNotesMaster() openFragmentStreamWithSerializer("ppt/notesMasters/notesMaster1.xml", "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml"); // write theme per master + WriteTheme(mnMasterPages, nullptr); // add implicit relation to the presentation theme diff --git a/svx/source/svdraw/svdpage.cxx b/svx/source/svdraw/svdpage.cxx index 235fc58da508..e685c40c89a5 100644 --- a/svx/source/svdraw/svdpage.cxx +++ b/svx/source/svdraw/svdpage.cxx @@ -1223,9 +1223,9 @@ SdrPageProperties::SdrPageProperties(SdrPage& rSdrPage) maProperties.Put(XFillStyleItem(drawing::FillStyle_NONE)); } - if (rSdrPage.getSdrModelFromSdrPage().IsWriter()) + if (rSdrPage.getSdrModelFromSdrPage().IsWriter() || rSdrPage.IsMasterPage()) { - mpTheme.reset(new model::Theme("Office")); + mpTheme.reset(new model::Theme("Office Theme")); auto const* pColorSet = svx::ColorSets::get().getColorSet(u"LibreOffice"); if (pColorSet) {