Repository.mk | 1 desktop/source/lib/init.cxx | 1 filter/Configuration_filter.mk | 4 filter/Library_flash.mk | 56 filter/Module_filter.mk | 1 filter/UIConfig_filter.mk | 1 filter/qa/unit/data/filter-dialogs-test.txt | 1 filter/source/config/cache/typedetection.cxx | 1 filter/source/config/fragments/filters/draw_flash_Export.xcu | 30 filter/source/config/fragments/filters/impress_flash_Export.xcu | 30 filter/source/config/fragments/types/graphic_SWF.xcu | 29 filter/source/flash/flash.component | 28 filter/source/flash/impswfdialog.cxx | 78 filter/source/flash/impswfdialog.hxx | 53 filter/source/flash/swfdialog.cxx | 159 filter/source/flash/swfdialog.hxx | 74 filter/source/flash/swfexporter.cxx | 729 +++ filter/source/flash/swfexporter.hxx | 148 filter/source/flash/swffilter.cxx | 519 ++ filter/source/flash/swfuno.cxx | 69 filter/source/flash/swfuno.hxx | 73 filter/source/flash/swfwriter.cxx | 401 ++ filter/source/flash/swfwriter.hxx | 421 ++ filter/source/flash/swfwriter1.cxx | 1961 ++++++++++ filter/source/flash/swfwriter2.cxx | 575 ++ filter/uiconfig/ui/impswfdialog.ui | 270 + include/sal/log-areas.dox | 1 include/vcl/bitmapex.hxx | 5 include/vcl/gdimetafiletools.hxx | 4 include/vcl/gradient.hxx | 1 include/vcl/outdev.hxx | 4 scp2/source/graphicfilter/module_graphicfilter.ulf | 6 sfx2/source/dialog/filtergrouping.cxx | 13 solenv/inc/mime.types | 3 sysui/desktop/apparmor/program.soffice.bin | 2 vcl/source/bitmap/BitmapEx.cxx | 61 vcl/source/gdi/gradient.cxx | 31 vcl/source/outdev/text.cxx | 14 38 files changed, 5850 insertions(+), 8 deletions(-)
New commits: commit f358a936a393a453b6fed54b4da33fc5a963ff26 Author: Andras Timar <andras.ti...@collabora.com> AuthorDate: Sun Feb 16 11:18:45 2025 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Feb 16 11:19:03 2025 +0100 enforce UI rules on Flash (SWF) Options dialog python3 bin/ui-rules-enforcer.py filter/uiconfig/ui/impswfdialog.ui Without this fix we see literal gtk-help, gtk-ok and gtk-cancel button labels on Windows. Change-Id: Ic401c97a9d105d2d3a26d71a70320ee5f1d68164 diff --git a/filter/uiconfig/ui/impswfdialog.ui b/filter/uiconfig/ui/impswfdialog.ui index 6617cd7128f2..f9fc0c843619 100644 --- a/filter/uiconfig/ui/impswfdialog.ui +++ b/filter/uiconfig/ui/impswfdialog.ui @@ -32,13 +32,13 @@ <property name="layout_style">end</property> <child> <object class="GtkButton" id="ok"> - <property name="label">gtk-ok</property> + <property name="label" translatable="yes" context="stock">_OK</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="can_default">True</property> <property name="has_default">True</property> <property name="receives_default">True</property> - <property name="use_stock">True</property> + <property name="use-underline">True</property> </object> <packing> <property name="expand">False</property> @@ -48,11 +48,11 @@ </child> <child> <object class="GtkButton" id="cancel"> - <property name="label">gtk-cancel</property> + <property name="label" translatable="yes" context="stock">_Cancel</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="use_stock">True</property> + <property name="use-underline">True</property> </object> <packing> <property name="expand">False</property> @@ -62,11 +62,11 @@ </child> <child> <object class="GtkButton" id="help"> - <property name="label">gtk-help</property> + <property name="label" translatable="yes" context="stock">_Help</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="use_stock">True</property> + <property name="use-underline">True</property> </object> <packing> <property name="expand">False</property> @@ -116,8 +116,8 @@ <property name="valign">center</property> <property name="activates_default">True</property> <property name="xalign">0.5</property> - <property name="input_purpose">digits</property> <property name="adjustment">adjustmentquality</property> + <property name="truncate-multiline">True</property> <property name="numeric">True</property> </object> <packing> @@ -138,7 +138,6 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> - <property name="xalign">0</property> <property name="draw_indicator">True</property> </object> <packing> @@ -158,7 +157,6 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> - <property name="xalign">0</property> <property name="draw_indicator">True</property> </object> <packing> @@ -179,7 +177,6 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> - <property name="xalign">0</property> <property name="draw_indicator">True</property> </object> <packing> @@ -194,7 +191,6 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> - <property name="xalign">0</property> <property name="draw_indicator">True</property> </object> <packing> @@ -209,7 +205,6 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> - <property name="xalign">0</property> <property name="draw_indicator">True</property> </object> <packing> @@ -236,7 +231,6 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> - <property name="xalign">0</property> <property name="draw_indicator">True</property> </object> <packing> @@ -251,7 +245,6 @@ <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="use_underline">True</property> - <property name="xalign">0</property> <property name="draw_indicator">True</property> </object> <packing> commit d9d3f39db539a952772898a86d60402964051cfd Author: Skyler Grey <skyler.g...@collabora.com> AuthorDate: Wed Nov 6 11:50:14 2024 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Feb 16 00:18:57 2025 +0100 fix(swfexport): Fix crash on matrix export Previously, we tried to set row 2 on matrices, which failed on matrices without multiple rows, leading to a crash. This was possibly caused by d0d46e0f506d7fd3578039ed23c9e4235c29ca8f, which migrated to B3DHomMatrix from Matrix3D, however B3DHomMatrix has the following comment (include/basegfx/matrix/b2dhommatrix.hxx): // Since this is a graphics matrix, the last row is always 0 0 1, so we don't bother to store it. It therefore seems likely that we incorrectly migrated this, and didn't notice for a long while (faulty code is not actually used on all documents, so there's a good chance you'll miss it) Co-Authored-By: Caolán McNamara <caolan.mcnam...@collabora.com> Change-Id: Ib4ba1ab6c9245190051bbf99628b3e9b28b9c34c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176146 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/filter/source/flash/swfwriter1.cxx b/filter/source/flash/swfwriter1.cxx index 9fbd9aa472fd..38dc0416c928 100644 --- a/filter/source/flash/swfwriter1.cxx +++ b/filter/source/flash/swfwriter1.cxx @@ -1179,9 +1179,6 @@ bool Writer::Impl_writeFilling(SvtGraphicFill const& rFilling) aMatrix.set(a, b, aTransform.matrix[a * 3 + b]); } } - aMatrix.set(2, 0, 0.0); - aMatrix.set(2, 1, 0.0); - aMatrix.set(2, 2, 1.0); // scale bitmap double XScale = aOldRect.GetWidth() commit 45f0e839d59ed88eba8160264185b01236c47de5 Author: Skyler Grey <skyler.g...@collabora.com> AuthorDate: Tue Oct 1 09:17:49 2024 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Feb 16 00:18:57 2025 +0100 Back out "Drop Macromedia Flash export filter" This backs out commit 63e43c1db9d0d5c52916dc6d2d7cd1d3d9bcae76. In an effort to support exporting to various legacy file formats, we want back SWF export. There are various changes over time from the original SWF support (e.g. changing TempFile to TempFileNamed) or the addition of an extra parameter to gb_Library_set_componentfile, however most of this is relatively straightforward... ...in my opinion it probably *should never* be cherry-picked into master, since as the original dropping of SWF in Ic2c6e95db2f56bcd4eb25abdd0a6748aee9b0e4c was decided on by ESC, so I think it would be "quite rude" to override that and backport it anyway. Therefore, I'm not going to backport it myself. If you would like this to be in master, please cherry-pick it yourself (although do feel free to ask me for review/testing/any other necessary help). Change-Id: I87f2756964a544d1a796b4046ca67b758cba90fd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174596 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/Repository.mk b/Repository.mk index 10c899ac01d3..7d128f773ffe 100644 --- a/Repository.mk +++ b/Repository.mk @@ -291,6 +291,7 @@ $(eval $(call gb_Helper_register_plugins_for_install,OOOLIBS,calc, \ $(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,graphicfilter, \ svgfilter \ + flash \ wpftdraw \ graphicfilter \ )) diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index b2e6a11e303e..66ec59c3686a 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -370,6 +370,7 @@ constexpr ExtensionMap aImpressExtensionMap[] = { "svg", u"impress_svg_Export"_ustr }, { "xhtml", u"XHTML Impress File"_ustr }, { "png", u"impress_png_Export"_ustr }, + { "swf", u"impress_flash_Export"_ustr }, { "bmp", u"impress_bmp_Export"_ustr }, { "gif", u"impress_gif_Export"_ustr }, { "tif", u"impress_tif_Export"_ustr }, diff --git a/filter/Configuration_filter.mk b/filter/Configuration_filter.mk index 42ebab575cd3..17e84036783a 100644 --- a/filter/Configuration_filter.mk +++ b/filter/Configuration_filter.mk @@ -696,6 +696,7 @@ $(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_drawgraphics_typ eps_Encapsulated_PostScript \ gif_Graphics_Interchange \ graphic_HTML \ + graphic_SWF \ jpg_JPEG \ met_OS2_Metafile \ mov_MOV \ @@ -761,6 +762,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_drawgraphics_f draw_emf_Export \ draw_emz_Export \ draw_eps_Export \ + draw_flash_Export \ draw_gif_Export \ draw_html_Export \ draw_jpg_Export \ @@ -781,6 +783,7 @@ $(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_impressgraphics_ eps_Encapsulated_PostScript \ gif_Graphics_Interchange \ graphic_HTML \ + graphic_SWF \ impress_CGM_Computer_Graphics_Metafile \ jpg_JPEG \ met_OS2_Metafile \ @@ -806,6 +809,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_impressgraphic impress_bmp_Export \ impress_emf_Export \ impress_eps_Export \ + impress_flash_Export \ impress_gif_Export \ impress_html_Export \ impress_jpg_Export \ diff --git a/filter/Library_flash.mk b/filter/Library_flash.mk new file mode 100644 index 000000000000..2ad3c5538198 --- /dev/null +++ b/filter/Library_flash.mk @@ -0,0 +1,56 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,flash)) + +$(eval $(call gb_Library_set_componentfile,flash,filter/source/flash/flash,services)) + +$(eval $(call gb_Library_use_sdk_api,flash)) + +$(eval $(call gb_Library_use_libraries,flash,\ + svt \ + vcl \ + utl \ + tl \ + i18nlangtag \ + comphelper \ + basegfx \ + cppuhelper \ + cppu \ + sal \ + salhelper \ +)) + +$(eval $(call gb_Library_use_externals,flash,\ + boost_headers \ + zlib \ +)) + +$(eval $(call gb_Library_add_exception_objects,flash,\ + filter/source/flash/impswfdialog \ + filter/source/flash/swfdialog \ + filter/source/flash/swfexporter \ + filter/source/flash/swffilter \ + filter/source/flash/swfuno \ + filter/source/flash/swfwriter \ + filter/source/flash/swfwriter1 \ + filter/source/flash/swfwriter2 \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Module_filter.mk b/filter/Module_filter.mk index a2cf70628bec..ed8873d8468c 100644 --- a/filter/Module_filter.mk +++ b/filter/Module_filter.mk @@ -23,6 +23,7 @@ $(eval $(call gb_Module_add_targets,filter,\ CustomTarget_svg \ CustomTarget_docbook \ Library_filterconfig \ + Library_flash \ Library_icg \ Library_msfilter \ Library_odfflatxml \ diff --git a/filter/UIConfig_filter.mk b/filter/UIConfig_filter.mk index 7d34128f56e0..34421120a05a 100644 --- a/filter/UIConfig_filter.mk +++ b/filter/UIConfig_filter.mk @@ -10,6 +10,7 @@ $(eval $(call gb_UIConfig_UIConfig,filter)) $(eval $(call gb_UIConfig_add_uifiles,filter,\ + filter/uiconfig/ui/impswfdialog \ filter/uiconfig/ui/pdfgeneralpage \ filter/uiconfig/ui/pdflinkspage \ filter/uiconfig/ui/pdfoptionsdialog \ diff --git a/filter/qa/unit/data/filter-dialogs-test.txt b/filter/qa/unit/data/filter-dialogs-test.txt index 22792ad28e6a..1f1715a194f8 100644 --- a/filter/qa/unit/data/filter-dialogs-test.txt +++ b/filter/qa/unit/data/filter-dialogs-test.txt @@ -44,6 +44,7 @@ filter/ui/pdflinkspage.ui filter/ui/pdfsignpage.ui filter/ui/xmlfiltertabpagegeneral.ui filter/ui/xmlfiltertabpagetransformation.ui +filter/ui/impswfdialog.ui filter/ui/testxmlfilter.ui filter/ui/warnpdfdialog.ui filter/ui/xmlfiltersettings.ui diff --git a/filter/source/config/cache/typedetection.cxx b/filter/source/config/cache/typedetection.cxx index 4fb9ab482571..5589d188fa9a 100644 --- a/filter/source/config/cache/typedetection.cxx +++ b/filter/source/config/cache/typedetection.cxx @@ -284,6 +284,7 @@ int getFlatTypeRank(std::u16string_view rType) // Export only "writer_layout_dump_xml", "writer_indexing_export", + "graphic_SWF", "graphic_HTML", // Internal use only diff --git a/filter/source/config/fragments/filters/draw_flash_Export.xcu b/filter/source/config/fragments/filters/draw_flash_Export.xcu new file mode 100644 index 000000000000..36e094c9bec9 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_flash_Export.xcu @@ -0,0 +1,30 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="draw_flash_Export" oor:op="replace"> + <prop oor:name="Flags"><value>EXPORT ALIEN 3RDPARTYFILTER</value></prop> + <prop oor:name="UIComponent"><value>com.sun.star.Impress.FlashExportDialog</value></prop> + <prop oor:name="FilterService"><value>com.sun.star.comp.Impress.FlashExportFilter</value></prop> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">Macromedia Flash (SWF)</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>graphic_SWF</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.drawing.DrawingDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/filters/impress_flash_Export.xcu b/filter/source/config/fragments/filters/impress_flash_Export.xcu new file mode 100644 index 000000000000..0cb961f7d287 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_flash_Export.xcu @@ -0,0 +1,30 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="impress_flash_Export" oor:op="replace"> + <prop oor:name="Flags"><value>EXPORT ALIEN 3RDPARTYFILTER</value></prop> + <prop oor:name="UIComponent"><value>com.sun.star.Impress.FlashExportDialog</value></prop> + <prop oor:name="FilterService"><value>com.sun.star.comp.Impress.FlashExportFilter</value></prop> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">Macromedia Flash (SWF)</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>graphic_SWF</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.presentation.PresentationDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/types/graphic_SWF.xcu b/filter/source/config/fragments/types/graphic_SWF.xcu new file mode 100644 index 000000000000..66f503d08623 --- /dev/null +++ b/filter/source/config/fragments/types/graphic_SWF.xcu @@ -0,0 +1,29 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="graphic_SWF" oor:op="replace" > + <prop oor:name="DetectService"/> + <prop oor:name="URLPattern"/> + <prop oor:name="Extensions"><value>swf</value></prop> + <prop oor:name="MediaType"/> + <prop oor:name="Preferred"><value>false</value></prop> + <prop oor:name="PreferredFilter"/> + <prop oor:name="UIName"> + <value>Macromedia Flash (SWF)</value> + </prop> + <prop oor:name="ClipboardFormat"/> + </node> diff --git a/filter/source/flash/flash.component b/filter/source/flash/flash.component new file mode 100644 index 000000000000..879466efb301 --- /dev/null +++ b/filter/source/flash/flash.component @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="flash" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.Impress.FlashExportDialog"> + <service name="com.sun.star.Impress.FlashExportDialog"/> + </implementation> + <implementation name="com.sun.star.comp.Impress.FlashExportFilter"> + <service name="com.sun.star.document.ExportFilter"/> + </implementation> +</component> diff --git a/filter/source/flash/impswfdialog.cxx b/filter/source/flash/impswfdialog.cxx new file mode 100644 index 000000000000..5e50c2c4f1b6 --- /dev/null +++ b/filter/source/flash/impswfdialog.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "impswfdialog.hxx" +#include <tools/solar.h> + +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; + +ImpSWFDialog::ImpSWFDialog(weld::Window* pParent, Sequence<PropertyValue>& rFilterData) + : GenericDialogController(pParent, "filter/ui/impswfdialog.ui", "ImpSWFDialog") + , maConfigItem(u"Office.Common/Filter/Flash/Export/", &rFilterData) + , mxNumFldQuality(m_xBuilder->weld_spin_button("quality")) + , mxCheckExportAll(m_xBuilder->weld_check_button("exportall")) + , mxCheckExportBackgrounds(m_xBuilder->weld_check_button("exportbackgrounds")) + , mxCheckExportBackgroundObjects(m_xBuilder->weld_check_button("exportbackgroundobjects")) + , mxCheckExportSlideContents(m_xBuilder->weld_check_button("exportslidecontents")) + , mxCheckExportSound(m_xBuilder->weld_check_button("exportsound")) + , mxCheckExportOLEAsJPEG(m_xBuilder->weld_check_button("exportoleasjpeg")) + , mxCheckExportMultipleFiles(m_xBuilder->weld_check_button("exportmultiplefiles")) +{ + const sal_Int32 nCompressMode = maConfigItem.ReadInt32("CompressMode", 75); + mxNumFldQuality->set_value(nCompressMode); + + mxCheckExportAll->set_active(true); + mxCheckExportSlideContents->set_active(true); + mxCheckExportSound->set_active(true); + + mxCheckExportAll->connect_toggled(LINK(this, ImpSWFDialog, OnToggleCheckbox)); + + mxCheckExportBackgrounds->set_sensitive(false); + mxCheckExportBackgroundObjects->set_sensitive(false); + mxCheckExportSlideContents->set_sensitive(false); +} + +ImpSWFDialog::~ImpSWFDialog() {} + +Sequence<PropertyValue> ImpSWFDialog::GetFilterData() +{ + sal_Int32 nCompressMode = static_cast<sal_Int32>(mxNumFldQuality->get_value()); + maConfigItem.WriteInt32("CompressMode", nCompressMode); + maConfigItem.WriteBool("ExportAll", mxCheckExportAll->get_active()); + maConfigItem.WriteBool("ExportBackgrounds", mxCheckExportBackgrounds->get_active()); + maConfigItem.WriteBool("ExportBackgroundObjects", mxCheckExportBackgroundObjects->get_active()); + maConfigItem.WriteBool("ExportSlideContents", mxCheckExportSlideContents->get_active()); + maConfigItem.WriteBool("ExportSound", mxCheckExportSound->get_active()); + maConfigItem.WriteBool("ExportOLEAsJPEG", mxCheckExportOLEAsJPEG->get_active()); + maConfigItem.WriteBool("ExportMultipleFiles", mxCheckExportMultipleFiles->get_active()); + + Sequence<PropertyValue> aRet(maConfigItem.GetFilterData()); + + return aRet; +} + +IMPL_LINK_NOARG(ImpSWFDialog, OnToggleCheckbox, weld::Toggleable&, void) +{ + mxCheckExportBackgrounds->set_sensitive(!mxCheckExportBackgrounds->get_sensitive()); + mxCheckExportBackgroundObjects->set_sensitive(!mxCheckExportBackgroundObjects->get_sensitive()); + mxCheckExportSlideContents->set_sensitive(!mxCheckExportSlideContents->get_sensitive()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/impswfdialog.hxx b/filter/source/flash/impswfdialog.hxx new file mode 100644 index 000000000000..b48cbaf5d980 --- /dev/null +++ b/filter/source/flash/impswfdialog.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_FILTER_SOURCE_FLASH_IMPSWFDIALOG_HXX +#define INCLUDED_FILTER_SOURCE_FLASH_IMPSWFDIALOG_HXX + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <vcl/FilterConfigItem.hxx> +#include <vcl/weld.hxx> + +class ImpSWFDialog : public weld::GenericDialogController +{ +private: + FilterConfigItem maConfigItem; + + std::unique_ptr<weld::SpinButton> mxNumFldQuality; + std::unique_ptr<weld::CheckButton> mxCheckExportAll; + std::unique_ptr<weld::CheckButton> mxCheckExportBackgrounds; + std::unique_ptr<weld::CheckButton> mxCheckExportBackgroundObjects; + std::unique_ptr<weld::CheckButton> mxCheckExportSlideContents; + std::unique_ptr<weld::CheckButton> mxCheckExportSound; + std::unique_ptr<weld::CheckButton> mxCheckExportOLEAsJPEG; + std::unique_ptr<weld::CheckButton> mxCheckExportMultipleFiles; + + DECL_LINK(OnToggleCheckbox, weld::Toggleable&, void); + +public: + ImpSWFDialog(weld::Window* pParent, css::uno::Sequence<css::beans::PropertyValue>& rFilterData); + virtual ~ImpSWFDialog() override; + + css::uno::Sequence<css::beans::PropertyValue> GetFilterData(); +}; + +#endif // INCLUDED_FILTER_SOURCE_FLASH_IMPSWFDIALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swfdialog.cxx b/filter/source/flash/swfdialog.cxx new file mode 100644 index 000000000000..11518d3f5f35 --- /dev/null +++ b/filter/source/flash/swfdialog.cxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "swfdialog.hxx" +#include "swfuno.hxx" +#include "impswfdialog.hxx" +#include <comphelper/processfactory.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <com/sun/star/view/XRenderable.hpp> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::document; + +#define SERVICE_NAME "com.sun.star.Impress.FlashExportDialog" + +OUString SWFDialog_getImplementationName() { return SERVICE_NAME; } + +Sequence<OUString> SWFDialog_getSupportedServiceNames() +{ + Sequence<OUString> aRet{ SERVICE_NAME }; + return aRet; +} + +Reference<XInterface> SWFDialog_createInstance(const Reference<XMultiServiceFactory>& rSMgr) +{ + return static_cast<cppu::OWeakObject*>(new SWFDialog(comphelper::getComponentContext(rSMgr))); +} + +#undef SERVICE_NAME + +SWFDialog::SWFDialog(const Reference<XComponentContext>& rxContext) + : SWFDialog_Base(rxContext) +{ +} + +SWFDialog::~SWFDialog() {} + +OUString SAL_CALL SWFDialog::getImplementationName() { return SWFDialog_getImplementationName(); } + +Sequence<OUString> SAL_CALL SWFDialog::getSupportedServiceNames() +{ + return SWFDialog_getSupportedServiceNames(); +} + +std::unique_ptr<weld::DialogController> +SWFDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + std::unique_ptr<weld::DialogController> xRet; + + if (mxSrcDoc.is()) + { + /* TODO: From the controller we may get information what page is visible and what shapes + are selected, if we optionally want to limit output to that + Any aSelection; + + try + { + Reference< XController > xController( Reference< XModel >( mxSrcDoc, UNO_QUERY )->getCurrentController() ); + + if( xController.is() ) + { + Reference< XSelectionSupplier > xView( xController, UNO_QUERY ); + + if( xView.is() ) + xView->getSelection() >>= aSelection; + } + } + catch( RuntimeException ) + { + } +*/ + xRet.reset(new ImpSWFDialog(Application::GetFrameWeld(rParent), maFilterData)); + } + + return xRet; +} + +void SWFDialog::executedDialog(sal_Int16 nExecutionResult) +{ + if (nExecutionResult && m_xDialog) + maFilterData = static_cast<ImpSWFDialog*>(m_xDialog.get())->GetFilterData(); + + destroyDialog(); +} + +Reference<XPropertySetInfo> SAL_CALL SWFDialog::getPropertySetInfo() +{ + Reference<XPropertySetInfo> xInfo(createPropertySetInfo(getInfoHelper())); + return xInfo; +} + +::cppu::IPropertyArrayHelper& SWFDialog::getInfoHelper() { return *getArrayHelper(); } + +::cppu::IPropertyArrayHelper* SWFDialog::createArrayHelper() const +{ + Sequence<Property> aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +Sequence<PropertyValue> SAL_CALL SWFDialog::getPropertyValues() +{ + sal_Int32 i, nCount; + + for (i = 0, nCount = maMediaDescriptor.getLength(); i < nCount; i++) + { + if (maMediaDescriptor[i].Name == "FilterData") + break; + } + + if (i == nCount) + maMediaDescriptor.realloc(++nCount); + + auto pMediaDescriptor = maMediaDescriptor.getArray(); + + pMediaDescriptor[i].Name = "FilterData"; + pMediaDescriptor[i].Value <<= maFilterData; + + return maMediaDescriptor; +} + +void SAL_CALL SWFDialog::setPropertyValues(const Sequence<PropertyValue>& rProps) +{ + maMediaDescriptor = rProps; + + for (sal_Int32 i = 0, nCount = maMediaDescriptor.getLength(); i < nCount; i++) + { + if (maMediaDescriptor[i].Name == "FilterData") + { + maMediaDescriptor[i].Value >>= maFilterData; + break; + } + } +} + +void SAL_CALL SWFDialog::setSourceDocument(const Reference<XComponent>& xDoc) { mxSrcDoc = xDoc; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swfdialog.hxx b/filter/source/flash/swfdialog.hxx new file mode 100644 index 000000000000..04bea8cc2f32 --- /dev/null +++ b/filter/source/flash/swfdialog.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_FILTER_SOURCE_FLASH_SWFDIALOG_HXX +#define INCLUDED_FILTER_SOURCE_FLASH_SWFDIALOG_HXX + +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/document/XExporter.hpp> + +#include <comphelper/proparrhlp.hxx> +#include <svtools/genericunodialog.hxx> + +namespace vcl +{ +class Window; +} + +typedef cppu::ImplInheritanceHelper<::svt::OGenericUnoDialog, css::beans::XPropertyAccess, + css::document::XExporter> + SWFDialog_Base; +class SWFDialog final : public ::comphelper::OPropertyArrayUsageHelper<SWFDialog>, + public SWFDialog_Base +{ +private: + css::uno::Sequence<css::beans::PropertyValue> maMediaDescriptor; + css::uno::Sequence<css::beans::PropertyValue> maFilterData; + css::uno::Reference<css::lang::XComponent> mxSrcDoc; + + // OGenericUnoDialog + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + virtual std::unique_ptr<weld::DialogController> + createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + virtual void executedDialog(sal_Int16 nExecutionResult) override; + virtual css::uno::Reference<css::beans::XPropertySetInfo> + SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + // XPropertyAccess + using ::cppu::OPropertySetHelper::getPropertyValues; + using ::cppu::OPropertySetHelper::setPropertyValues; + virtual css::uno::Sequence<css::beans::PropertyValue> SAL_CALL getPropertyValues() override; + virtual void SAL_CALL + setPropertyValues(const css::uno::Sequence<css::beans::PropertyValue>& aProps) override; + + // XExporter + virtual void SAL_CALL + setSourceDocument(const css::uno::Reference<css::lang::XComponent>& xDoc) override; + +public: + explicit SWFDialog(const css::uno::Reference<css::uno::XComponentContext>& rxContext); + virtual ~SWFDialog() override; +}; + +#endif // INCLUDED_FILTER_SOURCE_FLASH_SWFDIALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swfexporter.cxx b/filter/source/flash/swfexporter.cxx new file mode 100644 index 000000000000..6141b2772bd1 --- /dev/null +++ b/filter/source/flash/swfexporter.cxx @@ -0,0 +1,729 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/GraphicExportFilter.hpp> +#include <com/sun/star/drawing/XMasterPageTarget.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/task/XStatusIndicatorFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <vcl/gdimtf.hxx> +#include <unotools/tempfile.hxx> +#include <osl/diagnose.h> +#include <vcl/metaact.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/gdimetafiletools.hxx> +#include <memory> +#include <vcl/filter/SvmWriter.hxx> +#include <vcl/filter/SvmReader.hxx> + +#include "swfexporter.hxx" +#include "swfwriter.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::task; +using namespace ::swf; + +using com::sun::star::io::XOutputStream; +using com::sun::star::beans::PropertyValue; +using com::sun::star::container::XIndexAccess; +using com::sun::star::beans::XPropertySet; +using com::sun::star::lang::XComponent; +using com::sun::star::lang::XServiceInfo; + +PageInfo::PageInfo() + : mnBackgroundID(0) + , mnObjectsID(0) + , mnForegroundID(0) +{ +} + +FlashExporter::FlashExporter(const Reference<XComponentContext>& rxContext, + + // #i56084# variables for selection export + const Reference<XShapes>& rxSelectedShapes, + const Reference<XDrawPage>& rxSelectedDrawPage, + + sal_Int32 nJPEGCompressMode, bool bExportOLEAsJPEG) + : mxContext(rxContext) + // #i56084# variables for selection export + , mxSelectedShapes(rxSelectedShapes) + , mxSelectedDrawPage(rxSelectedDrawPage) + , mbExportSelection(false) + + , mnDocWidth(0) + , mnDocHeight(0) + , mnJPEGcompressMode(nJPEGCompressMode) + , mbExportOLEAsJPEG(bExportOLEAsJPEG) + , mbPresentation(true) + , mnPageNumber(-1) +{ + if (mxSelectedDrawPage.is() && mxSelectedShapes.is() && mxSelectedShapes->getCount()) + { + // #i56084# determine export selection + mbExportSelection = true; + } +} + +FlashExporter::~FlashExporter() { Flush(); } + +void FlashExporter::Flush() +{ + mpWriter.reset(); + maPagesMap.clear(); +} + +const sal_uInt16 cBackgroundDepth = 2; +const sal_uInt16 cBackgroundObjectsDepth = 3; +const sal_uInt16 cPageObjectsDepth = 4; +const sal_uInt16 cWaitButtonDepth = 10; + +bool FlashExporter::exportAll(const Reference<XComponent>& xDoc, + Reference<XOutputStream> const& xOutputStream, + Reference<XStatusIndicator> const& xStatusIndicator) +{ + Reference<XServiceInfo> xDocServInfo(xDoc, UNO_QUERY); + if (xDocServInfo.is()) + mbPresentation + = xDocServInfo->supportsService("com.sun.star.presentation.PresentationDocument"); + + Reference<XDrawPagesSupplier> xDrawPagesSupplier(xDoc, UNO_QUERY); + if (!xDrawPagesSupplier.is()) + return false; + + Reference<XIndexAccess> xDrawPages = xDrawPagesSupplier->getDrawPages(); + if (!xDrawPages.is()) + return false; + + Reference<XDrawPage> xDrawPage; + + // #i56084# set xDrawPage directly when exporting selection + if (mbExportSelection) + { + xDrawPage = mxSelectedDrawPage; + } + else + { + xDrawPages->getByIndex(0) >>= xDrawPage; + } + + Reference<XPropertySet> xProp(xDrawPage, UNO_QUERY); + try + { + xProp->getPropertyValue("Width") >>= mnDocWidth; + xProp->getPropertyValue("Height") >>= mnDocHeight; + + sal_Int32 nOutputWidth = 14400; + sal_Int32 nOutputHeight = (nOutputWidth * mnDocHeight) / mnDocWidth; + mpWriter.reset( + new Writer(nOutputWidth, nOutputHeight, mnDocWidth, mnDocHeight, mnJPEGcompressMode)); + } + catch (const Exception&) + { + OSL_ASSERT(false); + return false; // no writer, no cookies + } + + // #i56084# nPageCount is 1 when exporting selection + const sal_Int32 nPageCount = mbExportSelection ? 1 : xDrawPages->getCount(); + + if (xStatusIndicator.is()) + { + xStatusIndicator->start("Macromedia Flash (SWF)", nPageCount); + } + + for (sal_Int32 nPage = 0; nPage < nPageCount; nPage++) + { + // #i56084# keep PageNumber? We could determine the PageNumber of the single to-be-exported page + // when exporting the selection, but this is only used for swf internal, so no need to do so (AFAIK) + mnPageNumber = nPage + 1; + + if (xStatusIndicator.is()) + xStatusIndicator->setValue(nPage); + + // #i56084# get current xDrawPage when not exporting selection; else already set above + if (!mbExportSelection) + { + xDrawPages->getByIndex(nPage) >>= xDrawPage; + } + + if (!xDrawPage.is()) + continue; + + Reference<XPropertySet> xPropSet(xDrawPage, UNO_QUERY); + if (mbPresentation) + { + bool bVisible = false; + xPropSet->getPropertyValue("Visible") >>= bVisible; + if (!bVisible) + continue; + } + + // #i56084# no background when exporting selection + if (!mbExportSelection) + { + exportBackgrounds(xDrawPage, nPage, false); + exportBackgrounds(xDrawPage, nPage, true); + } + + maPagesMap[nPage].mnForegroundID = mpWriter->startSprite(); + + // #i56084# directly export selection in export selection mode + if (mbExportSelection) + { + exportShapes(mxSelectedShapes, false, false); + } + else + { + exportDrawPageContents(xDrawPage, false, false); + } + + mpWriter->endSprite(); + + // AS: If the background is different than the previous slide, + // we have to remove the old one and place the new one. + if (nPage) + { + if (maPagesMap[nPage].mnBackgroundID != maPagesMap[nPage - 1].mnBackgroundID) + { + mpWriter->removeShape(cBackgroundDepth); + mpWriter->placeShape(maPagesMap[nPage].mnBackgroundID, cBackgroundDepth, 0, 0); + } + + if (maPagesMap[nPage].mnObjectsID != maPagesMap[nPage - 1].mnObjectsID) + { + mpWriter->removeShape(cBackgroundObjectsDepth); + mpWriter->placeShape(maPagesMap[nPage].mnObjectsID, cBackgroundObjectsDepth, 0, 0); + } + + // AS: Remove the Foreground of the previous slide. + mpWriter->removeShape(cPageObjectsDepth); + } + else + { + mpWriter->placeShape(maPagesMap[nPage].mnBackgroundID, cBackgroundDepth, 0, 0); + mpWriter->placeShape(maPagesMap[nPage].mnObjectsID, cBackgroundObjectsDepth, 0, 0); + } + + mpWriter->placeShape(maPagesMap[nPage].mnForegroundID, cPageObjectsDepth, 0, 0); + + mpWriter->waitOnClick(cWaitButtonDepth); + mpWriter->showFrame(); + } + + mpWriter->removeShape(cBackgroundDepth); + mpWriter->removeShape(cBackgroundObjectsDepth); + mpWriter->removeShape(cPageObjectsDepth); + mpWriter->gotoFrame(0); + mpWriter->showFrame(); + + mpWriter->storeTo(xOutputStream); + + return true; +} + +bool FlashExporter::exportSlides(const Reference<XDrawPage>& xDrawPage, + Reference<XOutputStream> const& xOutputStream) +{ + Reference<XPropertySet> xPropSet(xDrawPage, UNO_QUERY); + if (!xDrawPage.is() || !xPropSet.is()) + return false; + + try + { + if (!mpWriter) + { + xPropSet->getPropertyValue("Width") >>= mnDocWidth; + xPropSet->getPropertyValue("Height") >>= mnDocHeight; + + mpWriter.reset(new Writer(14400, 10800, mnDocWidth, mnDocHeight, mnJPEGcompressMode)); + } + + if (mbPresentation) + { + bool bVisible = false; + xPropSet->getPropertyValue("Visible") >>= bVisible; + if (!bVisible) + return false; + } + } + catch (const Exception&) + { + OSL_ASSERT(false); + } + + exportDrawPageContents(xDrawPage, true, false); + + mpWriter->storeTo(xOutputStream); + + return true; +} + +sal_uInt16 FlashExporter::exportBackgrounds(const Reference<XDrawPage>& xDrawPage, + Reference<XOutputStream> const& xOutputStream, + sal_uInt16 nPage, bool bExportObjects) +{ + Reference<XPropertySet> xPropSet(xDrawPage, UNO_QUERY); + if (!xDrawPage.is() || !xPropSet.is()) + return 0; + + if (!mpWriter) + { + xPropSet->getPropertyValue("Width") >>= mnDocWidth; + xPropSet->getPropertyValue("Height") >>= mnDocHeight; + + mpWriter.reset(new Writer(14400, 10800, mnDocWidth, mnDocHeight, mnJPEGcompressMode)); + } + + sal_uInt16 ret = exportBackgrounds(xDrawPage, nPage, bExportObjects); + + if (ret != nPage) + return ret; + + if (bExportObjects) + mpWriter->placeShape(maPagesMap[nPage].mnObjectsID, uInt16_(1), 0, 0); + else + mpWriter->placeShape(maPagesMap[nPage].mnBackgroundID, uInt16_(0), 0, 0); + + mpWriter->storeTo(xOutputStream); + + return nPage; +} + +sal_uInt16 FlashExporter::exportBackgrounds(Reference<XDrawPage> const& xDrawPage, sal_uInt16 nPage, + bool bExportObjects) +{ + Reference<XPropertySet> xPropSet(xDrawPage, UNO_QUERY); + if (!xDrawPage.is() || !xPropSet.is()) + return 0; + + bool bBackgroundVisible = true; + bool bBackgroundObjectsVisible = true; + + if (mbPresentation) + { + xPropSet->getPropertyValue("IsBackgroundVisible") >>= bBackgroundVisible; + xPropSet->getPropertyValue("IsBackgroundObjectsVisible") >>= bBackgroundObjectsVisible; + } + + if (bExportObjects) + { + if (bBackgroundObjectsVisible) + { + Reference<XMasterPageTarget> xMasterPageTarget(xDrawPage, UNO_QUERY); + if (!xMasterPageTarget.is()) + { + maPagesMap[nPage].mnObjectsID = 0xffff; + return 0xffff; + } + Reference<XDrawPage> aTemp = xMasterPageTarget->getMasterPage(); + sal_uInt16 ret = exportMasterPageObjects(nPage, aTemp); + if (ret != nPage) + return ret; + } + else + { + maPagesMap[nPage].mnObjectsID = 0xffff; + return 0xffff; + } + } + else + { + if (bBackgroundVisible) + { + sal_uInt16 ret = exportDrawPageBackground(nPage, xDrawPage); + + if (ret != nPage) + return ret; + } + else + { + maPagesMap[nPage].mnBackgroundID = 0xffff; + return 0xffff; + } + } + + return nPage; +} + +static sal_Int32 nPlaceDepth; +// AS: A Slide can have a private background or use its masterpage's background. +// We use the checksums on the metafiles to tell if backgrounds are the same and +// should be reused. The return value indicates which slide's background to use. +// If the return value != nPage, then there is no background (if == -1) or the +// background has already been exported. +sal_uInt16 FlashExporter::exportDrawPageBackground(sal_uInt16 nPage, + Reference<XDrawPage> const& xPage) +{ + sal_uInt16 rBackgroundID; + + GDIMetaFile aMtfPrivate, aMtfMaster; + Reference<XComponent> xComponent(xPage, UNO_QUERY); + + Reference<XMasterPageTarget> xMasterPageTarget(xPage, UNO_QUERY); + if (!xMasterPageTarget.is()) + return 0xffff; + + Reference<XDrawPage> xMasterPage = xMasterPageTarget->getMasterPage(); + if (!xMasterPage.is()) + return 0xffff; + + Reference<XComponent> xCompMaster(xMasterPage, UNO_QUERY); + + getMetaFile(xCompMaster, aMtfMaster, true); + getMetaFile(xComponent, aMtfPrivate, true); + + BitmapChecksum masterchecksum = SvmWriter::GetChecksum(aMtfMaster); + BitmapChecksum privatechecksum = SvmWriter::GetChecksum(aMtfPrivate); + + // AS: If the slide has its own background + if (privatechecksum) + { + ChecksumCache::iterator it = gPrivateCache.find(privatechecksum); + + // AS: and we've previously encountered this background, just return + // the previous index. + if (gPrivateCache.end() != it) + { + maPagesMap[nPage].mnBackgroundID = maPagesMap[it->second].mnBackgroundID; + return it->second; + } + else + { + // AS: Otherwise, cache this checksum. + gPrivateCache[privatechecksum] = nPage; + + rBackgroundID = mpWriter->defineShape(aMtfPrivate); + + maPagesMap[nPage].mnBackgroundID = rBackgroundID; + return nPage; + } + } + + // AS: Ok, no private background. Use the master page's. + // AS: Have we already exported this master page? + ChecksumCache::iterator it = gMasterCache.find(masterchecksum); + + if (gMasterCache.end() != it) + { + maPagesMap[nPage].mnBackgroundID = maPagesMap[it->second].mnBackgroundID; + + return it->second; // AS: Yes, so don't export it again. + } + + gMasterCache[masterchecksum] = nPage; + + rBackgroundID = mpWriter->defineShape(aMtfMaster); + + maPagesMap[nPage].mnBackgroundID = rBackgroundID; + + return nPage; +} + +sal_uInt16 FlashExporter::exportMasterPageObjects(sal_uInt16 nPage, + Reference<XDrawPage> const& xMasterPage) +{ + BitmapChecksum shapesum = ActionSummer(xMasterPage); + + ChecksumCache::iterator it = gObjectCache.find(shapesum); + + if (gObjectCache.end() != it) + { + maPagesMap[nPage].mnObjectsID = maPagesMap[it->second].mnObjectsID; + + return it->second; // AS: Yes, so don't export it again. + } + + gObjectCache[shapesum] = nPage; + + sal_uInt16 rObjectsID = mpWriter->startSprite(); + exportDrawPageContents(xMasterPage, false, true); + mpWriter->endSprite(); + + maPagesMap[nPage].mnObjectsID = rObjectsID; + + return nPage; +} + +/** export's the definition of the shapes inside this drawing page and adds the + shape infos to the current PageInfo */ +void FlashExporter::exportDrawPageContents(const Reference<XDrawPage>& xPage, bool bStream, + bool bMaster) +{ + exportShapes(xPage, bStream, bMaster); +} + +/** export's the definition of the shapes inside this XShapes container and adds the + shape infos to the current PageInfo */ +void FlashExporter::exportShapes(const Reference<XShapes>& xShapes, bool bStream, bool bMaster) +{ + OSL_ENSURE((xShapes->getCount() <= 0xffff), + "overflow in FlashExporter::exportDrawPageContents()"); + + sal_uInt16 nShapeCount + = static_cast<sal_uInt16>(std::min(xShapes->getCount(), sal_Int32(0xffff))); + sal_uInt16 nShape; + + Reference<XShape> xShape; + + for (nShape = 0; nShape < nShapeCount; nShape++) + { + xShapes->getByIndex(nShape) >>= xShape; + + if (xShape.is()) + { + Reference<XShapes> xShapes2(xShape, UNO_QUERY); + if (xShapes2.is() && xShape->getShapeType() == "com.sun.star.drawing.GroupShape") + // export the contents of group shapes, but we only ever stream at the top + // recursive level anyway, so pass false for streaming. + exportShapes(xShapes2, false, bMaster); + else + exportShape(xShape, bMaster); + } + + if (bStream) + mpWriter->showFrame(); + } +} + +/** export this shape definition and adds it's info to the current PageInfo */ +void FlashExporter::exportShape(const Reference<XShape>& xShape, bool bMaster) +{ + Reference<XPropertySet> xPropSet(xShape, UNO_QUERY); + if (!xPropSet.is()) + return; + + if (mbPresentation) + { + try + { + // skip empty presentation objects + bool bEmpty = false; + xPropSet->getPropertyValue("IsEmptyPresentationObject") >>= bEmpty; + if (bEmpty) + return; + + // don't export presentation placeholders on masterpage + // they can be non empty when user edits the default texts + if (bMaster) + { + OUString aShapeType(xShape->getShapeType()); + if (aShapeType == "com.sun.star.presentation.TitleTextShape" + || aShapeType == "com.sun.star.presentation.OutlinerShape" + || aShapeType == "com.sun.star.presentation.HeaderShape" + || aShapeType == "com.sun.star.presentation.FooterShape" + || aShapeType == "com.sun.star.presentation.SlideNumberShape" + || aShapeType == "com.sun.star.presentation.DateTimeShape") + return; + } + } + catch (const Exception&) + { + // TODO: If we are exporting a draw, this property is not available + } + } + + try + { + css::awt::Rectangle aBoundRect; + xPropSet->getPropertyValue("BoundRect") >>= aBoundRect; + + std::unique_ptr<ShapeInfo> pShapeInfo(new ShapeInfo()); + pShapeInfo->mnX = aBoundRect.X; + pShapeInfo->mnY = aBoundRect.Y; + pShapeInfo->mnWidth = aBoundRect.Width; + pShapeInfo->mnHeight = aBoundRect.Height; + + GDIMetaFile aMtf; + Reference<XComponent> xComponent(xShape, UNO_QUERY); + + bool bIsOleObject = xShape->getShapeType() == "com.sun.star.presentation.OLE2Shape" + || xShape->getShapeType() == "com.sun.star.drawing.OLE2Shape"; + + getMetaFile(xComponent, aMtf); + + // AS: If it's an OLE object, then export a JPEG if the user requested. + // In this case, we use the bounding rect info generated in the first getMetaFile + // call, and then clear the metafile and add a BMP action. This may be turned into + // a JPEG, depending on what gives the best compression. + if (bIsOleObject && mbExportOLEAsJPEG) + getMetaFile(xComponent, aMtf, false, true); + + sal_uInt16 nID; + BitmapChecksum checksum = SvmWriter::GetChecksum(aMtf); + + ChecksumCache::iterator it = gMetafileCache.find(checksum); + + if (gMetafileCache.end() != it) + nID = it->second; + else + { + nID = mpWriter->defineShape(aMtf); + gMetafileCache[checksum] = nID; + } + + if (!nID) + return; + + pShapeInfo->mnID = nID; + + // pPageInfo->addShape( pShapeInfo ); + + mpWriter->placeShape(pShapeInfo->mnID, uInt16_(nPlaceDepth++), pShapeInfo->mnX, + pShapeInfo->mnY); + } + catch (const Exception&) + { + OSL_ASSERT(false); + } +} + +bool FlashExporter::getMetaFile(Reference<XComponent> const& xComponent, GDIMetaFile& rMtf, + bool bOnlyBackground /* = false */, + bool bExportAsJPEG /* = false */) +{ + if (!mxGraphicExporter.is()) + mxGraphicExporter = GraphicExportFilter::create(mxContext); + + utl::TempFileNamed aFile; + aFile.EnableKillingFile(); + + Sequence<PropertyValue> aFilterData(bExportAsJPEG ? 3 : 2); + + auto pFilterData = aFilterData.getArray(); + + pFilterData[0].Name = "Version"; + pFilterData[0].Value <<= sal_Int32(6000); + pFilterData[1].Name = "PageNumber"; + pFilterData[1].Value <<= mnPageNumber; + + if (bExportAsJPEG) + { + pFilterData[2].Name = "Translucent"; + pFilterData[2].Value <<= true; + } + + Sequence<PropertyValue> aDescriptor(bOnlyBackground ? 4 : 3); + + auto pDescriptor = aDescriptor.getArray(); + + pDescriptor[0].Name = "FilterName"; + + // AS: If we've been asked to export as an image, then use the BMP filter. + // Otherwise, use SVM. This is useful for things that don't convert well as + // metafiles, like the occasional OLE object. + pDescriptor[0].Value <<= bExportAsJPEG ? OUString("PNG") : OUString("SVM"); + + pDescriptor[1].Name = "URL"; + pDescriptor[1].Value <<= aFile.GetURL(); + pDescriptor[2].Name = "FilterData"; + pDescriptor[2].Value <<= aFilterData; + if (bOnlyBackground) + { + pDescriptor[3].Name = "ExportOnlyBackground"; + pDescriptor[3].Value <<= bOnlyBackground; + } + mxGraphicExporter->setSourceDocument(xComponent); + mxGraphicExporter->filter(aDescriptor); + + if (bExportAsJPEG) + { + Graphic aGraphic; + GraphicFilter aFilter; + + aFilter.ImportGraphic(aGraphic, aFile.GetURL(), *aFile.GetStream(StreamMode::READ)); + BitmapEx rBitmapEx(aGraphic.GetBitmapEx().GetBitmap(), Color(255, 255, 255)); + + tools::Rectangle clipRect; + for (size_t i = 0, nCount = rMtf.GetActionSize(); i < nCount; i++) + { + const MetaAction* pAction = rMtf.GetAction(i); + if (pAction->GetType() == MetaActionType::ISECTRECTCLIPREGION) + { + const MetaISectRectClipRegionAction* pA + = static_cast<const MetaISectRectClipRegionAction*>(pAction); + clipRect = pA->GetRect(); + break; + } + } + MetaBmpExScaleAction* pmetaAct + = new MetaBmpExScaleAction(Point(clipRect.Left(), clipRect.Top()), + Size(clipRect.GetWidth(), clipRect.GetHeight()), rBitmapEx); + + rMtf.Clear(); + rMtf.AddAction(pmetaAct); + } + else + { + SvmReader aReader(*aFile.GetStream(StreamMode::READ)); + aReader.Read(rMtf); + + if (usesClipActions(rMtf)) + { + // #i121267# It is necessary to prepare the metafile since the export does *not* support + // clip regions. This tooling method clips the geometry content of the metafile internally + // against its own clip regions, so that the export is safe to ignore clip regions + clipMetafileContentAgainstOwnRegions(rMtf); + } + } + + return rMtf.GetActionSize() != 0; +} + +BitmapChecksum FlashExporter::ActionSummer(Reference<XShape> const& xShape) +{ + Reference<XShapes> xShapes(xShape, UNO_QUERY); + + if (xShapes.is()) + { + return ActionSummer(xShapes); + } + else + { + Reference<XComponent> xComponentShape(xShape, UNO_QUERY); + + GDIMetaFile aMtf; + getMetaFile(xComponentShape, aMtf); + + return SvmWriter::GetChecksum(aMtf); + } +} + +BitmapChecksum FlashExporter::ActionSummer(Reference<XShapes> const& xShapes) +{ + sal_uInt32 nShapeCount = xShapes->getCount(); + BitmapChecksum shapecount = 0; + + Reference<XShape> xShape2; + + for (sal_uInt32 nShape = 0; nShape < nShapeCount; nShape++) + { + xShapes->getByIndex(nShape) >>= xShape2; + + shapecount += ActionSummer(xShape2); + } + + return shapecount; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swfexporter.hxx b/filter/source/flash/swfexporter.hxx new file mode 100644 index 000000000000..ffe17fbb8c76 --- /dev/null +++ b/filter/source/flash/swfexporter.hxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_FILTER_SOURCE_FLASH_SWFEXPORTER_HXX +#define INCLUDED_FILTER_SOURCE_FLASH_SWFEXPORTER_HXX + +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/drawing/XGraphicExportFilter.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <vcl/checksum.hxx> + +#include <map> +#include <memory> + +typedef ::std::map<BitmapChecksum, sal_uInt16> ChecksumCache; + +class GDIMetaFile; + +namespace swf +{ +class Writer; + +class ShapeInfo +{ +public: + sal_uInt16 mnID; // the character id for the sprite definition of this shape + + sal_Int32 mnX; + sal_Int32 mnY; + + sal_Int32 mnWidth; + sal_Int32 mnHeight; + + ShapeInfo() + : mnID(0) + , mnX(0) + , mnY(0) + , mnWidth(0) + , mnHeight(0) + { + } +}; + +struct PageInfo +{ + sal_uInt16 mnBackgroundID; + sal_uInt16 mnObjectsID; + sal_uInt16 mnForegroundID; + + PageInfo(); +}; + +class FlashExporter +{ +public: + FlashExporter(const css::uno::Reference<css::uno::XComponentContext>& rxContext, + + // #i56084# variables for selection export + const css::uno::Reference<css::drawing::XShapes>& rxSelectedShapes, + const css::uno::Reference<css::drawing::XDrawPage>& rxSelectedDrawPage, + + sal_Int32 nJPEGCompressMode, bool bExportOLEAsJPEG); + ~FlashExporter(); + + void Flush(); + + bool exportAll(const css::uno::Reference<css::lang::XComponent>& xDoc, + css::uno::Reference<css::io::XOutputStream> const& xOutputStream, + css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator); + bool exportSlides(const css::uno::Reference<css::drawing::XDrawPage>& xDrawPage, + css::uno::Reference<css::io::XOutputStream> const& xOutputStream); + sal_uInt16 exportBackgrounds(const css::uno::Reference<css::drawing::XDrawPage>& xDrawPage, + css::uno::Reference<css::io::XOutputStream> const& xOutputStream, + sal_uInt16 nPage, bool bExportObjects); + sal_uInt16 exportBackgrounds(css::uno::Reference<css::drawing::XDrawPage> const& xDrawPage, + sal_uInt16 nPage, bool bExportObjects); + + ChecksumCache gMasterCache; + ChecksumCache gPrivateCache; + ChecksumCache gObjectCache; + ChecksumCache gMetafileCache; + +private: + css::uno::Reference<css::uno::XComponentContext> mxContext; + + // #i56084# variables for selection export + const css::uno::Reference<css::drawing::XShapes> mxSelectedShapes; + const css::uno::Reference<css::drawing::XDrawPage> mxSelectedDrawPage; + bool mbExportSelection; + + css::uno::Reference<css::drawing::XGraphicExportFilter> mxGraphicExporter; + + ::std::map<sal_uInt32, PageInfo> maPagesMap; + + sal_uInt16 exportDrawPageBackground(sal_uInt16 nPage, + css::uno::Reference<css::drawing::XDrawPage> const& xPage); + sal_uInt16 + exportMasterPageObjects(sal_uInt16 nPage, + css::uno::Reference<css::drawing::XDrawPage> const& xMasterPage); + + void exportDrawPageContents(const css::uno::Reference<css::drawing::XDrawPage>& xPage, + bool bStream, bool bMaster); + void exportShapes(const css::uno::Reference<css::drawing::XShapes>& xShapes, bool bStream, + bool bMaster); + void exportShape(const css::uno::Reference<css::drawing::XShape>& xShape, bool bMaster); + + BitmapChecksum ActionSummer(css::uno::Reference<css::drawing::XShape> const& xShape); + BitmapChecksum ActionSummer(css::uno::Reference<css::drawing::XShapes> const& xShapes); + + bool getMetaFile(css::uno::Reference<css::lang::XComponent> const& xComponent, + GDIMetaFile& rMtf, bool bOnlyBackground = false, bool bExportAsJPEG = false); + + std::unique_ptr<Writer> mpWriter; + + sal_Int32 mnDocWidth; + sal_Int32 mnDocHeight; + + sal_Int32 mnJPEGcompressMode; + + bool mbExportOLEAsJPEG; + + bool mbPresentation; + + sal_Int32 mnPageNumber; +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swffilter.cxx b/filter/source/flash/swffilter.cxx new file mode 100644 index 000000000000..54fd7b58e9ed --- /dev/null +++ b/filter/source/flash/swffilter.cxx @@ -0,0 +1,519 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawView.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/task/XStatusIndicatorFactory.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/XOutputStream.hpp> + +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/processfactory.hxx> +#include <osl/diagnose.h> +#include <osl/file.hxx> + +#include "swfexporter.hxx" +#include "swfuno.hxx" + +#include <string.h> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::view; + +using ::com::sun::star::lang::XComponent; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::io::XOutputStream; +using ::com::sun::star::container::XIndexAccess; + +namespace swf +{ +namespace +{ +class OslOutputStreamWrapper : public ::cppu::WeakImplHelper<css::io::XOutputStream> +{ + osl::File maFile; + +public: + explicit OslOutputStreamWrapper(const OUString& rFileName) + : maFile(rFileName) + { + osl_removeFile(rFileName.pData); + (void)maFile.open(osl_File_OpenFlag_Create | osl_File_OpenFlag_Write); + } + + // css::io::XOutputStream + virtual void SAL_CALL writeBytes(const css::uno::Sequence<sal_Int8>& aData) override; + virtual void SAL_CALL flush() override; + virtual void SAL_CALL closeOutput() override; +}; +} + +void SAL_CALL OslOutputStreamWrapper::writeBytes(const css::uno::Sequence<sal_Int8>& aData) +{ + sal_uInt64 uBytesToWrite = aData.getLength(); + sal_uInt64 uBytesWritten = 0; + + sal_Int8 const* pBuffer = aData.getConstArray(); + + while (uBytesToWrite) + { + osl::File::RC eRC = maFile.write(pBuffer, uBytesToWrite, uBytesWritten); + + switch (eRC) + { + case osl::File::E_INVAL: // the format of the parameters was not valid + case osl::File::E_FBIG: // File too large + + case osl::File::E_AGAIN: // Operation would block + case osl::File::E_BADF: // Bad file + case osl::File::E_FAULT: // Bad address + case osl::File::E_INTR: // function call was interrupted + case osl::File::E_IO: // I/O error + case osl::File::E_NOLCK: // No record locks available + case osl::File::E_NOLINK: // Link has been severed + case osl::File::E_NOSPC: // No space left on device + case osl::File::E_NXIO: // No such device or address + throw css::io::IOException(); // TODO: Better error handling + default: + break; + } + + uBytesToWrite -= uBytesWritten; + pBuffer += uBytesWritten; + } +} + +void SAL_CALL OslOutputStreamWrapper::flush() {} + +void SAL_CALL OslOutputStreamWrapper::closeOutput() +{ + osl::File::RC eRC = maFile.close(); + + switch (eRC) + { + case osl::File::E_INVAL: // the format of the parameters was not valid + + case osl::File::E_BADF: // Bad file + case osl::File::E_INTR: // function call was interrupted + case osl::File::E_NOLINK: // Link has been severed + case osl::File::E_NOSPC: // No space left on device + case osl::File::E_IO: // I/O error + throw css::io::IOException(); // TODO: Better error handling + default: + break; + } +} + +namespace +{ +class FlashExportFilter + : public cppu::WeakImplHelper<css::document::XFilter, css::document::XExporter, + css::lang::XInitialization, css::lang::XServiceInfo> +{ + Reference<XComponent> mxDoc; + Reference<XComponentContext> mxContext; + Reference<XStatusIndicator> mxStatusIndicator; + + // #i56084# variables for selection export + Reference<XShapes> mxSelectedShapes; + Reference<XDrawPage> mxSelectedDrawPage; + bool mbExportSelection; + +public: + explicit FlashExportFilter(const Reference<XComponentContext>& rxContext); + + // XFilter + virtual sal_Bool SAL_CALL filter(const Sequence<PropertyValue>& aDescriptor) override; + + void ExportAsMultipleFiles(const Sequence<PropertyValue>& aDescriptor); + void ExportAsSingleFile(const Sequence<PropertyValue>& aDescriptor); + + virtual void SAL_CALL cancel() override; + + // XExporter + virtual void SAL_CALL setSourceDocument(const Reference<XComponent>& xDoc) override; + + // XInitialization + virtual void SAL_CALL initialize(const Sequence<Any>& aArguments) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override; +}; +} + +FlashExportFilter::FlashExportFilter(const Reference<XComponentContext>& rxContext) + : mxDoc() + , mxContext(rxContext) + , mxStatusIndicator() + , mxSelectedShapes() + , mxSelectedDrawPage() + , mbExportSelection(false) +{ +} + +static OUString exportBackground(FlashExporter& aFlashExporter, + const Reference<XDrawPage>& xDrawPage, + const std::u16string_view& sPath, sal_uInt32 nPage, + const char* suffix) +{ + OUString filename + = "slide" + OUString::number(nPage + 1) + OUString::createFromAscii(suffix) + ".swf"; + OUString fullpath = OUString::Concat(sPath) + "/" + filename; + + // AS: If suffix is "o" then the last parameter is true (for exporting objects). + sal_uInt16 nCached + = aFlashExporter.exportBackgrounds(xDrawPage, new OslOutputStreamWrapper(fullpath), + sal::static_int_cast<sal_uInt16>(nPage), *suffix == 'o'); + aFlashExporter.Flush(); + + if (nCached != nPage) + { + osl_removeFile(fullpath.pData); + if (0xffff == nCached) + return "NULL"; + else + return "slide" + OUString::number(nCached + 1) + OUString::createFromAscii(suffix) + + ".swf"; + } + + return filename; +} + +template <typename TYPE> +static TYPE findPropertyValue(const Sequence<PropertyValue>& aPropertySequence, const char* name, + TYPE def) +{ + TYPE temp = TYPE(); + + sal_Int32 nLength = aPropertySequence.getLength(); + const PropertyValue* pValue = aPropertySequence.getConstArray(); + + for (sal_Int32 i = 0; i < nLength; i++) + { + if (pValue[i].Name.equalsAsciiL(name, strlen(name))) + { + pValue[i].Value >>= temp; + return temp; + } + } + + return def; +} + +sal_Bool SAL_CALL +FlashExportFilter::filter(const css::uno::Sequence<css::beans::PropertyValue>& aDescriptor) +{ + mxStatusIndicator = findPropertyValue<Reference<XStatusIndicator>>( + aDescriptor, "StatusIndicator", mxStatusIndicator); + + Sequence<PropertyValue> aFilterData; + aFilterData + = findPropertyValue<Sequence<PropertyValue>>(aDescriptor, "FilterData", aFilterData); + + // #i56084# check if selection shall be exported only; if yes, get the selected page and the selection itself + if (findPropertyValue<bool>(aDescriptor, "SelectionOnly", false)) + { + Reference<XDesktop2> xDesktop(Desktop::create(mxContext)); + + if (xDesktop.is()) + { + Reference<XFrame> xFrame(xDesktop->getCurrentFrame()); + + if (xFrame.is()) + { + Reference<XController> xController(xFrame->getController()); + + if (xController.is()) + { + Reference<XDrawView> xDrawView(xController, UNO_QUERY); + + if (xDrawView.is()) + { + mxSelectedDrawPage = xDrawView->getCurrentPage(); + } + + if (mxSelectedDrawPage.is()) + { + Reference<XSelectionSupplier> xSelection(xController, UNO_QUERY); + + if (xSelection.is()) + { + xSelection->getSelection() >>= mxSelectedShapes; + } + } + } + } + } + } + + if (mxSelectedDrawPage.is() && mxSelectedShapes.is() && mxSelectedShapes->getCount()) + { + // #i56084# to export selection we need the selected page and the selected shapes. + // There must be shapes selected, else fallback to regular export (export all) + mbExportSelection = true; + } + + // #i56084# no multiple files (suppress) when selection since selection can only export a single page + if (!mbExportSelection && findPropertyValue<bool>(aFilterData, "ExportMultipleFiles", false)) + { + ExportAsMultipleFiles(aDescriptor); + } + else + { + ExportAsSingleFile(aDescriptor); + } + + if (mxStatusIndicator.is()) + mxStatusIndicator->end(); + + return true; +} + +// AS: When exporting as multiple files, each background, object layer, and slide gets its own +// file. Additionally, a file called BackgroundConfig.txt is generated, indicating which +// background and objects (if any) go with each slide. The files are named slideNb.swf, +// slideNo.swf, and slideNp.swf, where N is the slide number, and b=background, o=objects, and +// p=slide contents. Note that under normal circumstances, there will be very few b and o files. + +// AS: HACK! Right now, I create a directory as a sibling to the swf file selected in the Export +// dialog. This directory is called presentation.sxi-swf-files. The name of the swf file selected +// in the Export dialog has no impact on this. All files created are placed in this directory. +void FlashExportFilter::ExportAsMultipleFiles(const Sequence<PropertyValue>& aDescriptor) +{ + Reference<XDrawPagesSupplier> xDrawPagesSupplier(mxDoc, UNO_QUERY); + if (!xDrawPagesSupplier.is()) + return; + + Reference<XIndexAccess> xDrawPages = xDrawPagesSupplier->getDrawPages(); + if (!xDrawPages.is()) + return; + + Reference<XDesktop2> rDesktop = Desktop::create(mxContext); + + Reference<XStorable> xStorable(rDesktop->getCurrentComponent(), UNO_QUERY); + if (!xStorable.is()) + return; + + Reference<XDrawPage> xDrawPage; + + Reference<XFrame> rFrame = rDesktop->getCurrentFrame(); + Reference<XDrawView> rDrawView(rFrame->getController(), UNO_QUERY); + + Reference<XDrawPage> rCurrentPage = rDrawView->getCurrentPage(); + + Sequence<PropertyValue> aFilterData; + + aFilterData + = findPropertyValue<Sequence<PropertyValue>>(aDescriptor, "FilterData", aFilterData); + + //AS: Do a bunch of path mangling to figure out where to put the files. + + OUString sOriginalPath = findPropertyValue<OUString>(aDescriptor, "URL", OUString()); + + // AS: sPath is the parent directory, where everything else exists (like the sxi, + // the -swf-files folder, the -audio files, etc. + sal_Int32 lastslash = sOriginalPath.lastIndexOf('/'); + OUString sPath(sOriginalPath.copy(0, lastslash)); + + OUString sPresentation(xStorable->getLocation()); + + lastslash = sPresentation.lastIndexOf('/') + 1; + sal_Int32 lastdot = sPresentation.lastIndexOf('.'); + + // AS: The name of the presentation, without 3 character extension. + OUString sPresentationName; + if (lastdot < 0) // fdo#71309 in case file has no name + sPresentationName = sPresentation.copy(lastslash); + else + sPresentationName = sPresentation.copy(lastslash, lastdot - lastslash); + + OUString fullpath, swfdirpath, backgroundfilename, objectsfilename; + + swfdirpath = sPath + "/" + sPresentationName + ".sxi-swf-files"; + + osl_createDirectory(swfdirpath.pData); + + fullpath = swfdirpath + "/backgroundconfig.txt"; + + oslFileHandle aBackgroundConfig(nullptr); + + // AS: Only export the background config if we're exporting all of the pages, otherwise we'll + // screw it up. + bool bExportAll = findPropertyValue<bool>(aFilterData, "ExportAll", true); + if (bExportAll) + { + osl_removeFile(fullpath.pData); + osl_openFile(fullpath.pData, &aBackgroundConfig, + osl_File_OpenFlag_Create | osl_File_OpenFlag_Write); + + sal_uInt64 bytesWritten; + osl_writeFile(aBackgroundConfig, "slides=", strlen("slides="), &bytesWritten); + } + + // TODO: check for errors + + FlashExporter aFlashExporter(mxContext, mxSelectedShapes, mxSelectedDrawPage, + findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75), + findPropertyValue<bool>(aFilterData, "ExportOLEAsJPEG", false)); + + const sal_Int32 nPageCount = xDrawPages->getCount(); + if (mxStatusIndicator.is()) + mxStatusIndicator->start("Saving :", nPageCount); + + for (sal_Int32 nPage = 0; nPage < nPageCount; nPage++) + { + if (mxStatusIndicator.is()) + mxStatusIndicator->setValue(nPage); + xDrawPages->getByIndex(nPage) >>= xDrawPage; + + // AS: If we're only exporting the current page, then skip the rest. + if (!bExportAll && xDrawPage != rCurrentPage) + continue; + + // AS: Export the background, the background objects, and then the slide contents. + if (bExportAll || findPropertyValue<bool>(aFilterData, "ExportBackgrounds", true)) + { + backgroundfilename + = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "b"); + } + + if (bExportAll || findPropertyValue<bool>(aFilterData, "ExportBackgroundObjects", true)) + { + objectsfilename = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "o"); + } + + if (bExportAll || findPropertyValue<bool>(aFilterData, "ExportSlideContents", true)) + { + fullpath = swfdirpath + "/slide" + OUString::number(nPage + 1) + "p.swf"; + + bool ret = aFlashExporter.exportSlides(xDrawPage, new OslOutputStreamWrapper(fullpath)); + aFlashExporter.Flush(); + + if (!ret) + osl_removeFile(fullpath.pData); + } + + // AS: Write out to the background config what backgrounds and objects this + // slide used. + if (bExportAll) + { + OUString temp = backgroundfilename + "|" + objectsfilename; + OString ASCIItemp(temp.getStr(), temp.getLength(), RTL_TEXTENCODING_ASCII_US); + + sal_uInt64 bytesWritten; + osl_writeFile(aBackgroundConfig, ASCIItemp.getStr(), ASCIItemp.getLength(), + &bytesWritten); + + if (nPage < nPageCount - 1) + osl_writeFile(aBackgroundConfig, "|", 1, &bytesWritten); + } + } + + if (bExportAll) + osl_closeFile(aBackgroundConfig); +} + +void FlashExportFilter::ExportAsSingleFile(const Sequence<PropertyValue>& aDescriptor) +{ + Reference<XOutputStream> xOutputStream + = findPropertyValue<Reference<XOutputStream>>(aDescriptor, "OutputStream", nullptr); + Sequence<PropertyValue> aFilterData; + + if (!xOutputStream.is()) + { + OSL_ASSERT(false); + return; + } + + FlashExporter aFlashExporter(mxContext, mxSelectedShapes, mxSelectedDrawPage, + findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75), + findPropertyValue<bool>(aFilterData, "ExportOLEAsJPEG", false)); + + aFlashExporter.exportAll(mxDoc, xOutputStream, mxStatusIndicator); +} + +void SAL_CALL FlashExportFilter::cancel() {} + +// XExporter +void SAL_CALL +FlashExportFilter::setSourceDocument(const css::uno::Reference<css::lang::XComponent>& xDoc) +{ + mxDoc = xDoc; +} + +// XInitialization +void SAL_CALL +FlashExportFilter::initialize(const css::uno::Sequence<css::uno::Any>& /* aArguments */) +{ +} + +OUString FlashExportFilter_getImplementationName() +{ + return "com.sun.star.comp.Impress.FlashExportFilter"; +} + +Sequence<OUString> FlashExportFilter_getSupportedServiceNames() +{ + Sequence<OUString> aRet{ "com.sun.star.document.ExportFilter" }; + return aRet; +} + +Reference<XInterface> FlashExportFilter_createInstance(const Reference<XMultiServiceFactory>& rSMgr) +{ + return static_cast<cppu::OWeakObject*>( + new FlashExportFilter(comphelper::getComponentContext(rSMgr))); +} + +// XServiceInfo +OUString SAL_CALL FlashExportFilter::getImplementationName() +{ + return FlashExportFilter_getImplementationName(); +} + +sal_Bool SAL_CALL FlashExportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL FlashExportFilter::getSupportedServiceNames() +{ + return FlashExportFilter_getSupportedServiceNames(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swfuno.cxx b/filter/source/flash/swfuno.cxx new file mode 100644 index 000000000000..70532b38469f --- /dev/null +++ b/filter/source/flash/swfuno.cxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +#include "swfuno.hxx" + +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; + +using namespace ::swf; + +extern "C" { +SAL_DLLPUBLIC_EXPORT void* flash_component_getFactory(const char* pImplName, void* pServiceManager, + void* /* pRegistryKey */) +{ + void* pRet = nullptr; + + if (pServiceManager) + { + Reference<XSingleServiceFactory> xFactory; + + OUString implName = OUString::createFromAscii(pImplName); + if (implName == FlashExportFilter_getImplementationName()) + { + xFactory = createSingleFactory(static_cast<XMultiServiceFactory*>(pServiceManager), + OUString::createFromAscii(pImplName), + FlashExportFilter_createInstance, + FlashExportFilter_getSupportedServiceNames()); + } + else if (implName == SWFDialog_getImplementationName()) + { + xFactory = createSingleFactory(static_cast<XMultiServiceFactory*>(pServiceManager), + OUString::createFromAscii(pImplName), + SWFDialog_createInstance, + SWFDialog_getSupportedServiceNames()); + } + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swfuno.hxx b/filter/source/flash/swfuno.hxx new file mode 100644 index 000000000000..0db437675445 --- /dev/null +++ b/filter/source/flash/swfuno.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_FILTER_SOURCE_FLASH_SWFUNO_HXX +#define INCLUDED_FILTER_SOURCE_FLASH_SWFUNO_HXX + +#include <sal/config.h> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <rtl/ustring.hxx> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace lang +{ +class XMultiSerivceFactory; +} +namespace uno +{ +class XInterface; +} +} +} +} + +namespace swf +{ +/// @throws css::uno::RuntimeException +OUString FlashExportFilter_getImplementationName(); + +/// @throws css::uno::RuntimeException +css::uno::Sequence<OUString> FlashExportFilter_getSupportedServiceNames(); + +/// @throws css::uno::Exception +css::uno::Reference<css::uno::XInterface> +FlashExportFilter_createInstance(css::uno::Reference<css::lang::XMultiServiceFactory> const& rSMgr); +} + +/// @throws css::uno::RuntimeException +OUString SWFDialog_getImplementationName(); + +/// @throws css::uno::RuntimeException +css::uno::Sequence<OUString> SWFDialog_getSupportedServiceNames(); + +/// @throws css::uno::Exception +css::uno::Reference<css::uno::XInterface> +SWFDialog_createInstance(css::uno::Reference<css::lang::XMultiServiceFactory> const& rSMgr); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/flash/swfwriter.cxx b/filter/source/flash/swfwriter.cxx new file mode 100644 index 000000000000..81edf16a2f89 --- /dev/null +++ b/filter/source/flash/swfwriter.cxx @@ -0,0 +1,401 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "swfwriter.hxx" +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <tools/debug.hxx> + +using namespace ::swf; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; + +static MapMode aTWIPSMode(MapUnit::MapTwip); +static MapMode a100thmmMode(MapUnit::Map100thMM); + +static sal_Int32 map100thmm(sal_Int32 n100thMM) +{ + Point aPoint(n100thMM, n100thMM); + sal_Int32 nX = OutputDevice::LogicToLogic(aPoint, a100thmmMode, aTWIPSMode).X(); + return nX; +} + +Writer::Writer(sal_Int32 nTWIPWidthOutput, sal_Int32 nTWIPHeightOutput, sal_Int32 nDocWidth, + sal_Int32 nDocHeight, sal_Int32 nJPEGcompressMode) + : mnDocWidth(map100thmm(nDocWidth)) + , mnDocHeight(map100thmm(nDocHeight)) + , mnDocXScale(static_cast<double>(nTWIPWidthOutput) / mnDocWidth) + , mnDocYScale(static_cast<double>(nTWIPHeightOutput) / mnDocHeight) + , mpClipPolyPolygon(nullptr) + , mnNextId(1) + , mnFrames(0) + , mnGlobalTransparency(0) + , mnJPEGCompressMode(nJPEGcompressMode) +{ + mpVDev->EnableOutput(false); + + maMovieTempFile.EnableKillingFile(); + maFontsTempFile.EnableKillingFile(); + + mpMovieStream = maMovieTempFile.GetStream(StreamMode::WRITE | StreamMode::TRUNC); + mpFontsStream = maFontsTempFile.GetStream(StreamMode::WRITE | StreamMode::TRUNC); + + // define an invisible button with the size of a page + tools::Rectangle aRect(0, 0, static_cast<long>(mnDocWidth * mnDocXScale), + static_cast<long>(mnDocHeight * mnDocYScale)); + tools::Polygon aPoly(aRect); + FillStyle aFill(COL_WHITE); + sal_uInt16 nWhiteBackgroundShapeId = defineShape(aPoly, aFill); + + ::basegfx::B2DHomMatrix m; // #i73264# + mnPageButtonId = createID(); + startTag(TAG_DEFINEBUTTON); + mpTag->addUI16(mnPageButtonId); // character id for button + + // button records + mpTag->addUI8(0x08); // only hit state + mpTag->addUI16(nWhiteBackgroundShapeId); // shape id of background rectangle + mpTag->addUI16(0); // depth for button DANGER! + mpTag->addMatrix(m); // identity matrix + mpTag->addUI8(0); // empty color transform + + // mpTag->addUI8( 0 ); // end of button records + + // action records + mpTag->addUI8(0x06); // ActionPlay + mpTag->addUI8(0); // end of action records + + endTag(); + + // place a shape that clips shapes depth 2-3 to document boundaries + // placeShape( mnWhiteBackgroundShapeId, 1, 0, 0, 4 ); +} + +Writer::~Writer() { mpVDev.disposeAndClear(); } + +static void ImplCopySvStreamToXOutputStream(SvStream& rIn, Reference<XOutputStream> const& xOut) +{ + sal_uInt32 nBufferSize = 64 * 1024; + + sal_uInt32 nSize = rIn.TellEnd(); + rIn.Seek(STREAM_SEEK_TO_BEGIN); + + Sequence<sal_Int8> aBuffer(std::min(nBufferSize, nSize)); + + while (nSize) + { + if (nSize < nBufferSize) + { + nBufferSize = nSize; + aBuffer.realloc(nSize); + } + + sal_uInt32 nRead = rIn.ReadBytes(aBuffer.getArray(), nBufferSize); + DBG_ASSERT(nRead == nBufferSize, "ImplCopySvStreamToXOutputStream failed!"); + xOut->writeBytes(aBuffer); + + if (nRead == 0) + break; + + nSize -= nRead; + } +} + +void Writer::storeTo(Reference<XOutputStream> const& xOutStream) +{ + for (auto& font : maFonts) + { + font->write(*mpFontsStream); + font.reset(); + } + maFonts.clear(); + + // Endtag + mpMovieStream->WriteUInt16(0); + + Tag aHeader(0xff); + + aHeader.addUI8('F'); + aHeader.addUI8('W'); + aHeader.addUI8('S'); + aHeader.addUI8(5); + + sal_uInt32 nSizePos = aHeader.Tell(); + + aHeader.WriteUInt32(0); + + tools::Rectangle aDocRect(0, 0, static_cast<long>(mnDocWidth * mnDocXScale), + static_cast<long>(mnDocHeight * mnDocYScale)); + + aHeader.addRect(aDocRect); + + // frame delay in 8.8 fixed number of frames per second + aHeader.addUI8(0); + aHeader.addUI8(12); + + aHeader.addUI16(uInt16_(mnFrames)); + + const sal_uInt32 nSize = aHeader.Tell() + mpFontsStream->Tell() + mpMovieStream->Tell(); + + aHeader.Seek(nSizePos); + aHeader.WriteUInt32(nSize); + + ImplCopySvStreamToXOutputStream(aHeader, xOutStream); + ImplCopySvStreamToXOutputStream(*mpFontsStream, xOutStream); + ImplCopySvStreamToXOutputStream(*mpMovieStream, xOutStream); +} + +sal_uInt16 Writer::startSprite() +{ + sal_uInt16 nShapeId = createID(); + mvSpriteStack.push(mpSprite.release()); + mpSprite.reset(new Sprite(nShapeId)); + return nShapeId; +} + +void Writer::endSprite() +{ + if (!mpSprite) + return; + + startTag(TAG_END); + endTag(); + + mpSprite->write(*mpMovieStream); + mpSprite.reset(); + + if (!mvSpriteStack.empty()) + { + mpSprite.reset(mvSpriteStack.top()); + mvSpriteStack.pop(); + } +} + +void Writer::placeShape(sal_uInt16 nID, sal_uInt16 nDepth, sal_Int32 x, sal_Int32 y) +{ + startTag(TAG_PLACEOBJECT2); + + BitStream aBits; + + aBits.writeUB(sal_uInt32(0), 1); // Has Clip Actions? + aBits.writeUB(0, 1); // reserved + aBits.writeUB(sal_uInt32(0), 1); // has a name + aBits.writeUB(0, 1); // no ratio + aBits.writeUB(0, 1); // no color transform + aBits.writeUB(1, 1); // has a matrix + aBits.writeUB(1, 1); // places a character + aBits.writeUB(0, 1); // does not define a character to be moved + + mpTag->addBits(aBits); + mpTag->addUI16(nDepth); // depth + mpTag->addUI16(nID); // character Id + + // #i73264# + const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createTranslateB2DHomMatrix( + Int16_(static_cast<long>(map100thmm(x) * mnDocXScale)), + Int16_(static_cast<long>(map100thmm(y) * mnDocYScale)))); + mpTag->addMatrix(aMatrix); // transformation matrix + + endTag(); +} + +void Writer::removeShape(sal_uInt16 nDepth) +{ + startTag(TAG_REMOVEOBJECT2); + mpTag->addUI16(nDepth); // depth + endTag(); +} + +void Writer::startTag(sal_uInt8 nTagId) +{ + DBG_ASSERT(mpTag == nullptr, "Last tag was not ended"); + + mpTag.reset(new Tag(nTagId)); +} + +void Writer::endTag() +{ + sal_uInt8 nTag = mpTag->getTagId(); + + if (mpSprite + && ((nTag == TAG_END) || (nTag == TAG_SHOWFRAME) || (nTag == TAG_DOACTION) + || (nTag == TAG_STARTSOUND) || (nTag == TAG_PLACEOBJECT) || (nTag == TAG_PLACEOBJECT2) + || (nTag == TAG_REMOVEOBJECT2) || (nTag == TAG_FRAMELABEL))) + { + mpSprite->addTag(std::move(mpTag)); + } + else + { + mpTag->write(*mpMovieStream); + mpTag.reset(); + } +} + -e ... etc. - the rest is truncated