From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- filter/AllLangMoTarget_flt.mk | 13 + filter/Configuration_filter.mk | 934 + filter/CppunitTest_filter_dialogs_test.mk | 68 + filter/CppunitTest_filter_msfilter.mk | 44 + filter/CppunitTest_filter_pdf.mk | 48 + filter/CppunitTest_filter_priority.mk | 41 + filter/CppunitTest_filter_svg.mk | 47 + filter/CppunitTest_filter_textfilterdetect.mk | 44 + filter/CppunitTest_filter_xslt.mk | 41 + filter/CustomTarget_svg.mk | 63 + filter/IwyuFilter_filter.yaml | 56 + filter/JunitTest_filter_complex.mk | 33 + filter/Library_filterconfig.mk | 61 + filter/Library_graphicfilter.mk | 53 + filter/Library_icg.mk | 56 + filter/Library_msfilter.mk | 72 + filter/Library_odfflatxml.mk | 36 + filter/Library_pdffilter.mk | 66 + filter/Library_storagefd.mk | 34 + filter/Library_svgfilter.mk | 79 + filter/Library_t602filter.mk | 47 + filter/Library_textfd.mk | 36 + filter/Library_xmlfa.mk | 42 + filter/Library_xmlfd.mk | 42 + filter/Library_xsltdlg.mk | 60 + filter/Library_xsltfilter.mk | 52 + filter/Makefile | 14 + filter/Module_filter.mk | 72 + filter/Package_docbook.mk | 27 + filter/Package_xhtml.mk | 26 + filter/Package_xslt.mk | 70 + filter/README.md | 25 + filter/UIConfig_filter.mk | 28 + filter/inc/strings.hrc | 76 + filter/inc/strings.hxx | 24 + .../filter/detection/typeDetection/Helper.java | 431 + .../detection/typeDetection/TypeDetection.java | 546 + .../detection/typeDetection/TypeDetection.props | 31 + .../filter/detection/typeDetection/files.csv | 117 + .../filter/detection/typeDetection/makefile.mk | 109 + .../detection/typeDetection/preselectedFilter.csv | 6 + .../detection/typeDetection/preselectedType.csv | 6 + .../filter/detection/typeDetection/serviceName.csv | 6 + .../filter/misc/FinalizedMandatoryTest.java | 304 + .../filter/misc/TypeDetection6FileFormat.java | 127 + .../filter/misc/TypeDetection6FileFormat.xcu | 42 + filter/qa/cppunit/data/xslt/copy.xslt | 9 + filter/qa/cppunit/msfilter-test.cxx | 76 + filter/qa/cppunit/priority-test.cxx | 85 + filter/qa/cppunit/xslt-test.cxx | 207 + filter/qa/data/picture.pdf | Bin 0 -> 13829 bytes filter/qa/pdf.cxx | 347 + filter/qa/unit/data/TransparentText.odg | Bin 0 -> 9354 bytes filter/qa/unit/data/attributeRedefinedTest.odp | Bin 0 -> 12610 bytes filter/qa/unit/data/calc.ots | Bin 0 -> 9564 bytes filter/qa/unit/data/custom-bullet.fodp | 36 + filter/qa/unit/data/empty.doc | 0 filter/qa/unit/data/empty.odp | 0 filter/qa/unit/data/empty.ods | 0 filter/qa/unit/data/empty.odt | 0 filter/qa/unit/data/empty.pptx | 0 filter/qa/unit/data/filter-dialogs-test.txt | 49 + filter/qa/unit/data/impress.otp | Bin 0 -> 15382 bytes filter/qa/unit/data/preserve-jpg.odt | Bin 0 -> 10052 bytes filter/qa/unit/data/semi-transparent-fill.odg | Bin 0 -> 10597 bytes filter/qa/unit/data/semi-transparent-line.odg | Bin 0 -> 8874 bytes filter/qa/unit/data/shape-nographic.odp | Bin 0 -> 14769 bytes filter/qa/unit/data/tdf114428.xhtml | 9 + filter/qa/unit/data/writer.ott | Bin 0 -> 10017 bytes filter/qa/unit/filter-dialogs-test.cxx | 61 + filter/qa/unit/svg.cxx | 380 + filter/qa/unit/textfilterdetect.cxx | 199 + filter/source/config/cache/basecontainer.cxx | 476 + filter/source/config/cache/basecontainer.hxx | 256 + filter/source/config/cache/cacheitem.cxx | 325 + filter/source/config/cache/cacheitem.hxx | 177 + filter/source/config/cache/cacheupdatelistener.cxx | 182 + filter/source/config/cache/cacheupdatelistener.hxx | 113 + filter/source/config/cache/configflush.cxx | 112 + filter/source/config/cache/configflush.hxx | 89 + filter/source/config/cache/constant.hxx | 153 + .../source/config/cache/contenthandlerfactory.cxx | 103 + .../source/config/cache/contenthandlerfactory.hxx | 99 + filter/source/config/cache/filtercache.cxx | 2236 +++ filter/source/config/cache/filtercache.hxx | 939 + filter/source/config/cache/filterconfig1.component | 42 + filter/source/config/cache/filterfactory.cxx | 498 + filter/source/config/cache/filterfactory.hxx | 135 + filter/source/config/cache/frameloaderfactory.cxx | 102 + filter/source/config/cache/frameloaderfactory.hxx | 98 + filter/source/config/cache/querytokenizer.cxx | 69 + filter/source/config/cache/querytokenizer.hxx | 92 + filter/source/config/cache/typedetection.cxx | 1204 ++ filter/source/config/cache/typedetection.hxx | 350 + .../com_sun_star_comp_framework_SoundHandler.xcu | 20 + .../com_sun_star_comp_framework_oxt_handler.xcu | 20 + .../config/fragments/filters/ADO_rowset_XML.xcu | 30 + filter/source/config/fragments/filters/AbiWord.xcu | 30 + .../config/fragments/filters/AppleKeynote.xcu | 29 + .../config/fragments/filters/AppleNumbers.xcu | 29 + .../source/config/fragments/filters/ApplePages.xcu | 29 + .../config/fragments/filters/BMP___MS_Windows.xcu | 30 + .../config/fragments/filters/BroadBand_eBook.xcu | 29 + .../filters/CGM___Computer_Graphics_Metafile.xcu | 30 + .../config/fragments/filters/ClarisWorks.xcu | 30 + .../config/fragments/filters/ClarisWorks_Calc.xcu | 30 + .../config/fragments/filters/ClarisWorks_Draw.xcu | 30 + .../fragments/filters/ClarisWorks_Impress.xcu | 30 + .../fragments/filters/Claris_Resolve_Calc.xcu | 30 + .../config/fragments/filters/CorelDrawDocument.xcu | 30 + .../filters/CorelPresentationExchange.xcu | 30 + filter/source/config/fragments/filters/DIF.xcu | 30 + .../filters/DXF___AutoCAD_Interchange.xcu | 30 + .../config/fragments/filters/DocBook_File.xcu | 30 + filter/source/config/fragments/filters/DosWord.xcu | 28 + .../filters/EMF___MS_Windows_Metafile.xcu | 30 + .../filters/EPS___Encapsulated_PostScript.xcu | 30 + filter/source/config/fragments/filters/EPUB.xcu | 30 + .../config/fragments/filters/FictionBook_2.xcu | 29 + .../config/fragments/filters/FreehandDocument.xcu | 13 + .../filters/GIF___Graphics_Interchange.xcu | 30 + filter/source/config/fragments/filters/HTML.xcu | 30 + .../config/fragments/filters/HTML_MasterDoc.xcu | 30 + .../config/fragments/filters/HTML__StarCalc_.xcu | 30 + .../config/fragments/filters/HTML__StarWriter_.xcu | 30 + .../source/config/fragments/filters/JPG___JPEG.xcu | 30 + filter/source/config/fragments/filters/Lotus.xcu | 30 + .../config/fragments/filters/LotusWordPro.xcu | 30 + .../fragments/filters/MET___OS_2_Metafile.xcu | 30 + .../config/fragments/filters/MS_Excel_2003_XML.xcu | 30 + .../fragments/filters/MS_Excel_2003_XML_Orcus.xcu | 19 + .../config/fragments/filters/MS_Excel_4_0.xcu | 30 + .../filters/MS_Excel_4_0_Vorlage_Template.xcu | 30 + .../config/fragments/filters/MS_Excel_5_0_95.xcu | 30 + .../filters/MS_Excel_5_0_95_Vorlage_Template.xcu | 30 + .../config/fragments/filters/MS_Excel_95.xcu | 30 + .../filters/MS_Excel_95_Vorlage_Template.xcu | 30 + .../config/fragments/filters/MS_Excel_97.xcu | 30 + .../filters/MS_Excel_97_Vorlage_Template.xcu | 30 + .../config/fragments/filters/MS_Multiplan.xcu | 29 + .../config/fragments/filters/MS_PowerPoint_97.xcu | 30 + .../filters/MS_PowerPoint_97_AutoPlay.xcu | 30 + .../fragments/filters/MS_PowerPoint_97_Vorlage.xcu | 30 + .../config/fragments/filters/MS_WinWord_5.xcu | 30 + .../config/fragments/filters/MS_WinWord_6_0.xcu | 30 + .../config/fragments/filters/MS_Word_2003_XML.xcu | 30 + .../config/fragments/filters/MS_Word_2007_XML.xcu | 30 + .../filters/MS_Word_2007_XML_Template.xcu | 28 + .../fragments/filters/MS_Word_2007_XML_VBA.xcu | 18 + .../source/config/fragments/filters/MS_Word_95.xcu | 30 + .../fragments/filters/MS_Word_95_Vorlage.xcu | 30 + .../source/config/fragments/filters/MS_Word_97.xcu | 30 + .../fragments/filters/MS_Word_97_Vorlage.xcu | 30 + .../source/config/fragments/filters/MS_Works.xcu | 30 + .../config/fragments/filters/MS_Works_Calc.xcu | 30 + .../source/config/fragments/filters/MS_Write.xcu | 30 + .../config/fragments/filters/MWAW_Bitmap.xcu | 29 + .../config/fragments/filters/MWAW_Database.xcu | 29 + .../config/fragments/filters/MWAW_Drawing.xcu | 29 + .../config/fragments/filters/MWAW_Presentation.xcu | 29 + .../config/fragments/filters/MWAW_Spreadsheet.xcu | 29 + .../fragments/filters/MWAW_Text_Document.xcu | 29 + .../source/config/fragments/filters/MacWrite.xcu | 30 + .../source/config/fragments/filters/Mac_Word.xcu | 30 + .../source/config/fragments/filters/Mac_Works.xcu | 30 + .../config/fragments/filters/Mac_Works_Calc.xcu | 30 + .../config/fragments/filters/Mariner_Write.xcu | 30 + .../config/fragments/filters/MathML_XML__Math_.xcu | 30 + .../config/fragments/filters/MathType_3_x.xcu | 30 + .../config/fragments/filters/ODG_FlatXML.xcu | 30 + .../config/fragments/filters/ODP_FlatXML.xcu | 30 + .../config/fragments/filters/ODS_FlatXML.xcu | 30 + .../config/fragments/filters/ODT_FlatXML.xcu | 30 + .../source/config/fragments/filters/OOXML_Text.xcu | 31 + .../fragments/filters/OOXML_Text_Template.xcu | 31 + .../fragments/filters/PBM___Portable_Bitmap.xcu | 30 + .../config/fragments/filters/PCT___Mac_Pict.xcu | 30 + .../fragments/filters/PCX___Zsoft_Paintbrush.xcu | 30 + .../fragments/filters/PGM___Portable_Graymap.xcu | 30 + .../filters/PNG___Portable_Network_Graphic.xcu | 30 + .../fragments/filters/PPM___Portable_Pixelmap.xcu | 30 + .../fragments/filters/PSD___Adobe_Photoshop.xcu | 30 + .../config/fragments/filters/PageMakerDocument.xcu | 13 + filter/source/config/fragments/filters/PalmDoc.xcu | 29 + .../fragments/filters/Palm_Text_Document.xcu | 29 + .../config/fragments/filters/Plucker_eBook.xcu | 29 + .../config/fragments/filters/PocketWord_File.xcu | 29 + .../config/fragments/filters/PowerPoint3.xcu | 28 + .../config/fragments/filters/PublisherDocument.xcu | 30 + filter/source/config/fragments/filters/QPro.xcu | 30 + .../config/fragments/filters/QXPDocument.xcu | 13 + .../fragments/filters/RAS___Sun_Rasterfile.xcu | 30 + .../config/fragments/filters/Rich_Text_Format.xcu | 30 + .../filters/Rich_Text_Format__StarCalc_.xcu | 30 + .../filters/SVG___Scalable_Vector_Graphics.xcu | 30 + .../SVG___Scalable_Vector_Graphics_Draw.xcu | 30 + .../fragments/filters/SVM___StarView_Metafile.xcu | 30 + filter/source/config/fragments/filters/SYLK.xcu | 30 + .../config/fragments/filters/StarBaseReport.xcu | 38 + .../fragments/filters/StarBaseReportChart.xcu | 40 + .../fragments/filters/StarOffice_Drawing.xcu | 29 + .../fragments/filters/StarOffice_Presentation.xcu | 29 + .../fragments/filters/StarOffice_Spreadsheet.xcu | 29 + .../config/fragments/filters/StarOffice_Writer.xcu | 29 + .../fragments/filters/StarOffice_XML__Base_.xcu | 30 + .../fragments/filters/StarOffice_XML__Calc_.xcu | 30 + .../fragments/filters/StarOffice_XML__Chart_.xcu | 30 + .../fragments/filters/StarOffice_XML__Draw_.xcu | 30 + .../fragments/filters/StarOffice_XML__Impress_.xcu | 30 + .../fragments/filters/StarOffice_XML__Math_.xcu | 30 + .../fragments/filters/StarOffice_XML__Writer_.xcu | 30 + .../config/fragments/filters/T602Document.xcu | 30 + .../fragments/filters/TGA___Truevision_TARGA.xcu | 30 + .../fragments/filters/TIF___Tag_Image_File.xcu | 30 + filter/source/config/fragments/filters/Text.xcu | 31 + .../fragments/filters/Text__StarWriter_Web_.xcu | 31 + .../filters/Text___txt___csv__StarCalc_.xcu | 31 + .../config/fragments/filters/Text__encoded_.xcu | 31 + .../Text__encoded___StarWriter_GlobalDocument_.xcu | 31 + .../filters/Text__encoded___StarWriter_Web_.xcu | 31 + .../config/fragments/filters/UOF_presentation.xcu | 30 + .../config/fragments/filters/UOF_spreadsheet.xcu | 30 + .../source/config/fragments/filters/UOF_text.xcu | 30 + .../config/fragments/filters/VisioDocument.xcu | 30 + .../config/fragments/filters/WEBP___WebP.xcu | 30 + .../filters/WMF___MS_Windows_Metafile.xcu | 30 + .../config/fragments/filters/WPS_Lotus_Calc.xcu | 30 + .../config/fragments/filters/WPS_QPro_Calc.xcu | 30 + .../config/fragments/filters/WordPerfect.xcu | 30 + .../fragments/filters/WordPerfectGraphics.xcu | 30 + .../source/config/fragments/filters/WriteNow.xcu | 30 + .../fragments/filters/XBM___X_Consortium.xcu | 30 + .../config/fragments/filters/XHTML_Calc_File.xcu | 30 + .../config/fragments/filters/XHTML_Draw_File.xcu | 30 + .../fragments/filters/XHTML_Impress_File.xcu | 30 + .../config/fragments/filters/XHTML_Writer_File.xcu | 30 + filter/source/config/fragments/filters/XPM.xcu | 30 + .../config/fragments/filters/ZMFDocument.xcu | 13 + filter/source/config/fragments/filters/calc8.xcu | 30 + .../config/fragments/filters/calc8_template.xcu | 30 + .../config/fragments/filters/calc_Gnumeric.xcu | 29 + .../fragments/filters/calc_HTML_WebQuery.xcu | 30 + .../filters/calc_MS_Excel_2007_Binary.xcu | 30 + .../filters/calc_MS_Excel_2007_VBA_XML.xcu | 30 + .../fragments/filters/calc_MS_Excel_2007_XML.xcu | 30 + .../filters/calc_MS_Excel_2007_XML_Template.xcu | 30 + .../source/config/fragments/filters/calc_OOXML.xcu | 30 + .../fragments/filters/calc_OOXML_Template.xcu | 30 + .../filters/calc_StarOffice_XML_Calc_Template.xcu | 30 + .../config/fragments/filters/calc_jpg_Export.xcu | 20 + .../config/fragments/filters/calc_pdf_Export.xcu | 30 + .../config/fragments/filters/calc_png_Export.xcu | 20 + .../config/fragments/filters/calc_svg_Export.xcu | 30 + .../config/fragments/filters/calc_webp_Export.xcu | 20 + filter/source/config/fragments/filters/chart8.xcu | 30 + filter/source/config/fragments/filters/dBase.xcu | 30 + filter/source/config/fragments/filters/draw8.xcu | 30 + .../config/fragments/filters/draw8_template.xcu | 30 + .../fragments/filters/draw_PCD_Photo_CD_Base.xcu | 30 + .../fragments/filters/draw_PCD_Photo_CD_Base16.xcu | 30 + .../fragments/filters/draw_PCD_Photo_CD_Base4.xcu | 30 + .../filters/draw_StarOffice_XML_Draw_Template.xcu | 30 + .../config/fragments/filters/draw_bmp_Export.xcu | 30 + .../config/fragments/filters/draw_emf_Export.xcu | 30 + .../config/fragments/filters/draw_eps_Export.xcu | 30 + .../config/fragments/filters/draw_gif_Export.xcu | 30 + .../config/fragments/filters/draw_html_Export.xcu | 30 + .../config/fragments/filters/draw_jpg_Export.xcu | 30 + .../config/fragments/filters/draw_pdf_Export.xcu | 30 + .../config/fragments/filters/draw_png_Export.xcu | 30 + .../config/fragments/filters/draw_svg_Export.xcu | 30 + .../config/fragments/filters/draw_tif_Export.xcu | 30 + .../config/fragments/filters/draw_webp_Export.xcu | 30 + .../config/fragments/filters/draw_wmf_Export.xcu | 30 + .../source/config/fragments/filters/impress8.xcu | 30 + .../config/fragments/filters/impress8_draw.xcu | 30 + .../config/fragments/filters/impress8_template.xcu | 30 + .../filters/impress_MS_PowerPoint_2007_XML.xcu | 30 + .../impress_MS_PowerPoint_2007_XML_AutoPlay.xcu | 28 + .../impress_MS_PowerPoint_2007_XML_Template.xcu | 28 + .../filters/impress_MS_PowerPoint_2007_XML_VBA.xcu | 30 + .../config/fragments/filters/impress_OOXML.xcu | 29 + .../fragments/filters/impress_OOXML_AutoPlay.xcu | 28 + .../fragments/filters/impress_OOXML_Template.xcu | 29 + .../filters/impress_StarOffice_XML_Draw.xcu | 30 + .../impress_StarOffice_XML_Impress_Template.xcu | 30 + .../fragments/filters/impress_bmp_Export.xcu | 30 + .../fragments/filters/impress_emf_Export.xcu | 30 + .../fragments/filters/impress_eps_Export.xcu | 30 + .../fragments/filters/impress_gif_Export.xcu | 30 + .../fragments/filters/impress_html_Export.xcu | 30 + .../fragments/filters/impress_jpg_Export.xcu | 30 + .../fragments/filters/impress_pdf_Export.xcu | 30 + .../fragments/filters/impress_png_Export.xcu | 30 + .../fragments/filters/impress_svg_Export.xcu | 30 + .../fragments/filters/impress_tif_Export.xcu | 30 + .../fragments/filters/impress_webp_Export.xcu | 30 + .../fragments/filters/impress_wmf_Export.xcu | 30 + filter/source/config/fragments/filters/math8.xcu | 30 + .../config/fragments/filters/math_pdf_Export.xcu | 30 + .../source/config/fragments/filters/mov__MOV.xcu | 21 + filter/source/config/fragments/filters/writer8.xcu | 30 + .../config/fragments/filters/writer8_template.xcu | 30 + .../fragments/filters/writer_MIZI_Hwp_97.xcu | 30 + .../writer_StarOffice_XML_Writer_Template.xcu | 30 + ...writer_globaldocument_StarOffice_XML_Writer.xcu | 30 + ...cument_StarOffice_XML_Writer_GlobalDocument.xcu | 30 + .../filters/writer_globaldocument_pdf_Export.xcu | 30 + .../fragments/filters/writer_indexing_export.xcu | 22 + .../config/fragments/filters/writer_jpg_Export.xcu | 30 + .../fragments/filters/writer_layout_dump.xcu | 30 + .../config/fragments/filters/writer_pdf_Export.xcu | 30 + .../config/fragments/filters/writer_png_Export.xcu | 30 + .../config/fragments/filters/writer_svg_Export.xcu | 30 + .../fragments/filters/writer_web_HTML_help.xcu | 30 + .../filters/writer_web_StarOffice_XML_Writer.xcu | 30 + ...iter_web_StarOffice_XML_Writer_Web_Template.xcu | 30 + .../fragments/filters/writer_web_jpg_Export.xcu | 21 + .../fragments/filters/writer_web_pdf_Export.xcu | 30 + .../fragments/filters/writer_web_png_Export.xcu | 21 + .../fragments/filters/writer_web_webp_Export.xcu | 21 + .../fragments/filters/writer_webp_Export.xcu | 30 + .../config/fragments/filters/writerglobal8.xcu | 30 + .../fragments/filters/writerglobal8_HTML.xcu | 30 + .../fragments/filters/writerglobal8_template.xcu | 20 + .../fragments/filters/writerglobal8_writer.xcu | 30 + .../config/fragments/filters/writerweb8_writer.xcu | 30 + .../filters/writerweb8_writer_template.xcu | 30 + .../com_sun_star_comp_chart2_ChartFrameLoader.xcu | 20 + .../com_sun_star_frame_Bibliography.xcu | 20 + .../com_sun_star_sdb_ContentLoader.xcu | 20 + .../org_openoffice_comp_dbflt_DBContentLoader2.xcu | 20 + .../internalgraphicfilters/bmp_Export.xcu | 27 + .../internalgraphicfilters/bmp_Import.xcu | 27 + .../internalgraphicfilters/dxf_Import.xcu | 28 + .../internalgraphicfilters/emf_Export.xcu | 27 + .../internalgraphicfilters/emf_Import.xcu | 27 + .../internalgraphicfilters/eps_Export.xcu | 28 + .../internalgraphicfilters/eps_Import.xcu | 28 + .../internalgraphicfilters/gif_Export.xcu | 28 + .../internalgraphicfilters/gif_Import.xcu | 27 + .../internalgraphicfilters/jpg_Export.xcu | 27 + .../internalgraphicfilters/jpg_Import.xcu | 27 + .../internalgraphicfilters/met_Import.xcu | 28 + .../internalgraphicfilters/mov_Import.xcu | 18 + .../internalgraphicfilters/pbm_Import.xcu | 28 + .../internalgraphicfilters/pcd_Import_Base.xcu | 28 + .../internalgraphicfilters/pcd_Import_Base16.xcu | 28 + .../internalgraphicfilters/pcd_Import_Base4.xcu | 28 + .../internalgraphicfilters/pct_Import.xcu | 28 + .../internalgraphicfilters/pcx_Import.xcu | 28 + .../internalgraphicfilters/pdf_Export.xcu | 17 + .../internalgraphicfilters/pdf_Import.xcu | 17 + .../internalgraphicfilters/pgm_Import.xcu | 28 + .../internalgraphicfilters/png_Export.xcu | 27 + .../internalgraphicfilters/png_Import.xcu | 27 + .../internalgraphicfilters/ppm_Import.xcu | 28 + .../internalgraphicfilters/psd_Import.xcu | 28 + .../internalgraphicfilters/ras_Import.xcu | 28 + .../internalgraphicfilters/svg_Export.xcu | 27 + .../internalgraphicfilters/svg_Import.xcu | 27 + .../internalgraphicfilters/svm_Export.xcu | 27 + .../internalgraphicfilters/svm_Import.xcu | 27 + .../internalgraphicfilters/tga_Import.xcu | 28 + .../internalgraphicfilters/tif_Export.xcu | 27 + .../internalgraphicfilters/tif_Import.xcu | 27 + .../internalgraphicfilters/webp_Export.xcu | 27 + .../internalgraphicfilters/webp_Import.xcu | 27 + .../internalgraphicfilters/wmf_Export.xcu | 27 + .../internalgraphicfilters/wmf_Import.xcu | 27 + .../internalgraphicfilters/xbm_Import.xcu | 27 + .../internalgraphicfilters/xpm_Import.xcu | 27 + filter/source/config/fragments/langfilter.xsl | 57 + .../fragments/types/MS_Excel_2007_Binary.xcu | 27 + .../fragments/types/MS_Excel_2007_VBA_XML.xcu | 27 + .../config/fragments/types/MS_Excel_2007_XML.xcu | 27 + .../fragments/types/MS_Excel_2007_XML_Template.xcu | 27 + .../fragments/types/MS_PowerPoint_2007_XML.xcu | 27 + .../types/MS_PowerPoint_2007_XML_AutoPlay.xcu | 27 + .../types/MS_PowerPoint_2007_XML_Template.xcu | 27 + .../fragments/types/MS_PowerPoint_2007_XML_VBA.xcu | 28 + .../source/config/fragments/types/MWAW_Bitmap.xcu | 27 + .../config/fragments/types/MWAW_Database.xcu | 27 + .../source/config/fragments/types/MWAW_Drawing.xcu | 27 + .../config/fragments/types/MWAW_Presentation.xcu | 27 + .../config/fragments/types/MWAW_Spreadsheet.xcu | 27 + .../config/fragments/types/MWAW_Text_Document.xcu | 27 + .../config/fragments/types/Palm_Text_Document.xcu | 29 + filter/source/config/fragments/types/StarBase.xcu | 29 + .../config/fragments/types/StarBaseReport.xcu | 43 + .../config/fragments/types/StarBaseReportChart.xcu | 41 + .../config/fragments/types/StarOffice_Drawing.xcu | 27 + .../fragments/types/StarOffice_Presentation.xcu | 27 + .../fragments/types/StarOffice_Spreadsheet.xcu | 27 + .../config/fragments/types/StarOffice_Writer.xcu | 27 + .../types/Unified_Office_Format_presentation.xcu | 29 + .../types/Unified_Office_Format_spreadsheet.xcu | 29 + .../fragments/types/Unified_Office_Format_text.xcu | 29 + .../source/config/fragments/types/XHTML_File.xcu | 29 + .../config/fragments/types/bmp_MS_Windows.xcu | 29 + filter/source/config/fragments/types/calc8.xcu | 29 + .../config/fragments/types/calc8_template.xcu | 29 + .../config/fragments/types/calc_ADO_rowset_XML.xcu | 29 + .../config/fragments/types/calc_AppleNumbers.xcu | 29 + .../config/fragments/types/calc_ClarisWorks.xcu | 29 + .../config/fragments/types/calc_Claris_Resolve.xcu | 29 + filter/source/config/fragments/types/calc_DIF.xcu | 29 + .../config/fragments/types/calc_Gnumeric.xcu | 17 + filter/source/config/fragments/types/calc_HTML.xcu | 35 + .../source/config/fragments/types/calc_Lotus.xcu | 29 + .../fragments/types/calc_MS_Excel_2003_XML.xcu | 29 + .../config/fragments/types/calc_MS_Excel_40.xcu | 29 + .../types/calc_MS_Excel_40_VorlageTemplate.xcu | 29 + .../config/fragments/types/calc_MS_Excel_5095.xcu | 29 + .../types/calc_MS_Excel_5095_VorlageTemplate.xcu | 29 + .../config/fragments/types/calc_MS_Excel_95.xcu | 29 + .../types/calc_MS_Excel_95_VorlageTemplate.xcu | 29 + .../config/fragments/types/calc_MS_Excel_97.xcu | 29 + .../types/calc_MS_Excel_97_VorlageTemplate.xcu | 29 + .../config/fragments/types/calc_MS_Multiplan.xcu | 25 + .../fragments/types/calc_MS_Works_Document.xcu | 29 + .../config/fragments/types/calc_Mac_Works.xcu | 29 + .../config/fragments/types/calc_ODS_FlatXML.xcu | 31 + .../source/config/fragments/types/calc_OOXML.xcu | 27 + .../config/fragments/types/calc_OOXML_Template.xcu | 27 + filter/source/config/fragments/types/calc_QPro.xcu | 29 + filter/source/config/fragments/types/calc_SYLK.xcu | 29 + .../fragments/types/calc_StarOffice_XML_Calc.xcu | 29 + .../types/calc_StarOffice_XML_Calc_Template.xcu | 29 + .../fragments/types/calc_WPS_Lotus_Document.xcu | 29 + .../fragments/types/calc_WPS_QPro_Document.xcu | 29 + .../source/config/fragments/types/calc_dBase.xcu | 29 + filter/source/config/fragments/types/chart8.xcu | 29 + .../fragments/types/chart_StarOffice_XML_Chart.xcu | 29 + .../fragments/types/component_Bibliography.xcu | 29 + .../source/config/fragments/types/component_DB.xcu | 29 + filter/source/config/fragments/types/draw8.xcu | 29 + .../config/fragments/types/draw8_template.xcu | 29 + .../config/fragments/types/draw_ClarisWorks.xcu | 29 + .../fragments/types/draw_CorelDraw_Document.xcu | 29 + .../types/draw_Corel_Presentation_Exchange.xcu | 29 + .../fragments/types/draw_Freehand_Document.xcu | 12 + .../config/fragments/types/draw_ODG_FlatXML.xcu | 31 + .../fragments/types/draw_PageMaker_Document.xcu | 12 + .../fragments/types/draw_Publisher_Document.xcu | 29 + .../config/fragments/types/draw_QXP_Document.xcu | 12 + .../fragments/types/draw_StarOffice_XML_Draw.xcu | 29 + .../types/draw_StarOffice_XML_Draw_Template.xcu | 29 + .../config/fragments/types/draw_Visio_Document.xcu | 29 + .../fragments/types/draw_WordPerfect_Graphics.xcu | 29 + .../config/fragments/types/draw_ZMF_Document.xcu | 12 + .../fragments/types/dxf_AutoCAD_Interchange.xcu | 29 + .../fragments/types/emf_MS_Windows_Metafile.xcu | 29 + .../types/eps_Encapsulated_PostScript.xcu | 29 + .../source/config/fragments/types/generic_HTML.xcu | 30 + .../source/config/fragments/types/generic_Text.xcu | 28 + .../fragments/types/gif_Graphics_Interchange.xcu | 29 + .../source/config/fragments/types/graphic_HTML.xcu | 29 + filter/source/config/fragments/types/impress8.xcu | 29 + .../config/fragments/types/impress8_template.xcu | 29 + .../fragments/types/impress_AppleKeynote.xcu | 29 + .../impress_CGM_Computer_Graphics_Metafile.xcu | 29 + .../config/fragments/types/impress_ClarisWorks.xcu | 29 + .../fragments/types/impress_MS_PowerPoint_97.xcu | 29 + .../types/impress_MS_PowerPoint_97_AutoPlay.xcu | 29 + .../types/impress_MS_PowerPoint_97_Vorlage.xcu | 29 + .../config/fragments/types/impress_ODP_FlatXML.xcu | 31 + .../fragments/types/impress_OOXML_Presentation.xcu | 27 + .../types/impress_OOXML_Presentation_AutoPlay.xcu | 27 + .../types/impress_OOXML_Presentation_Template.xcu | 27 + .../config/fragments/types/impress_PowerPoint3.xcu | 22 + .../types/impress_StarOffice_XML_Impress.xcu | 29 + .../impress_StarOffice_XML_Impress_Template.xcu | 29 + filter/source/config/fragments/types/jpg_JPEG.xcu | 29 + filter/source/config/fragments/types/math8.xcu | 29 + .../fragments/types/math_MathML_XML_Math.xcu | 29 + .../config/fragments/types/math_MathType_3x.xcu | 29 + .../fragments/types/math_StarOffice_XML_Math.xcu | 29 + .../config/fragments/types/met_OS2_Metafile.xcu | 29 + filter/source/config/fragments/types/mov_MOV.xcu | 20 + .../fragments/types/oxt_OpenOffice_Extension.xcu | 29 + .../config/fragments/types/pbm_Portable_Bitmap.xcu | 29 + .../config/fragments/types/pcd_Photo_CD_Base.xcu | 29 + .../config/fragments/types/pcd_Photo_CD_Base16.xcu | 29 + .../config/fragments/types/pcd_Photo_CD_Base4.xcu | 29 + .../source/config/fragments/types/pct_Mac_Pict.xcu | 29 + .../fragments/types/pcx_Zsoft_Paintbrush.xcu | 29 + .../types/pdf_Portable_Document_Format.xcu | 29 + .../fragments/types/pgm_Portable_Graymap.xcu | 29 + .../types/png_Portable_Network_Graphic.xcu | 29 + .../fragments/types/ppm_Portable_Pixelmap.xcu | 29 + .../config/fragments/types/psd_Adobe_Photoshop.xcu | 29 + .../config/fragments/types/ras_Sun_Rasterfile.xcu | 29 + .../types/svg_Scalable_Vector_Graphics.xcu | 29 + .../types/svg_Scalable_Vector_Graphics_Draw.xcu | 29 + .../fragments/types/svm_StarView_Metafile.xcu | 29 + .../fragments/types/tga_Truevision_TARGA.xcu | 29 + .../config/fragments/types/tif_Tag_Image_File.xcu | 29 + .../config/fragments/types/wav_Wave_Audio_File.xcu | 29 + filter/source/config/fragments/types/webp_WebP.xcu | 29 + .../fragments/types/wmf_MS_Windows_Metafile.xcu | 29 + filter/source/config/fragments/types/writer8.xcu | 29 + .../config/fragments/types/writer8_template.xcu | 29 + .../fragments/types/writer_AbiWord_Document.xcu | 29 + .../config/fragments/types/writer_ApplePages.xcu | 29 + .../fragments/types/writer_BroadBand_eBook.xcu | 29 + .../config/fragments/types/writer_ClarisWorks.xcu | 29 + .../config/fragments/types/writer_DocBook_File.xcu | 29 + .../config/fragments/types/writer_DosWord.xcu | 22 + .../fragments/types/writer_EPUB_Document.xcu | 29 + .../fragments/types/writer_FictionBook_2.xcu | 29 + .../types/writer_LotusWordPro_Document.xcu | 29 + .../config/fragments/types/writer_MIZI_Hwp_97.xcu | 29 + .../config/fragments/types/writer_MS_WinWord_5.xcu | 29 + .../fragments/types/writer_MS_WinWord_60.xcu | 29 + .../fragments/types/writer_MS_Word_2003_XML.xcu | 29 + .../fragments/types/writer_MS_Word_2007_XML.xcu | 27 + .../types/writer_MS_Word_2007_XML_Template.xcu | 27 + .../types/writer_MS_Word_2007_XML_VBA.xcu | 17 + .../config/fragments/types/writer_MS_Word_95.xcu | 29 + .../fragments/types/writer_MS_Word_95_Vorlage.xcu | 29 + .../config/fragments/types/writer_MS_Word_97.xcu | 29 + .../fragments/types/writer_MS_Word_97_Vorlage.xcu | 29 + .../fragments/types/writer_MS_Works_Document.xcu | 29 + .../config/fragments/types/writer_MS_Write.xcu | 29 + .../config/fragments/types/writer_MacWrite.xcu | 29 + .../config/fragments/types/writer_Mac_Word.xcu | 29 + .../config/fragments/types/writer_Mac_Works.xcu | 29 + .../fragments/types/writer_Mariner_Write.xcu | 29 + .../config/fragments/types/writer_ODT_FlatXML.xcu | 31 + .../source/config/fragments/types/writer_OOXML.xcu | 29 + .../fragments/types/writer_OOXML_Template.xcu | 29 + .../config/fragments/types/writer_PalmDoc.xcu | 29 + .../fragments/types/writer_Plucker_eBook.xcu | 29 + .../fragments/types/writer_PocketWord_File.xcu | 29 + .../fragments/types/writer_Rich_Text_Format.xcu | 29 + .../types/writer_StarOffice_XML_Writer.xcu | 29 + .../writer_StarOffice_XML_Writer_Template.xcu | 29 + .../fragments/types/writer_T602_Document.xcu | 29 + .../types/writer_WordPerfect_Document.xcu | 29 + .../config/fragments/types/writer_WriteNow.xcu | 29 + ...cument_StarOffice_XML_Writer_GlobalDocument.xcu | 29 + .../fragments/types/writer_indexing_export_xml.xcu | 21 + .../fragments/types/writer_layout_dump_xml.xcu | 29 + .../fragments/types/writer_web_HTML_help.xcu | 29 + ...iter_web_StarOffice_XML_Writer_Web_Template.xcu | 29 + .../config/fragments/types/writerglobal8.xcu | 29 + .../fragments/types/writerglobal8_template.xcu | 19 + .../fragments/types/writerweb8_writer_template.xcu | 29 + .../config/fragments/types/xbm_X_Consortium.xcu | 29 + filter/source/config/fragments/types/xpm_XPM.xcu | 29 + filter/source/config/tools/merge/FCFGMerge.cfg | 112 + filter/source/config/tools/merge/pyAltFCFGMerge | 590 + filter/source/docbook/DocBookTemplate.stw | Bin 0 -> 6688 bytes filter/source/docbook/docbooktosoffheadings.xsl | 1416 ++ filter/source/docbook/sofftodocbookheadings.xsl | 1152 ++ filter/source/graphic/GraphicExportFilter.cxx | 235 + filter/source/graphic/GraphicExportFilter.hxx | 79 + filter/source/graphic/graphicfilter.component | 26 + filter/source/graphicfilter/icgm/actimpr.cxx | 1041 + filter/source/graphicfilter/icgm/bitmap.cxx | 433 + filter/source/graphicfilter/icgm/bitmap.hxx | 81 + filter/source/graphicfilter/icgm/bundles.cxx | 141 + filter/source/graphicfilter/icgm/bundles.hxx | 166 + filter/source/graphicfilter/icgm/cgm.cxx | 741 + filter/source/graphicfilter/icgm/cgm.hxx | 151 + filter/source/graphicfilter/icgm/cgmtypes.hxx | 127 + filter/source/graphicfilter/icgm/chart.cxx | 57 + filter/source/graphicfilter/icgm/chart.hxx | 84 + filter/source/graphicfilter/icgm/class0.cxx | 128 + filter/source/graphicfilter/icgm/class1.cxx | 225 + filter/source/graphicfilter/icgm/class2.cxx | 233 + filter/source/graphicfilter/icgm/class3.cxx | 134 + filter/source/graphicfilter/icgm/class4.cxx | 911 + filter/source/graphicfilter/icgm/class5.cxx | 532 + filter/source/graphicfilter/icgm/class7.cxx | 210 + filter/source/graphicfilter/icgm/classx.cxx | 249 + filter/source/graphicfilter/icgm/elements.cxx | 336 + filter/source/graphicfilter/icgm/elements.hxx | 136 + filter/source/graphicfilter/icgm/outact.hxx | 108 + filter/source/msfilter/countryid.cxx | 319 + filter/source/msfilter/dffpropset.cxx | 1360 ++ filter/source/msfilter/dffrecordheader.cxx | 43 + filter/source/msfilter/escherex.cxx | 5295 +++++ filter/source/msfilter/eschesdo.cxx | 1237 ++ filter/source/msfilter/eschesdo.hxx | 138 + filter/source/msfilter/mscodec.cxx | 642 + filter/source/msfilter/msdffimp.cxx | 7610 +++++++ filter/source/msfilter/msfilter.component | 26 + filter/source/msfilter/msocximex.cxx | 146 + filter/source/msfilter/msoleexp.cxx | 340 + filter/source/msfilter/mstoolbar.cxx | 824 + filter/source/msfilter/msvbahelper.cxx | 768 + filter/source/msfilter/rtfutil.cxx | 401 + filter/source/msfilter/svdfppt.cxx | 7832 ++++++++ filter/source/msfilter/svxmsbas2.cxx | 80 + filter/source/msfilter/util.cxx | 1340 ++ filter/source/msfilter/viscache.hxx | 52 + filter/source/odfflatxml/OdfFlatXml.cxx | 260 + filter/source/odfflatxml/odfflatxml.component | 17 + filter/source/pdf/impdialog.cxx | 1638 ++ filter/source/pdf/impdialog.hxx | 419 + filter/source/pdf/pdfdecomposer.cxx | 123 + filter/source/pdf/pdfdialog.cxx | 139 + filter/source/pdf/pdfdialog.hxx | 72 + filter/source/pdf/pdfexport.cxx | 1374 ++ filter/source/pdf/pdfexport.hxx | 145 + filter/source/pdf/pdffilter.component | 38 + filter/source/pdf/pdffilter.cxx | 295 + filter/source/pdf/pdffilter.hxx | 70 + filter/source/pdf/pdfinteract.cxx | 97 + filter/source/pdf/pdfinteract.hxx | 61 + filter/source/storagefilterdetect/filterdetect.cxx | 192 + filter/source/storagefilterdetect/filterdetect.hxx | 56 + .../source/storagefilterdetect/storagefd.component | 16 + filter/source/svg/.eslintrc.js | 250 + filter/source/svg/gentoken.py | 60 + filter/source/svg/js2hxx.py | 149 + filter/source/svg/presentation_engine.js | 19575 +++++++++++++++++++ filter/source/svg/svgexport.cxx | 2877 +++ filter/source/svg/svgfilter.component | 32 + filter/source/svg/svgfilter.cxx | 847 + filter/source/svg/svgfilter.hxx | 321 + filter/source/svg/svgfontexport.cxx | 321 + filter/source/svg/svgfontexport.hxx | 72 + filter/source/svg/svgwriter.cxx | 4096 ++++ filter/source/svg/svgwriter.hxx | 406 + filter/source/svg/test/odfserializer.cxx | 128 + filter/source/svg/test/odfserializer.hxx | 33 + filter/source/svg/tokens.txt | 403 + filter/source/t602/t602filter.component | 31 + filter/source/t602/t602filter.cxx | 1137 ++ filter/source/t602/t602filter.hxx | 255 + filter/source/textfilterdetect/filterdetect.cxx | 247 + filter/source/textfilterdetect/filterdetect.hxx | 59 + filter/source/textfilterdetect/textfd.component | 17 + .../source/xmlfilteradaptor/XmlFilterAdaptor.cxx | 391 + .../source/xmlfilteradaptor/XmlFilterAdaptor.hxx | 106 + filter/source/xmlfilteradaptor/xmlfa.component | 27 + filter/source/xmlfilterdetect/filterdetect.cxx | 246 + filter/source/xmlfilterdetect/filterdetect.hxx | 59 + filter/source/xmlfilterdetect/xmlfd.component | 26 + filter/source/xslt/common/copy.xsl | 26 + filter/source/xslt/common/math.xsl | 580 + filter/source/xslt/common/measure_conversion.xsl | 479 + filter/source/xslt/export/common/ooo2ms_docpr.xsl | 130 + .../source/xslt/export/spreadsheetml/formular.xsl | 631 + .../export/spreadsheetml/ooo2spreadsheetml.xsl | 408 + .../xslt/export/spreadsheetml/style_mapping.xsl | 381 + filter/source/xslt/export/spreadsheetml/styles.xsl | 686 + filter/source/xslt/export/spreadsheetml/table.xsl | 928 + .../xslt/export/uof/odf2uof_presentation.xsl | 3392 ++++ .../source/xslt/export/uof/odf2uof_spreadsheet.xsl | 6245 ++++++ filter/source/xslt/export/uof/odf2uof_text.xsl | 4456 +++++ filter/source/xslt/export/wordml/ooo2wordml.xsl | 209 + .../xslt/export/wordml/ooo2wordml_border.xsl | 144 + .../xslt/export/wordml/ooo2wordml_custom_draw.xsl | 275 + .../source/xslt/export/wordml/ooo2wordml_draw.xsl | 1760 ++ .../source/xslt/export/wordml/ooo2wordml_field.xsl | 726 + .../source/xslt/export/wordml/ooo2wordml_list.xsl | 349 + .../source/xslt/export/wordml/ooo2wordml_page.xsl | 392 + .../source/xslt/export/wordml/ooo2wordml_path.xsl | 849 + .../xslt/export/wordml/ooo2wordml_settings.xsl | 308 + .../source/xslt/export/wordml/ooo2wordml_table.xsl | 407 + .../source/xslt/export/wordml/ooo2wordml_text.xsl | 1270 ++ filter/source/xslt/import/common/ms2ooo_docpr.xsl | 92 + .../xslt/import/spreadsheetml/adorowset2ods.xsl | 216 + .../import/spreadsheetml/spreadsheetml2ooo.xsl | 9152 +++++++++ .../xslt/import/uof/uof2odf_presentation.xsl | 3494 ++++ .../source/xslt/import/uof/uof2odf_spreadsheet.xsl | 9071 +++++++++ filter/source/xslt/import/uof/uof2odf_text.xsl | 4667 +++++ filter/source/xslt/import/wordml/wordml2ooo.xsl | 256 + .../xslt/import/wordml/wordml2ooo_custom_draw.xsl | 275 + .../source/xslt/import/wordml/wordml2ooo_draw.xsl | 2170 ++ .../source/xslt/import/wordml/wordml2ooo_field.xsl | 1581 ++ .../source/xslt/import/wordml/wordml2ooo_list.xsl | 648 + .../source/xslt/import/wordml/wordml2ooo_page.xsl | 402 + .../source/xslt/import/wordml/wordml2ooo_path.xsl | 1809 ++ .../source/xslt/import/wordml/wordml2ooo_props.xsl | 268 + .../xslt/import/wordml/wordml2ooo_settings.xsl | 60 + .../source/xslt/import/wordml/wordml2ooo_table.xsl | 1277 ++ .../source/xslt/import/wordml/wordml2ooo_text.xsl | 1049 + .../source/xslt/odf2xhtml/export/common/body.xsl | 428 + .../export/common/styles/style_collector.xsl | 832 + .../export/common/styles/style_mapping_css.xsl | 380 + .../xslt/odf2xhtml/export/common/table/table.xsl | 155 + .../odf2xhtml/export/common/table/table_cells.xsl | 270 + .../export/common/table/table_columns.xsl | 232 + .../odf2xhtml/export/common/table/table_rows.xsl | 203 + .../odf2xhtml/export/common/table_of_content.xsl | 579 + filter/source/xslt/odf2xhtml/export/xhtml/body.xsl | 3022 +++ .../source/xslt/odf2xhtml/export/xhtml/header.xsl | 480 + .../xslt/odf2xhtml/export/xhtml/opendoc2xhtml.xsl | 186 + .../source/xslt/odf2xhtml/export/xhtml/table.xsl | 213 + filter/source/xsltdialog/typedetectionexport.cxx | 264 + filter/source/xsltdialog/typedetectionexport.hxx | 41 + filter/source/xsltdialog/typedetectionimport.cxx | 316 + filter/source/xsltdialog/typedetectionimport.hxx | 92 + filter/source/xsltdialog/xmlfiltercommon.hxx | 83 + .../source/xsltdialog/xmlfilterdialogcomponent.cxx | 285 + filter/source/xsltdialog/xmlfilterjar.cxx | 361 + filter/source/xsltdialog/xmlfilterjar.hxx | 52 + .../source/xsltdialog/xmlfiltersettingsdialog.cxx | 1384 ++ .../source/xsltdialog/xmlfiltersettingsdialog.hxx | 97 + filter/source/xsltdialog/xmlfiltertabdialog.cxx | 263 + filter/source/xsltdialog/xmlfiltertabdialog.hxx | 54 + filter/source/xsltdialog/xmlfiltertabpagebasic.cxx | 128 + filter/source/xsltdialog/xmlfiltertabpagebasic.hxx | 43 + filter/source/xsltdialog/xmlfiltertabpagexslt.cxx | 165 + filter/source/xsltdialog/xmlfiltertabpagexslt.hxx | 56 + filter/source/xsltdialog/xmlfiltertestdialog.cxx | 697 + filter/source/xsltdialog/xmlfiltertestdialog.hxx | 81 + filter/source/xsltdialog/xsltdlg.component | 26 + filter/source/xsltfilter/LibXSLTTransformer.cxx | 571 + filter/source/xsltfilter/LibXSLTTransformer.hxx | 185 + filter/source/xsltfilter/OleHandler.cxx | 214 + filter/source/xsltfilter/OleHandler.hxx | 93 + filter/source/xsltfilter/XSLTFilter.cxx | 659 + filter/source/xsltfilter/xsltfilter.component | 30 + filter/uiconfig/ui/pdfgeneralpage.ui | 1038 + filter/uiconfig/ui/pdflinkspage.ui | 197 + filter/uiconfig/ui/pdfoptionsdialog.ui | 399 + filter/uiconfig/ui/pdfsecuritypage.ui | 595 + filter/uiconfig/ui/pdfsignpage.ui | 307 + filter/uiconfig/ui/pdfuserinterfacepage.ui | 381 + filter/uiconfig/ui/pdfviewpage.ui | 491 + filter/uiconfig/ui/testxmlfilter.ui | 411 + filter/uiconfig/ui/warnpdfdialog.ui | 128 + filter/uiconfig/ui/xmlfiltersettings.ui | 294 + filter/uiconfig/ui/xmlfiltertabpagegeneral.ui | 217 + .../uiconfig/ui/xmlfiltertabpagetransformation.ui | 254 + filter/uiconfig/ui/xsltfilterdialog.ui | 153 + 732 files changed, 181672 insertions(+) create mode 100644 filter/AllLangMoTarget_flt.mk create mode 100644 filter/Configuration_filter.mk create mode 100644 filter/CppunitTest_filter_dialogs_test.mk create mode 100644 filter/CppunitTest_filter_msfilter.mk create mode 100644 filter/CppunitTest_filter_pdf.mk create mode 100644 filter/CppunitTest_filter_priority.mk create mode 100644 filter/CppunitTest_filter_svg.mk create mode 100644 filter/CppunitTest_filter_textfilterdetect.mk create mode 100644 filter/CppunitTest_filter_xslt.mk create mode 100644 filter/CustomTarget_svg.mk create mode 100644 filter/IwyuFilter_filter.yaml create mode 100644 filter/JunitTest_filter_complex.mk create mode 100644 filter/Library_filterconfig.mk create mode 100644 filter/Library_graphicfilter.mk create mode 100644 filter/Library_icg.mk create mode 100644 filter/Library_msfilter.mk create mode 100644 filter/Library_odfflatxml.mk create mode 100644 filter/Library_pdffilter.mk create mode 100644 filter/Library_storagefd.mk create mode 100644 filter/Library_svgfilter.mk create mode 100644 filter/Library_t602filter.mk create mode 100644 filter/Library_textfd.mk create mode 100644 filter/Library_xmlfa.mk create mode 100644 filter/Library_xmlfd.mk create mode 100644 filter/Library_xsltdlg.mk create mode 100644 filter/Library_xsltfilter.mk create mode 100644 filter/Makefile create mode 100644 filter/Module_filter.mk create mode 100644 filter/Package_docbook.mk create mode 100644 filter/Package_xhtml.mk create mode 100644 filter/Package_xslt.mk create mode 100644 filter/README.md create mode 100644 filter/UIConfig_filter.mk create mode 100644 filter/inc/strings.hrc create mode 100644 filter/inc/strings.hxx create mode 100644 filter/qa/complex/filter/detection/typeDetection/Helper.java create mode 100644 filter/qa/complex/filter/detection/typeDetection/TypeDetection.java create mode 100644 filter/qa/complex/filter/detection/typeDetection/TypeDetection.props create mode 100644 filter/qa/complex/filter/detection/typeDetection/files.csv create mode 100644 filter/qa/complex/filter/detection/typeDetection/makefile.mk create mode 100644 filter/qa/complex/filter/detection/typeDetection/preselectedFilter.csv create mode 100644 filter/qa/complex/filter/detection/typeDetection/preselectedType.csv create mode 100644 filter/qa/complex/filter/detection/typeDetection/serviceName.csv create mode 100644 filter/qa/complex/filter/misc/FinalizedMandatoryTest.java create mode 100644 filter/qa/complex/filter/misc/TypeDetection6FileFormat.java create mode 100644 filter/qa/complex/filter/misc/TypeDetection6FileFormat.xcu create mode 100644 filter/qa/cppunit/data/xslt/copy.xslt create mode 100644 filter/qa/cppunit/msfilter-test.cxx create mode 100644 filter/qa/cppunit/priority-test.cxx create mode 100644 filter/qa/cppunit/xslt-test.cxx create mode 100644 filter/qa/data/picture.pdf create mode 100644 filter/qa/pdf.cxx create mode 100644 filter/qa/unit/data/TransparentText.odg create mode 100644 filter/qa/unit/data/attributeRedefinedTest.odp create mode 100644 filter/qa/unit/data/calc.ots create mode 100644 filter/qa/unit/data/custom-bullet.fodp create mode 100644 filter/qa/unit/data/empty.doc create mode 100644 filter/qa/unit/data/empty.odp create mode 100644 filter/qa/unit/data/empty.ods create mode 100644 filter/qa/unit/data/empty.odt create mode 100644 filter/qa/unit/data/empty.pptx create mode 100644 filter/qa/unit/data/filter-dialogs-test.txt create mode 100644 filter/qa/unit/data/impress.otp create mode 100644 filter/qa/unit/data/preserve-jpg.odt create mode 100644 filter/qa/unit/data/semi-transparent-fill.odg create mode 100644 filter/qa/unit/data/semi-transparent-line.odg create mode 100644 filter/qa/unit/data/shape-nographic.odp create mode 100644 filter/qa/unit/data/tdf114428.xhtml create mode 100644 filter/qa/unit/data/writer.ott create mode 100644 filter/qa/unit/filter-dialogs-test.cxx create mode 100644 filter/qa/unit/svg.cxx create mode 100644 filter/qa/unit/textfilterdetect.cxx create mode 100644 filter/source/config/cache/basecontainer.cxx create mode 100644 filter/source/config/cache/basecontainer.hxx create mode 100644 filter/source/config/cache/cacheitem.cxx create mode 100644 filter/source/config/cache/cacheitem.hxx create mode 100644 filter/source/config/cache/cacheupdatelistener.cxx create mode 100644 filter/source/config/cache/cacheupdatelistener.hxx create mode 100644 filter/source/config/cache/configflush.cxx create mode 100644 filter/source/config/cache/configflush.hxx create mode 100644 filter/source/config/cache/constant.hxx create mode 100644 filter/source/config/cache/contenthandlerfactory.cxx create mode 100644 filter/source/config/cache/contenthandlerfactory.hxx create mode 100644 filter/source/config/cache/filtercache.cxx create mode 100644 filter/source/config/cache/filtercache.hxx create mode 100644 filter/source/config/cache/filterconfig1.component create mode 100644 filter/source/config/cache/filterfactory.cxx create mode 100644 filter/source/config/cache/filterfactory.hxx create mode 100644 filter/source/config/cache/frameloaderfactory.cxx create mode 100644 filter/source/config/cache/frameloaderfactory.hxx create mode 100644 filter/source/config/cache/querytokenizer.cxx create mode 100644 filter/source/config/cache/querytokenizer.hxx create mode 100644 filter/source/config/cache/typedetection.cxx create mode 100644 filter/source/config/cache/typedetection.hxx create mode 100644 filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_SoundHandler.xcu create mode 100644 filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_oxt_handler.xcu create mode 100644 filter/source/config/fragments/filters/ADO_rowset_XML.xcu create mode 100644 filter/source/config/fragments/filters/AbiWord.xcu create mode 100644 filter/source/config/fragments/filters/AppleKeynote.xcu create mode 100644 filter/source/config/fragments/filters/AppleNumbers.xcu create mode 100644 filter/source/config/fragments/filters/ApplePages.xcu create mode 100644 filter/source/config/fragments/filters/BMP___MS_Windows.xcu create mode 100644 filter/source/config/fragments/filters/BroadBand_eBook.xcu create mode 100644 filter/source/config/fragments/filters/CGM___Computer_Graphics_Metafile.xcu create mode 100644 filter/source/config/fragments/filters/ClarisWorks.xcu create mode 100644 filter/source/config/fragments/filters/ClarisWorks_Calc.xcu create mode 100644 filter/source/config/fragments/filters/ClarisWorks_Draw.xcu create mode 100644 filter/source/config/fragments/filters/ClarisWorks_Impress.xcu create mode 100644 filter/source/config/fragments/filters/Claris_Resolve_Calc.xcu create mode 100644 filter/source/config/fragments/filters/CorelDrawDocument.xcu create mode 100644 filter/source/config/fragments/filters/CorelPresentationExchange.xcu create mode 100644 filter/source/config/fragments/filters/DIF.xcu create mode 100644 filter/source/config/fragments/filters/DXF___AutoCAD_Interchange.xcu create mode 100644 filter/source/config/fragments/filters/DocBook_File.xcu create mode 100644 filter/source/config/fragments/filters/DosWord.xcu create mode 100644 filter/source/config/fragments/filters/EMF___MS_Windows_Metafile.xcu create mode 100644 filter/source/config/fragments/filters/EPS___Encapsulated_PostScript.xcu create mode 100644 filter/source/config/fragments/filters/EPUB.xcu create mode 100644 filter/source/config/fragments/filters/FictionBook_2.xcu create mode 100644 filter/source/config/fragments/filters/FreehandDocument.xcu create mode 100644 filter/source/config/fragments/filters/GIF___Graphics_Interchange.xcu create mode 100644 filter/source/config/fragments/filters/HTML.xcu create mode 100644 filter/source/config/fragments/filters/HTML_MasterDoc.xcu create mode 100644 filter/source/config/fragments/filters/HTML__StarCalc_.xcu create mode 100644 filter/source/config/fragments/filters/HTML__StarWriter_.xcu create mode 100644 filter/source/config/fragments/filters/JPG___JPEG.xcu create mode 100644 filter/source/config/fragments/filters/Lotus.xcu create mode 100644 filter/source/config/fragments/filters/LotusWordPro.xcu create mode 100644 filter/source/config/fragments/filters/MET___OS_2_Metafile.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_2003_XML.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_2003_XML_Orcus.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_4_0.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_4_0_Vorlage_Template.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_5_0_95.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_5_0_95_Vorlage_Template.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_95.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_95_Vorlage_Template.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_97.xcu create mode 100644 filter/source/config/fragments/filters/MS_Excel_97_Vorlage_Template.xcu create mode 100644 filter/source/config/fragments/filters/MS_Multiplan.xcu create mode 100644 filter/source/config/fragments/filters/MS_PowerPoint_97.xcu create mode 100644 filter/source/config/fragments/filters/MS_PowerPoint_97_AutoPlay.xcu create mode 100644 filter/source/config/fragments/filters/MS_PowerPoint_97_Vorlage.xcu create mode 100644 filter/source/config/fragments/filters/MS_WinWord_5.xcu create mode 100644 filter/source/config/fragments/filters/MS_WinWord_6_0.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_2003_XML.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_2007_XML.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_2007_XML_Template.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_2007_XML_VBA.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_95.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_95_Vorlage.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_97.xcu create mode 100644 filter/source/config/fragments/filters/MS_Word_97_Vorlage.xcu create mode 100644 filter/source/config/fragments/filters/MS_Works.xcu create mode 100644 filter/source/config/fragments/filters/MS_Works_Calc.xcu create mode 100644 filter/source/config/fragments/filters/MS_Write.xcu create mode 100644 filter/source/config/fragments/filters/MWAW_Bitmap.xcu create mode 100644 filter/source/config/fragments/filters/MWAW_Database.xcu create mode 100644 filter/source/config/fragments/filters/MWAW_Drawing.xcu create mode 100644 filter/source/config/fragments/filters/MWAW_Presentation.xcu create mode 100644 filter/source/config/fragments/filters/MWAW_Spreadsheet.xcu create mode 100644 filter/source/config/fragments/filters/MWAW_Text_Document.xcu create mode 100644 filter/source/config/fragments/filters/MacWrite.xcu create mode 100644 filter/source/config/fragments/filters/Mac_Word.xcu create mode 100644 filter/source/config/fragments/filters/Mac_Works.xcu create mode 100644 filter/source/config/fragments/filters/Mac_Works_Calc.xcu create mode 100644 filter/source/config/fragments/filters/Mariner_Write.xcu create mode 100644 filter/source/config/fragments/filters/MathML_XML__Math_.xcu create mode 100644 filter/source/config/fragments/filters/MathType_3_x.xcu create mode 100644 filter/source/config/fragments/filters/ODG_FlatXML.xcu create mode 100644 filter/source/config/fragments/filters/ODP_FlatXML.xcu create mode 100644 filter/source/config/fragments/filters/ODS_FlatXML.xcu create mode 100644 filter/source/config/fragments/filters/ODT_FlatXML.xcu create mode 100644 filter/source/config/fragments/filters/OOXML_Text.xcu create mode 100644 filter/source/config/fragments/filters/OOXML_Text_Template.xcu create mode 100644 filter/source/config/fragments/filters/PBM___Portable_Bitmap.xcu create mode 100644 filter/source/config/fragments/filters/PCT___Mac_Pict.xcu create mode 100644 filter/source/config/fragments/filters/PCX___Zsoft_Paintbrush.xcu create mode 100644 filter/source/config/fragments/filters/PGM___Portable_Graymap.xcu create mode 100644 filter/source/config/fragments/filters/PNG___Portable_Network_Graphic.xcu create mode 100644 filter/source/config/fragments/filters/PPM___Portable_Pixelmap.xcu create mode 100644 filter/source/config/fragments/filters/PSD___Adobe_Photoshop.xcu create mode 100644 filter/source/config/fragments/filters/PageMakerDocument.xcu create mode 100644 filter/source/config/fragments/filters/PalmDoc.xcu create mode 100644 filter/source/config/fragments/filters/Palm_Text_Document.xcu create mode 100644 filter/source/config/fragments/filters/Plucker_eBook.xcu create mode 100644 filter/source/config/fragments/filters/PocketWord_File.xcu create mode 100644 filter/source/config/fragments/filters/PowerPoint3.xcu create mode 100644 filter/source/config/fragments/filters/PublisherDocument.xcu create mode 100644 filter/source/config/fragments/filters/QPro.xcu create mode 100644 filter/source/config/fragments/filters/QXPDocument.xcu create mode 100644 filter/source/config/fragments/filters/RAS___Sun_Rasterfile.xcu create mode 100644 filter/source/config/fragments/filters/Rich_Text_Format.xcu create mode 100644 filter/source/config/fragments/filters/Rich_Text_Format__StarCalc_.xcu create mode 100644 filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu create mode 100644 filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics_Draw.xcu create mode 100644 filter/source/config/fragments/filters/SVM___StarView_Metafile.xcu create mode 100644 filter/source/config/fragments/filters/SYLK.xcu create mode 100644 filter/source/config/fragments/filters/StarBaseReport.xcu create mode 100644 filter/source/config/fragments/filters/StarBaseReportChart.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_Drawing.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_Presentation.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_Spreadsheet.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_Writer.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_XML__Base_.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_XML__Calc_.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_XML__Chart_.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_XML__Draw_.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_XML__Impress_.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_XML__Math_.xcu create mode 100644 filter/source/config/fragments/filters/StarOffice_XML__Writer_.xcu create mode 100644 filter/source/config/fragments/filters/T602Document.xcu create mode 100644 filter/source/config/fragments/filters/TGA___Truevision_TARGA.xcu create mode 100644 filter/source/config/fragments/filters/TIF___Tag_Image_File.xcu create mode 100644 filter/source/config/fragments/filters/Text.xcu create mode 100644 filter/source/config/fragments/filters/Text__StarWriter_Web_.xcu create mode 100644 filter/source/config/fragments/filters/Text___txt___csv__StarCalc_.xcu create mode 100644 filter/source/config/fragments/filters/Text__encoded_.xcu create mode 100644 filter/source/config/fragments/filters/Text__encoded___StarWriter_GlobalDocument_.xcu create mode 100644 filter/source/config/fragments/filters/Text__encoded___StarWriter_Web_.xcu create mode 100644 filter/source/config/fragments/filters/UOF_presentation.xcu create mode 100644 filter/source/config/fragments/filters/UOF_spreadsheet.xcu create mode 100644 filter/source/config/fragments/filters/UOF_text.xcu create mode 100644 filter/source/config/fragments/filters/VisioDocument.xcu create mode 100644 filter/source/config/fragments/filters/WEBP___WebP.xcu create mode 100644 filter/source/config/fragments/filters/WMF___MS_Windows_Metafile.xcu create mode 100644 filter/source/config/fragments/filters/WPS_Lotus_Calc.xcu create mode 100644 filter/source/config/fragments/filters/WPS_QPro_Calc.xcu create mode 100644 filter/source/config/fragments/filters/WordPerfect.xcu create mode 100644 filter/source/config/fragments/filters/WordPerfectGraphics.xcu create mode 100644 filter/source/config/fragments/filters/WriteNow.xcu create mode 100644 filter/source/config/fragments/filters/XBM___X_Consortium.xcu create mode 100644 filter/source/config/fragments/filters/XHTML_Calc_File.xcu create mode 100644 filter/source/config/fragments/filters/XHTML_Draw_File.xcu create mode 100644 filter/source/config/fragments/filters/XHTML_Impress_File.xcu create mode 100644 filter/source/config/fragments/filters/XHTML_Writer_File.xcu create mode 100644 filter/source/config/fragments/filters/XPM.xcu create mode 100644 filter/source/config/fragments/filters/ZMFDocument.xcu create mode 100644 filter/source/config/fragments/filters/calc8.xcu create mode 100644 filter/source/config/fragments/filters/calc8_template.xcu create mode 100644 filter/source/config/fragments/filters/calc_Gnumeric.xcu create mode 100644 filter/source/config/fragments/filters/calc_HTML_WebQuery.xcu create mode 100644 filter/source/config/fragments/filters/calc_MS_Excel_2007_Binary.xcu create mode 100644 filter/source/config/fragments/filters/calc_MS_Excel_2007_VBA_XML.xcu create mode 100644 filter/source/config/fragments/filters/calc_MS_Excel_2007_XML.xcu create mode 100644 filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu create mode 100644 filter/source/config/fragments/filters/calc_OOXML.xcu create mode 100644 filter/source/config/fragments/filters/calc_OOXML_Template.xcu create mode 100644 filter/source/config/fragments/filters/calc_StarOffice_XML_Calc_Template.xcu create mode 100644 filter/source/config/fragments/filters/calc_jpg_Export.xcu create mode 100644 filter/source/config/fragments/filters/calc_pdf_Export.xcu create mode 100644 filter/source/config/fragments/filters/calc_png_Export.xcu create mode 100644 filter/source/config/fragments/filters/calc_svg_Export.xcu create mode 100644 filter/source/config/fragments/filters/calc_webp_Export.xcu create mode 100644 filter/source/config/fragments/filters/chart8.xcu create mode 100644 filter/source/config/fragments/filters/dBase.xcu create mode 100644 filter/source/config/fragments/filters/draw8.xcu create mode 100644 filter/source/config/fragments/filters/draw8_template.xcu create mode 100644 filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base.xcu create mode 100644 filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base16.xcu create mode 100644 filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base4.xcu create mode 100644 filter/source/config/fragments/filters/draw_StarOffice_XML_Draw_Template.xcu create mode 100644 filter/source/config/fragments/filters/draw_bmp_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_emf_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_eps_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_gif_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_html_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_jpg_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_pdf_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_png_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_svg_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_tif_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_webp_Export.xcu create mode 100644 filter/source/config/fragments/filters/draw_wmf_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress8.xcu create mode 100644 filter/source/config/fragments/filters/impress8_draw.xcu create mode 100644 filter/source/config/fragments/filters/impress8_template.xcu create mode 100644 filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu create mode 100644 filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu create mode 100644 filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_Template.xcu create mode 100644 filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_VBA.xcu create mode 100644 filter/source/config/fragments/filters/impress_OOXML.xcu create mode 100644 filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu create mode 100644 filter/source/config/fragments/filters/impress_OOXML_Template.xcu create mode 100644 filter/source/config/fragments/filters/impress_StarOffice_XML_Draw.xcu create mode 100644 filter/source/config/fragments/filters/impress_StarOffice_XML_Impress_Template.xcu create mode 100644 filter/source/config/fragments/filters/impress_bmp_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_emf_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_eps_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_gif_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_html_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_jpg_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_pdf_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_png_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_svg_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_tif_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_webp_Export.xcu create mode 100644 filter/source/config/fragments/filters/impress_wmf_Export.xcu create mode 100644 filter/source/config/fragments/filters/math8.xcu create mode 100644 filter/source/config/fragments/filters/math_pdf_Export.xcu create mode 100644 filter/source/config/fragments/filters/mov__MOV.xcu create mode 100644 filter/source/config/fragments/filters/writer8.xcu create mode 100644 filter/source/config/fragments/filters/writer8_template.xcu create mode 100644 filter/source/config/fragments/filters/writer_MIZI_Hwp_97.xcu create mode 100644 filter/source/config/fragments/filters/writer_StarOffice_XML_Writer_Template.xcu create mode 100644 filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer.xcu create mode 100644 filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu create mode 100644 filter/source/config/fragments/filters/writer_globaldocument_pdf_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_indexing_export.xcu create mode 100644 filter/source/config/fragments/filters/writer_jpg_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_layout_dump.xcu create mode 100644 filter/source/config/fragments/filters/writer_pdf_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_png_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_svg_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_web_HTML_help.xcu create mode 100644 filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer.xcu create mode 100644 filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer_Web_Template.xcu create mode 100644 filter/source/config/fragments/filters/writer_web_jpg_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_web_pdf_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_web_png_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_web_webp_Export.xcu create mode 100644 filter/source/config/fragments/filters/writer_webp_Export.xcu create mode 100644 filter/source/config/fragments/filters/writerglobal8.xcu create mode 100644 filter/source/config/fragments/filters/writerglobal8_HTML.xcu create mode 100644 filter/source/config/fragments/filters/writerglobal8_template.xcu create mode 100644 filter/source/config/fragments/filters/writerglobal8_writer.xcu create mode 100644 filter/source/config/fragments/filters/writerweb8_writer.xcu create mode 100644 filter/source/config/fragments/filters/writerweb8_writer_template.xcu create mode 100644 filter/source/config/fragments/frameloaders/com_sun_star_comp_chart2_ChartFrameLoader.xcu create mode 100644 filter/source/config/fragments/frameloaders/com_sun_star_frame_Bibliography.xcu create mode 100644 filter/source/config/fragments/frameloaders/com_sun_star_sdb_ContentLoader.xcu create mode 100644 filter/source/config/fragments/frameloaders/org_openoffice_comp_dbflt_DBContentLoader2.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/bmp_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/bmp_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/dxf_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/emf_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/emf_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/eps_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/eps_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/gif_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/gif_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/jpg_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/jpg_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/met_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/mov_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pbm_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base16.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base4.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pct_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pcx_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pdf_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pdf_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/pgm_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/png_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/png_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/ppm_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/psd_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/ras_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/svg_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/svg_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/svm_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/svm_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/tga_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/tif_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/tif_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/webp_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/webp_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/wmf_Export.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/wmf_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/xbm_Import.xcu create mode 100644 filter/source/config/fragments/internalgraphicfilters/xpm_Import.xcu create mode 100644 filter/source/config/fragments/langfilter.xsl create mode 100644 filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu create mode 100644 filter/source/config/fragments/types/MS_Excel_2007_VBA_XML.xcu create mode 100644 filter/source/config/fragments/types/MS_Excel_2007_XML.xcu create mode 100644 filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu create mode 100644 filter/source/config/fragments/types/MS_PowerPoint_2007_XML.xcu create mode 100644 filter/source/config/fragments/types/MS_PowerPoint_2007_XML_AutoPlay.xcu create mode 100644 filter/source/config/fragments/types/MS_PowerPoint_2007_XML_Template.xcu create mode 100644 filter/source/config/fragments/types/MS_PowerPoint_2007_XML_VBA.xcu create mode 100644 filter/source/config/fragments/types/MWAW_Bitmap.xcu create mode 100644 filter/source/config/fragments/types/MWAW_Database.xcu create mode 100644 filter/source/config/fragments/types/MWAW_Drawing.xcu create mode 100644 filter/source/config/fragments/types/MWAW_Presentation.xcu create mode 100644 filter/source/config/fragments/types/MWAW_Spreadsheet.xcu create mode 100644 filter/source/config/fragments/types/MWAW_Text_Document.xcu create mode 100644 filter/source/config/fragments/types/Palm_Text_Document.xcu create mode 100644 filter/source/config/fragments/types/StarBase.xcu create mode 100644 filter/source/config/fragments/types/StarBaseReport.xcu create mode 100644 filter/source/config/fragments/types/StarBaseReportChart.xcu create mode 100644 filter/source/config/fragments/types/StarOffice_Drawing.xcu create mode 100644 filter/source/config/fragments/types/StarOffice_Presentation.xcu create mode 100644 filter/source/config/fragments/types/StarOffice_Spreadsheet.xcu create mode 100644 filter/source/config/fragments/types/StarOffice_Writer.xcu create mode 100644 filter/source/config/fragments/types/Unified_Office_Format_presentation.xcu create mode 100644 filter/source/config/fragments/types/Unified_Office_Format_spreadsheet.xcu create mode 100644 filter/source/config/fragments/types/Unified_Office_Format_text.xcu create mode 100644 filter/source/config/fragments/types/XHTML_File.xcu create mode 100644 filter/source/config/fragments/types/bmp_MS_Windows.xcu create mode 100644 filter/source/config/fragments/types/calc8.xcu create mode 100644 filter/source/config/fragments/types/calc8_template.xcu create mode 100644 filter/source/config/fragments/types/calc_ADO_rowset_XML.xcu create mode 100644 filter/source/config/fragments/types/calc_AppleNumbers.xcu create mode 100644 filter/source/config/fragments/types/calc_ClarisWorks.xcu create mode 100644 filter/source/config/fragments/types/calc_Claris_Resolve.xcu create mode 100644 filter/source/config/fragments/types/calc_DIF.xcu create mode 100644 filter/source/config/fragments/types/calc_Gnumeric.xcu create mode 100644 filter/source/config/fragments/types/calc_HTML.xcu create mode 100644 filter/source/config/fragments/types/calc_Lotus.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_2003_XML.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_40.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_40_VorlageTemplate.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_5095.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_5095_VorlageTemplate.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_95.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_95_VorlageTemplate.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_97.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Excel_97_VorlageTemplate.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Multiplan.xcu create mode 100644 filter/source/config/fragments/types/calc_MS_Works_Document.xcu create mode 100644 filter/source/config/fragments/types/calc_Mac_Works.xcu create mode 100644 filter/source/config/fragments/types/calc_ODS_FlatXML.xcu create mode 100644 filter/source/config/fragments/types/calc_OOXML.xcu create mode 100644 filter/source/config/fragments/types/calc_OOXML_Template.xcu create mode 100644 filter/source/config/fragments/types/calc_QPro.xcu create mode 100644 filter/source/config/fragments/types/calc_SYLK.xcu create mode 100644 filter/source/config/fragments/types/calc_StarOffice_XML_Calc.xcu create mode 100644 filter/source/config/fragments/types/calc_StarOffice_XML_Calc_Template.xcu create mode 100644 filter/source/config/fragments/types/calc_WPS_Lotus_Document.xcu create mode 100644 filter/source/config/fragments/types/calc_WPS_QPro_Document.xcu create mode 100644 filter/source/config/fragments/types/calc_dBase.xcu create mode 100644 filter/source/config/fragments/types/chart8.xcu create mode 100644 filter/source/config/fragments/types/chart_StarOffice_XML_Chart.xcu create mode 100644 filter/source/config/fragments/types/component_Bibliography.xcu create mode 100644 filter/source/config/fragments/types/component_DB.xcu create mode 100644 filter/source/config/fragments/types/draw8.xcu create mode 100644 filter/source/config/fragments/types/draw8_template.xcu create mode 100644 filter/source/config/fragments/types/draw_ClarisWorks.xcu create mode 100644 filter/source/config/fragments/types/draw_CorelDraw_Document.xcu create mode 100644 filter/source/config/fragments/types/draw_Corel_Presentation_Exchange.xcu create mode 100644 filter/source/config/fragments/types/draw_Freehand_Document.xcu create mode 100644 filter/source/config/fragments/types/draw_ODG_FlatXML.xcu create mode 100644 filter/source/config/fragments/types/draw_PageMaker_Document.xcu create mode 100644 filter/source/config/fragments/types/draw_Publisher_Document.xcu create mode 100644 filter/source/config/fragments/types/draw_QXP_Document.xcu create mode 100644 filter/source/config/fragments/types/draw_StarOffice_XML_Draw.xcu create mode 100644 filter/source/config/fragments/types/draw_StarOffice_XML_Draw_Template.xcu create mode 100644 filter/source/config/fragments/types/draw_Visio_Document.xcu create mode 100644 filter/source/config/fragments/types/draw_WordPerfect_Graphics.xcu create mode 100644 filter/source/config/fragments/types/draw_ZMF_Document.xcu create mode 100644 filter/source/config/fragments/types/dxf_AutoCAD_Interchange.xcu create mode 100644 filter/source/config/fragments/types/emf_MS_Windows_Metafile.xcu create mode 100644 filter/source/config/fragments/types/eps_Encapsulated_PostScript.xcu create mode 100644 filter/source/config/fragments/types/generic_HTML.xcu create mode 100644 filter/source/config/fragments/types/generic_Text.xcu create mode 100644 filter/source/config/fragments/types/gif_Graphics_Interchange.xcu create mode 100644 filter/source/config/fragments/types/graphic_HTML.xcu create mode 100644 filter/source/config/fragments/types/impress8.xcu create mode 100644 filter/source/config/fragments/types/impress8_template.xcu create mode 100644 filter/source/config/fragments/types/impress_AppleKeynote.xcu create mode 100644 filter/source/config/fragments/types/impress_CGM_Computer_Graphics_Metafile.xcu create mode 100644 filter/source/config/fragments/types/impress_ClarisWorks.xcu create mode 100644 filter/source/config/fragments/types/impress_MS_PowerPoint_97.xcu create mode 100644 filter/source/config/fragments/types/impress_MS_PowerPoint_97_AutoPlay.xcu create mode 100644 filter/source/config/fragments/types/impress_MS_PowerPoint_97_Vorlage.xcu create mode 100644 filter/source/config/fragments/types/impress_ODP_FlatXML.xcu create mode 100644 filter/source/config/fragments/types/impress_OOXML_Presentation.xcu create mode 100644 filter/source/config/fragments/types/impress_OOXML_Presentation_AutoPlay.xcu create mode 100644 filter/source/config/fragments/types/impress_OOXML_Presentation_Template.xcu create mode 100644 filter/source/config/fragments/types/impress_PowerPoint3.xcu create mode 100644 filter/source/config/fragments/types/impress_StarOffice_XML_Impress.xcu create mode 100644 filter/source/config/fragments/types/impress_StarOffice_XML_Impress_Template.xcu create mode 100644 filter/source/config/fragments/types/jpg_JPEG.xcu create mode 100644 filter/source/config/fragments/types/math8.xcu create mode 100644 filter/source/config/fragments/types/math_MathML_XML_Math.xcu create mode 100644 filter/source/config/fragments/types/math_MathType_3x.xcu create mode 100644 filter/source/config/fragments/types/math_StarOffice_XML_Math.xcu create mode 100644 filter/source/config/fragments/types/met_OS2_Metafile.xcu create mode 100644 filter/source/config/fragments/types/mov_MOV.xcu create mode 100644 filter/source/config/fragments/types/oxt_OpenOffice_Extension.xcu create mode 100644 filter/source/config/fragments/types/pbm_Portable_Bitmap.xcu create mode 100644 filter/source/config/fragments/types/pcd_Photo_CD_Base.xcu create mode 100644 filter/source/config/fragments/types/pcd_Photo_CD_Base16.xcu create mode 100644 filter/source/config/fragments/types/pcd_Photo_CD_Base4.xcu create mode 100644 filter/source/config/fragments/types/pct_Mac_Pict.xcu create mode 100644 filter/source/config/fragments/types/pcx_Zsoft_Paintbrush.xcu create mode 100644 filter/source/config/fragments/types/pdf_Portable_Document_Format.xcu create mode 100644 filter/source/config/fragments/types/pgm_Portable_Graymap.xcu create mode 100644 filter/source/config/fragments/types/png_Portable_Network_Graphic.xcu create mode 100644 filter/source/config/fragments/types/ppm_Portable_Pixelmap.xcu create mode 100644 filter/source/config/fragments/types/psd_Adobe_Photoshop.xcu create mode 100644 filter/source/config/fragments/types/ras_Sun_Rasterfile.xcu create mode 100644 filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu create mode 100644 filter/source/config/fragments/types/svg_Scalable_Vector_Graphics_Draw.xcu create mode 100644 filter/source/config/fragments/types/svm_StarView_Metafile.xcu create mode 100644 filter/source/config/fragments/types/tga_Truevision_TARGA.xcu create mode 100644 filter/source/config/fragments/types/tif_Tag_Image_File.xcu create mode 100644 filter/source/config/fragments/types/wav_Wave_Audio_File.xcu create mode 100644 filter/source/config/fragments/types/webp_WebP.xcu create mode 100644 filter/source/config/fragments/types/wmf_MS_Windows_Metafile.xcu create mode 100644 filter/source/config/fragments/types/writer8.xcu create mode 100644 filter/source/config/fragments/types/writer8_template.xcu create mode 100644 filter/source/config/fragments/types/writer_AbiWord_Document.xcu create mode 100644 filter/source/config/fragments/types/writer_ApplePages.xcu create mode 100644 filter/source/config/fragments/types/writer_BroadBand_eBook.xcu create mode 100644 filter/source/config/fragments/types/writer_ClarisWorks.xcu create mode 100644 filter/source/config/fragments/types/writer_DocBook_File.xcu create mode 100644 filter/source/config/fragments/types/writer_DosWord.xcu create mode 100644 filter/source/config/fragments/types/writer_EPUB_Document.xcu create mode 100644 filter/source/config/fragments/types/writer_FictionBook_2.xcu create mode 100644 filter/source/config/fragments/types/writer_LotusWordPro_Document.xcu create mode 100644 filter/source/config/fragments/types/writer_MIZI_Hwp_97.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_WinWord_5.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_WinWord_60.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_2003_XML.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_2007_XML.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_2007_XML_Template.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_2007_XML_VBA.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_95.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_95_Vorlage.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_97.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Word_97_Vorlage.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Works_Document.xcu create mode 100644 filter/source/config/fragments/types/writer_MS_Write.xcu create mode 100644 filter/source/config/fragments/types/writer_MacWrite.xcu create mode 100644 filter/source/config/fragments/types/writer_Mac_Word.xcu create mode 100644 filter/source/config/fragments/types/writer_Mac_Works.xcu create mode 100644 filter/source/config/fragments/types/writer_Mariner_Write.xcu create mode 100644 filter/source/config/fragments/types/writer_ODT_FlatXML.xcu create mode 100644 filter/source/config/fragments/types/writer_OOXML.xcu create mode 100644 filter/source/config/fragments/types/writer_OOXML_Template.xcu create mode 100644 filter/source/config/fragments/types/writer_PalmDoc.xcu create mode 100644 filter/source/config/fragments/types/writer_Plucker_eBook.xcu create mode 100644 filter/source/config/fragments/types/writer_PocketWord_File.xcu create mode 100644 filter/source/config/fragments/types/writer_Rich_Text_Format.xcu create mode 100644 filter/source/config/fragments/types/writer_StarOffice_XML_Writer.xcu create mode 100644 filter/source/config/fragments/types/writer_StarOffice_XML_Writer_Template.xcu create mode 100644 filter/source/config/fragments/types/writer_T602_Document.xcu create mode 100644 filter/source/config/fragments/types/writer_WordPerfect_Document.xcu create mode 100644 filter/source/config/fragments/types/writer_WriteNow.xcu create mode 100644 filter/source/config/fragments/types/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu create mode 100644 filter/source/config/fragments/types/writer_indexing_export_xml.xcu create mode 100644 filter/source/config/fragments/types/writer_layout_dump_xml.xcu create mode 100644 filter/source/config/fragments/types/writer_web_HTML_help.xcu create mode 100644 filter/source/config/fragments/types/writer_web_StarOffice_XML_Writer_Web_Template.xcu create mode 100644 filter/source/config/fragments/types/writerglobal8.xcu create mode 100644 filter/source/config/fragments/types/writerglobal8_template.xcu create mode 100644 filter/source/config/fragments/types/writerweb8_writer_template.xcu create mode 100644 filter/source/config/fragments/types/xbm_X_Consortium.xcu create mode 100644 filter/source/config/fragments/types/xpm_XPM.xcu create mode 100644 filter/source/config/tools/merge/FCFGMerge.cfg create mode 100755 filter/source/config/tools/merge/pyAltFCFGMerge create mode 100644 filter/source/docbook/DocBookTemplate.stw create mode 100644 filter/source/docbook/docbooktosoffheadings.xsl create mode 100644 filter/source/docbook/sofftodocbookheadings.xsl create mode 100644 filter/source/graphic/GraphicExportFilter.cxx create mode 100644 filter/source/graphic/GraphicExportFilter.hxx create mode 100644 filter/source/graphic/graphicfilter.component create mode 100644 filter/source/graphicfilter/icgm/actimpr.cxx create mode 100644 filter/source/graphicfilter/icgm/bitmap.cxx create mode 100644 filter/source/graphicfilter/icgm/bitmap.hxx create mode 100644 filter/source/graphicfilter/icgm/bundles.cxx create mode 100644 filter/source/graphicfilter/icgm/bundles.hxx create mode 100644 filter/source/graphicfilter/icgm/cgm.cxx create mode 100644 filter/source/graphicfilter/icgm/cgm.hxx create mode 100644 filter/source/graphicfilter/icgm/cgmtypes.hxx create mode 100644 filter/source/graphicfilter/icgm/chart.cxx create mode 100644 filter/source/graphicfilter/icgm/chart.hxx create mode 100644 filter/source/graphicfilter/icgm/class0.cxx create mode 100644 filter/source/graphicfilter/icgm/class1.cxx create mode 100644 filter/source/graphicfilter/icgm/class2.cxx create mode 100644 filter/source/graphicfilter/icgm/class3.cxx create mode 100644 filter/source/graphicfilter/icgm/class4.cxx create mode 100644 filter/source/graphicfilter/icgm/class5.cxx create mode 100644 filter/source/graphicfilter/icgm/class7.cxx create mode 100644 filter/source/graphicfilter/icgm/classx.cxx create mode 100644 filter/source/graphicfilter/icgm/elements.cxx create mode 100644 filter/source/graphicfilter/icgm/elements.hxx create mode 100644 filter/source/graphicfilter/icgm/outact.hxx create mode 100644 filter/source/msfilter/countryid.cxx create mode 100644 filter/source/msfilter/dffpropset.cxx create mode 100644 filter/source/msfilter/dffrecordheader.cxx create mode 100644 filter/source/msfilter/escherex.cxx create mode 100644 filter/source/msfilter/eschesdo.cxx create mode 100644 filter/source/msfilter/eschesdo.hxx create mode 100644 filter/source/msfilter/mscodec.cxx create mode 100644 filter/source/msfilter/msdffimp.cxx create mode 100644 filter/source/msfilter/msfilter.component create mode 100644 filter/source/msfilter/msocximex.cxx create mode 100644 filter/source/msfilter/msoleexp.cxx create mode 100644 filter/source/msfilter/mstoolbar.cxx create mode 100644 filter/source/msfilter/msvbahelper.cxx create mode 100644 filter/source/msfilter/rtfutil.cxx create mode 100644 filter/source/msfilter/svdfppt.cxx create mode 100644 filter/source/msfilter/svxmsbas2.cxx create mode 100644 filter/source/msfilter/util.cxx create mode 100644 filter/source/msfilter/viscache.hxx create mode 100644 filter/source/odfflatxml/OdfFlatXml.cxx create mode 100644 filter/source/odfflatxml/odfflatxml.component create mode 100644 filter/source/pdf/impdialog.cxx create mode 100644 filter/source/pdf/impdialog.hxx create mode 100644 filter/source/pdf/pdfdecomposer.cxx create mode 100644 filter/source/pdf/pdfdialog.cxx create mode 100644 filter/source/pdf/pdfdialog.hxx create mode 100644 filter/source/pdf/pdfexport.cxx create mode 100644 filter/source/pdf/pdfexport.hxx create mode 100644 filter/source/pdf/pdffilter.component create mode 100644 filter/source/pdf/pdffilter.cxx create mode 100644 filter/source/pdf/pdffilter.hxx create mode 100644 filter/source/pdf/pdfinteract.cxx create mode 100644 filter/source/pdf/pdfinteract.hxx create mode 100644 filter/source/storagefilterdetect/filterdetect.cxx create mode 100644 filter/source/storagefilterdetect/filterdetect.hxx create mode 100644 filter/source/storagefilterdetect/storagefd.component create mode 100644 filter/source/svg/.eslintrc.js create mode 100644 filter/source/svg/gentoken.py create mode 100755 filter/source/svg/js2hxx.py create mode 100644 filter/source/svg/presentation_engine.js create mode 100644 filter/source/svg/svgexport.cxx create mode 100644 filter/source/svg/svgfilter.component create mode 100644 filter/source/svg/svgfilter.cxx create mode 100644 filter/source/svg/svgfilter.hxx create mode 100644 filter/source/svg/svgfontexport.cxx create mode 100644 filter/source/svg/svgfontexport.hxx create mode 100644 filter/source/svg/svgwriter.cxx create mode 100644 filter/source/svg/svgwriter.hxx create mode 100644 filter/source/svg/test/odfserializer.cxx create mode 100644 filter/source/svg/test/odfserializer.hxx create mode 100644 filter/source/svg/tokens.txt create mode 100644 filter/source/t602/t602filter.component create mode 100644 filter/source/t602/t602filter.cxx create mode 100644 filter/source/t602/t602filter.hxx create mode 100644 filter/source/textfilterdetect/filterdetect.cxx create mode 100644 filter/source/textfilterdetect/filterdetect.hxx create mode 100644 filter/source/textfilterdetect/textfd.component create mode 100644 filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx create mode 100644 filter/source/xmlfilteradaptor/XmlFilterAdaptor.hxx create mode 100644 filter/source/xmlfilteradaptor/xmlfa.component create mode 100644 filter/source/xmlfilterdetect/filterdetect.cxx create mode 100644 filter/source/xmlfilterdetect/filterdetect.hxx create mode 100644 filter/source/xmlfilterdetect/xmlfd.component create mode 100644 filter/source/xslt/common/copy.xsl create mode 100644 filter/source/xslt/common/math.xsl create mode 100644 filter/source/xslt/common/measure_conversion.xsl create mode 100644 filter/source/xslt/export/common/ooo2ms_docpr.xsl create mode 100644 filter/source/xslt/export/spreadsheetml/formular.xsl create mode 100644 filter/source/xslt/export/spreadsheetml/ooo2spreadsheetml.xsl create mode 100644 filter/source/xslt/export/spreadsheetml/style_mapping.xsl create mode 100644 filter/source/xslt/export/spreadsheetml/styles.xsl create mode 100644 filter/source/xslt/export/spreadsheetml/table.xsl create mode 100644 filter/source/xslt/export/uof/odf2uof_presentation.xsl create mode 100644 filter/source/xslt/export/uof/odf2uof_spreadsheet.xsl create mode 100644 filter/source/xslt/export/uof/odf2uof_text.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_border.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_custom_draw.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_draw.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_field.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_list.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_page.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_path.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_settings.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_table.xsl create mode 100644 filter/source/xslt/export/wordml/ooo2wordml_text.xsl create mode 100644 filter/source/xslt/import/common/ms2ooo_docpr.xsl create mode 100644 filter/source/xslt/import/spreadsheetml/adorowset2ods.xsl create mode 100644 filter/source/xslt/import/spreadsheetml/spreadsheetml2ooo.xsl create mode 100644 filter/source/xslt/import/uof/uof2odf_presentation.xsl create mode 100644 filter/source/xslt/import/uof/uof2odf_spreadsheet.xsl create mode 100644 filter/source/xslt/import/uof/uof2odf_text.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_custom_draw.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_draw.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_field.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_list.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_page.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_path.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_props.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_settings.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_table.xsl create mode 100644 filter/source/xslt/import/wordml/wordml2ooo_text.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/body.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/styles/style_collector.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/styles/style_mapping_css.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/table/table.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/table/table_cells.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/table/table_columns.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/table/table_rows.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/common/table_of_content.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/xhtml/body.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/xhtml/header.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/xhtml/opendoc2xhtml.xsl create mode 100644 filter/source/xslt/odf2xhtml/export/xhtml/table.xsl create mode 100644 filter/source/xsltdialog/typedetectionexport.cxx create mode 100644 filter/source/xsltdialog/typedetectionexport.hxx create mode 100644 filter/source/xsltdialog/typedetectionimport.cxx create mode 100644 filter/source/xsltdialog/typedetectionimport.hxx create mode 100644 filter/source/xsltdialog/xmlfiltercommon.hxx create mode 100644 filter/source/xsltdialog/xmlfilterdialogcomponent.cxx create mode 100644 filter/source/xsltdialog/xmlfilterjar.cxx create mode 100644 filter/source/xsltdialog/xmlfilterjar.hxx create mode 100644 filter/source/xsltdialog/xmlfiltersettingsdialog.cxx create mode 100644 filter/source/xsltdialog/xmlfiltersettingsdialog.hxx create mode 100644 filter/source/xsltdialog/xmlfiltertabdialog.cxx create mode 100644 filter/source/xsltdialog/xmlfiltertabdialog.hxx create mode 100644 filter/source/xsltdialog/xmlfiltertabpagebasic.cxx create mode 100644 filter/source/xsltdialog/xmlfiltertabpagebasic.hxx create mode 100644 filter/source/xsltdialog/xmlfiltertabpagexslt.cxx create mode 100644 filter/source/xsltdialog/xmlfiltertabpagexslt.hxx create mode 100644 filter/source/xsltdialog/xmlfiltertestdialog.cxx create mode 100644 filter/source/xsltdialog/xmlfiltertestdialog.hxx create mode 100644 filter/source/xsltdialog/xsltdlg.component create mode 100644 filter/source/xsltfilter/LibXSLTTransformer.cxx create mode 100644 filter/source/xsltfilter/LibXSLTTransformer.hxx create mode 100644 filter/source/xsltfilter/OleHandler.cxx create mode 100644 filter/source/xsltfilter/OleHandler.hxx create mode 100644 filter/source/xsltfilter/XSLTFilter.cxx create mode 100644 filter/source/xsltfilter/xsltfilter.component create mode 100644 filter/uiconfig/ui/pdfgeneralpage.ui create mode 100644 filter/uiconfig/ui/pdflinkspage.ui create mode 100644 filter/uiconfig/ui/pdfoptionsdialog.ui create mode 100644 filter/uiconfig/ui/pdfsecuritypage.ui create mode 100644 filter/uiconfig/ui/pdfsignpage.ui create mode 100644 filter/uiconfig/ui/pdfuserinterfacepage.ui create mode 100644 filter/uiconfig/ui/pdfviewpage.ui create mode 100644 filter/uiconfig/ui/testxmlfilter.ui create mode 100644 filter/uiconfig/ui/warnpdfdialog.ui create mode 100644 filter/uiconfig/ui/xmlfiltersettings.ui create mode 100644 filter/uiconfig/ui/xmlfiltertabpagegeneral.ui create mode 100644 filter/uiconfig/ui/xmlfiltertabpagetransformation.ui create mode 100644 filter/uiconfig/ui/xsltfilterdialog.ui (limited to 'filter') diff --git a/filter/AllLangMoTarget_flt.mk b/filter/AllLangMoTarget_flt.mk new file mode 100644 index 000000000..3c491bc95 --- /dev/null +++ b/filter/AllLangMoTarget_flt.mk @@ -0,0 +1,13 @@ +# -*- 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/. + +$(eval $(call gb_AllLangMoTarget_AllLangMoTarget,flt)) + +$(eval $(call gb_AllLangMoTarget_set_polocation,flt,filter)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Configuration_filter.mk b/filter/Configuration_filter.mk new file mode 100644 index 000000000..a58b8396c --- /dev/null +++ b/filter/Configuration_filter.mk @@ -0,0 +1,934 @@ +# +# 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 . +# + +# this deviates from Configuration.mk in rather bizarre ways + +# most of the rules here use some weird merge program, and this is sort of +# semi-integrated with the stuff from Configuration.mk; not exactly pretty... + +filter_MERGE_TARGET := $(call gb_ExternalExecutable_get_dependencies,python) \ + $(SRCDIR)/filter/source/config/tools/merge/pyAltFCFGMerge +filter_MERGE := $(call gb_ExternalExecutable_get_command,python) \ + $(SRCDIR)/filter/source/config/tools/merge/pyAltFCFGMerge \ + $(if $(verbose),-verbose) + +### filter configuration rules: generic stuff ####################### + +### types + +filter_XcuFilterTypesTarget_get_clean_target = \ + $(WORKDIR)/Clean/XcuFilterTypesTarget/$(1) + +$(call gb_XcuFilterTypesTarget_get_target,%) : $(filter_MERGE_TARGET) + $(call gb_Output_announce,$*,$(true),FIT,1) + $(call gb_Trace_StartRange,$*,FIT) + $(call gb_Helper_abbreviate_dirs,\ + mkdir -p $(dir $@) && \ + RESPONSEFILE=`$(gb_MKTEMP)` && \ + echo "items=$(basename $(notdir $(filter %.xcu,$^)))" \ + | sed "s/ /$(COMMA)/g" > $${RESPONSEFILE} && \ + $(filter_MERGE) tempdir=$(TMPDIR) \ + share_subdir_name=$(LIBO_SHARE_FOLDER) \ + fragmentsdir=$(dir $(firstword $(filter %.xcu,$^))).. \ + outdir=$(dir $@) pkg=$@ xmlpackage=Types tcfg=$${RESPONSEFILE} && \ + rm -f $${RESPONSEFILE}) + $(call gb_Trace_EndRange,$*,FIT) + +$(call filter_XcuFilterTypesTarget_get_clean_target,%) : + $(call gb_Output_announce,$*,$(false),FIT,1) + rm -f $(call gb_XcuFilterTypesTarget_get_target,$*) + +# $(call filter_Configuration__add_module,configuration,module,prefix,xcufiles,target,cleantarget) +define filter_Configuration__add_module +$(call gb_Configuration_get_target,$(1)) : $(5) +$(call gb_Configuration_get_clean_target,$(1)) : $(6) +$(if $(4),,$(error filter_Configuration__add_module: no input files)) +$(5) : \ + $(addprefix $(SRCDIR)/$(3)/,$(addsuffix .xcu,$(4))) \ + $(gb_Module_CURRENTMAKEFILE) + +endef + +# $(call filter_Configuration_add_types,configuration,typesfile,prefix,xcufiles) +define filter_Configuration_add_types +$(call filter_Configuration__add_module,$(1),$(2),$(3),$(4),\ + $(call gb_XcuFilterTypesTarget_get_target,$(2)),\ + $(call filter_XcuFilterTypesTarget_get_clean_target,$(2))) + +endef + +### filters + +filter_XcuFilterFiltersTarget_get_clean_target = \ + $(WORKDIR)/Clean/XcuFilterFiltersTarget/$(1) + +$(call gb_XcuFilterFiltersTarget_get_target,%) : $(filter_MERGE_TARGET) + $(call gb_Output_announce,$*,$(true),FIF,1) + $(call gb_Trace_StartRange,$*,FIF) + $(call gb_Helper_abbreviate_dirs,\ + mkdir -p $(dir $@) && \ + RESPONSEFILE=`$(gb_MKTEMP)` && \ + echo "items=$(basename $(notdir $(filter %.xcu,$^)))" \ + | sed "s/ /$(COMMA)/g" > $${RESPONSEFILE} && \ + $(filter_MERGE) tempdir=$(TMPDIR) \ + share_subdir_name=$(LIBO_SHARE_FOLDER) \ + fragmentsdir=$(dir $(firstword $(filter %.xcu,$^))).. \ + outdir=$(dir $@) pkg=$@ xmlpackage=Filter fcfg=$${RESPONSEFILE} && \ + rm -f $${RESPONSEFILE}) + $(call gb_Trace_EndRange,$*,FIF) + +$(call filter_XcuFilterFiltersTarget_get_clean_target,%) : + $(call gb_Output_announce,$*,$(false),FIF,1) + rm -f $(call gb_XcuFilterFiltersTarget_get_target,$*) + +# $(call filter_Configuration_add_filters,configuration,typesfile,prefix,xcufiles) +define filter_Configuration_add_filters +$(call filter_Configuration__add_module,$(1),$(2),$(3),$(4),\ + $(call gb_XcuFilterFiltersTarget_get_target,$(2)),\ + $(call filter_XcuFilterFiltersTarget_get_clean_target,$(2))) +$(call filter_Configuration_add_ui_filters,$(1),$(3),$(4)) + +endef + +### others (frameloaders, contenthandlers) + +filter_XcuFilterOthersTarget_get_clean_target = \ + $(WORKDIR)/Clean/XcuFilterOthersTarget/$(1) + +$(call gb_XcuFilterOthersTarget_get_target,%) : $(filter_MERGE_TARGET) + $(call gb_Output_announce,$*,$(true),FIO,1) + $(call gb_Trace_StartRange,$*,FIO) + $(call gb_Helper_abbreviate_dirs,\ + mkdir -p $(dir $@) && \ + RESPONSEFILE=`$(gb_MKTEMP)` && \ + RESPONSEFILE2=`$(gb_MKTEMP)` && \ + echo "items=$(strip $(foreach xcu,$(filter %.xcu,$^),$(if $(filter frameloaders,$(notdir $(patsubst %/,%,$(dir $(xcu))))),$(basename $(notdir $(xcu),)))))" \ + | sed "s/ /$(COMMA)/g" > $${RESPONSEFILE} && \ + echo "items=$(strip $(foreach xcu,$(filter %.xcu,$^),$(if $(filter contenthandlers,$(notdir $(patsubst %/,%,$(dir $(xcu))))),$(basename $(notdir $(xcu),)))))" \ + | sed "s/ /$(COMMA)/g" > $${RESPONSEFILE2} && \ + $(filter_MERGE) tempdir=$(TMPDIR) \ + share_subdir_name=$(LIBO_SHARE_FOLDER) \ + fragmentsdir=$(dir $(firstword $(filter %.xcu,$^))).. \ + outdir=$(dir $@) pkg=$@ xmlpackage=Misc \ + lcfg=$${RESPONSEFILE} ccfg=$${RESPONSEFILE2} && \ + rm -f $${RESPONSEFILE} $${RESPONSEFILE2}) + $(call gb_Trace_EndRange,$*,FIO) + +$(call filter_XcuFilterOthersTarget_get_clean_target,%) : + $(call gb_Output_announce,$*,$(false),FIO,1) + rm -f $(call gb_XcuFilterOthersTarget_get_target,$*) + +# $(call filter_Configuration_add_others,configuration,typesfile,prefix,xcufiles) +define filter_Configuration_add_others +$(call filter_Configuration__add_module,$(1),$(2),$(3),$(4),\ + $(call gb_XcuFilterOthersTarget_get_target,$(2)),\ + $(call filter_XcuFilterOthersTarget_get_clean_target,$(2))) + +endef + +### internal filters + +filter_XcuFilterInternalTarget_get_clean_target = \ + $(WORKDIR)/Clean/XcuFilterInternalTarget/$(1) + +$(call gb_XcuFilterInternalTarget_get_target,%) : $(filter_MERGE_TARGET) + $(call gb_Output_announce,$*,$(true),FII,1) + $(call gb_Trace_StartRange,$*,FII) + $(call gb_Helper_abbreviate_dirs,\ + mkdir -p $(dir $@) && \ + RESPONSEFILE=`$(gb_MKTEMP)` && \ + echo "items=$(basename $(notdir $(filter %.xcu,$^)))" \ + | sed "s/ /$(COMMA)/g" > $${RESPONSEFILE} && \ + $(filter_MERGE) tempdir=$(TMPDIR) \ + share_subdir_name=$(LIBO_SHARE_FOLDER) \ + fragmentsdir=$(dir $(firstword $(filter %.xcu,$^))).. \ + outdir=$(dir $@) pkg=$@ xmlpackage=GraphicFilter \ + fcfg=$${RESPONSEFILE} subdir_filters=internalgraphicfilters && \ + rm -f $${RESPONSEFILE}) + $(call gb_Trace_EndRange,$*,FII) + +$(call filter_XcuFilterInternalTarget_get_clean_target,%) : + $(call gb_Output_announce,$*,$(false),FII,1) + rm -f $(call gb_XcuFilterInternalTarget_get_target,$*) + +# $(call filter_Configuration_add_internal_filters,configuration,typesfile,prefix,xcufiles) +define filter_Configuration_add_internal_filters +$(call filter_Configuration__add_module,$(1),$(2),$(3),$(4),\ + $(call gb_XcuFilterInternalTarget_get_target,$(2)),\ + $(call filter_XcuFilterInternalTarget_get_clean_target,$(2))) + +endef + + +### filter configuration rules: l10n stuff: ######################### + +# Configuration fcfg_langpack +# => $(lang)/org/openoffice/TypeDetection/Filter.xcu +# xslt=> filter_ui.xcu +# merge=> *.xcu $(ALL_UI_FILTERS) [if WITH_LANG] +# cfgex=> source/%.xcu +# merge=> source/*.xcu [if !WITH_LANG] + +filter_XSLT_langfilter := \ + $(SRCDIR)/filter/source/config/fragments/langfilter.xsl +filter_XcuFilterUiTarget = $(WORKDIR)/XcuFilterUiTarget/filter_ui.xcu +filter_XcuFilterUiCleanTarget = $(WORKDIR)/Clean/XcuFilterUiTarget/filter_ui.xcu +filter_XCU_filter := org/openoffice/TypeDetection/Filter.xcu +filter_XcuResTarget_get_target = \ + $(call gb_XcuResTarget_get_target,fcfg_langpack/$(1)/$(filter_XCU_filter)) +filter_XcuResTarget_get_clean_target = \ + $(call gb_XcuResTarget_get_clean_target,fcfg_langpack/$(1)/$(filter_XCU_filter)) + +$(filter_XcuFilterUiTarget) : $(filter_MERGE_TARGET) + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),FIU,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),FIU) + $(call gb_Helper_abbreviate_dirs,\ + mkdir -p $(dir $@) && \ + RESPONSEFILE=`$(gb_MKTEMP)` && \ + echo "items=$(basename $(notdir $(filter %.xcu,$^)))" \ + | sed "s/ /$(COMMA)/g" > $${RESPONSEFILE} && \ + $(filter_MERGE) tempdir=$(TMPDIR) \ + share_subdir_name=$(LIBO_SHARE_FOLDER) \ + fragmentsdir=$(dir $(firstword $(filter %.xcu,$^))).. \ + pkg=$@ xmlpackage=Filter fcfg=$${RESPONSEFILE} languagepack=true \ + && rm -f $${RESPONSEFILE}) + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),FIU) + +$(filter_XcuFilterUiCleanTarget) : + $(call gb_Output_announce,$(filter_XcuFilterUiTarget),$(false),FIU,1) + $(call gb_Helper_abbreviate_dirs,\ + rm -f $(filter_XcuFilterUiTarget)) + +$(call gb_Configuration_get_clean_target,fcfg_langpack) : \ + $(filter_XcuFilterUiCleanTarget) + +# this is _not_ a pattern rule: +# there is already a pattern rule for gb_XcuResTarget_get_target, +# so generate non-pattern rules which have higher priority even in GNUmake 3.81 +define filter_XcuResTarget__rule +$$(call filter_XcuResTarget_get_target,$(1)) : \ + $(filter_XSLT_langfilter) $(filter_XcuFilterUiTarget) \ + | $(call gb_ExternalExecutable_get_dependencies,xsltproc) + $$(call gb_Output_announce,$(1),$(true),XCU,1) + $$(call gb_Trace_StartRange,$(1),XCU) + $$(call gb_Helper_abbreviate_dirs,\ + mkdir -p $$(dir $$@) && \ + $(subst $$,$$$$,$(call gb_ExternalExecutable_get_command,xsltproc)) --nonet --stringparam lang $(1) \ + $(filter_XSLT_langfilter) \ + $(filter_XcuFilterUiTarget) > $$@) + $$(call gb_Trace_EndRange,$(1),XCU) + +endef + +$(foreach lang,$(gb_Configuration_LANGS),$(eval \ + $(call filter_XcuResTarget__rule,$(lang)))) + +define filter_Configuration_Configuration +$(call gb_Configuration_Configuration,$(1)) + +$(call gb_Configuration_get_target,$(1)) : \ + $(foreach lang,$(gb_Configuration_LANGS),$(call filter_XcuResTarget_get_target,$(lang))) +$(call gb_Configuration_get_clean_target,$(1)) : \ + $(foreach lang,$(gb_Configuration_LANGS),$(call filter_XcuResTarget_get_clean_target,$(lang))) + +endef + + +# $(call filter_Configuration_add_ui_filter,configuration,prefix,xcufile) +define filter_Configuration_add_ui_filter +ifeq ($(WITH_LANG),) +$(filter_XcuFilterUiTarget) : $(SRCDIR)/$(2)/$(3) +else +$(call gb_XcuMergeTarget_XcuMergeTarget,$(2)/$(3),$(1),$(2),$(3)) +$(filter_XcuFilterUiTarget) : \ + $(call gb_XcuMergeTarget_get_target,$(2)/$(3)) +endif +$(call gb_Configuration_get_clean_target,$(1)) : \ + $(call gb_XcuMergeTarget_get_clean_target,$(2)/$(3)) + +endef + +# $(call filter_Configuration_add_ui_filters,configuration,prefix,xcufile) +define filter_Configuration_add_ui_filters +$(foreach xcu,$(3),$(call filter_Configuration_add_ui_filter,$(1),$(2),$(xcu).xcu)) + +endef + + +### the filter configuration ######################################## + +$(eval $(call filter_Configuration_Configuration,fcfg_langpack)) + +# fcfg_base +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_base_types.xcu,filter/source/config/fragments/types,\ + writer_web_HTML_help \ + oxt_OpenOffice_Extension \ + wav_Wave_Audio_File \ + component_Bibliography \ + component_DB \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_base_filters.xcu,filter/source/config/fragments/filters,\ + writer_web_HTML_help \ +)) + +$(eval $(call filter_Configuration_add_others,fcfg_langpack,fcfg_base_others.xcu,filter/source/config/fragments,\ + frameloaders/com_sun_star_frame_Bibliography \ + frameloaders/com_sun_star_sdb_ContentLoader \ + contenthandlers/com_sun_star_comp_framework_SoundHandler \ + contenthandlers/com_sun_star_comp_framework_oxt_handler \ +)) + +# fcfg_database +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_database_types.xcu,filter/source/config/fragments/types,\ + StarBase \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_database_filters.xcu,filter/source/config/fragments/filters,\ + StarOffice_XML__Base_ \ +)) + +$(eval $(call filter_Configuration_add_others,fcfg_langpack,fcfg_database_others.xcu,filter/source/config/fragments,\ + frameloaders/org_openoffice_comp_dbflt_DBContentLoader2 \ +)) + +# fcfg_reportbuilder +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_reportbuilder_types.xcu,filter/source/config/fragments/types,\ + StarBaseReport \ + StarBaseReportChart \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_reportbuilder_filters.xcu,filter/source/config/fragments/filters,\ + StarBaseReport \ + StarBaseReportChart \ +)) + +# fcfg_writer +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_writer_types.xcu,filter/source/config/fragments/types,\ + generic_HTML \ + calc_MS_Excel_40 \ + calc_MS_Excel_5095 \ + calc_MS_Excel_95 \ + writer_MS_WinWord_5 \ + writer_MS_WinWord_60 \ + writer_MS_Word_95 \ + writer_MS_Word_95_Vorlage \ + writer_MS_Word_97 \ + writer_MS_Word_97_Vorlage \ + writer_ODT_FlatXML \ + writer_Rich_Text_Format \ + writer_StarOffice_XML_Writer \ + writer_WordPerfect_Document \ + writer_MS_Works_Document \ + writer_MS_Write \ + writer_DosWord \ + writer_ClarisWorks \ + writer_Mac_Word \ + writer_Mac_Works \ + writer_MacWrite \ + writer_Mariner_Write \ + writer_WriteNow \ + writer_AbiWord_Document \ + writer_T602_Document \ + writer_LotusWordPro_Document \ + generic_Text \ + writer_MIZI_Hwp_97 \ + writer_StarOffice_XML_Writer_Template \ + pdf_Portable_Document_Format \ + writer8_template \ + writer8 \ + writer_MS_Word_2007_XML \ + writer_MS_Word_2007_XML_Template \ + writer_MS_Word_2007_XML_VBA \ + writer_OOXML \ + writer_OOXML_Template \ + writer_layout_dump_xml \ + writer_indexing_export_xml \ + writer_BroadBand_eBook \ + writer_FictionBook_2 \ + writer_PalmDoc \ + writer_Plucker_eBook \ + writer_ApplePages \ + MWAW_Text_Document \ + Palm_Text_Document \ + StarOffice_Writer \ + writer_EPUB_Document \ + writer_PocketWord_File \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_writer_filters.xcu,filter/source/config/fragments/filters,\ + HTML__StarWriter_ \ + MS_WinWord_5 \ + MS_WinWord_6_0 \ + MS_Word_95 \ + MS_Word_95_Vorlage \ + MS_Word_97 \ + MS_Word_97_Vorlage \ + ODT_FlatXML \ + Rich_Text_Format \ + StarOffice_XML__Writer_ \ + WordPerfect \ + MS_Works \ + MS_Write \ + DosWord \ + ClarisWorks \ + Mac_Word \ + Mac_Works \ + MacWrite \ + Mariner_Write \ + WriteNow \ + AbiWord \ + T602Document \ + LotusWordPro \ + Text \ + Text__encoded_ \ + writer_MIZI_Hwp_97 \ + writer_StarOffice_XML_Writer_Template \ + writer_pdf_Export\ + writer8\ + writer8_template \ + MS_Word_2007_XML \ + MS_Word_2007_XML_Template \ + MS_Word_2007_XML_VBA \ + OOXML_Text \ + OOXML_Text_Template \ + writer_layout_dump \ + writer_indexing_export \ + BroadBand_eBook \ + FictionBook_2 \ + PalmDoc \ + Plucker_eBook \ + ApplePages \ + MWAW_Text_Document \ + Palm_Text_Document \ + StarOffice_Writer \ + EPUB \ + PocketWord_File \ +)) + +# fcfg_web +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_web_types.xcu,filter/source/config/fragments/types,\ + generic_HTML \ + generic_Text \ + writer_web_HTML_help \ + writer_StarOffice_XML_Writer \ + writer_web_StarOffice_XML_Writer_Web_Template \ + pdf_Portable_Document_Format \ + writerweb8_writer_template \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_web_filters.xcu,filter/source/config/fragments/filters,\ + HTML \ + Text__StarWriter_Web_ \ + Text__encoded___StarWriter_Web_ \ + writer_web_HTML_help \ + writer_web_StarOffice_XML_Writer \ + writer_web_StarOffice_XML_Writer_Web_Template \ + writer_web_pdf_Export\ + writer_web_png_Export\ + writer_web_jpg_Export\ + writer_web_webp_Export\ + writerweb8_writer_template\ + writerweb8_writer \ +)) + +# fcfg_global +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_global_types.xcu,filter/source/config/fragments/types,\ + generic_Text \ + writer_StarOffice_XML_Writer \ + writer_globaldocument_StarOffice_XML_Writer_GlobalDocument \ + pdf_Portable_Document_Format \ + writerglobal8 \ + writerglobal8_template \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_global_filters.xcu,filter/source/config/fragments/filters,\ + Text__encoded___StarWriter_GlobalDocument_ \ + writer_globaldocument_StarOffice_XML_Writer \ + writer_globaldocument_StarOffice_XML_Writer_GlobalDocument \ + writer_globaldocument_pdf_Export \ + writerglobal8 \ + writerglobal8_template \ + writerglobal8_writer \ + writerglobal8_HTML \ +)) + +# fcfg_calc +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_calc_types.xcu,filter/source/config/fragments/types,\ + calc_DIF \ + calc_ODS_FlatXML \ + calc_HTML \ + generic_HTML \ + generic_Text \ + calc_Gnumeric \ + calc_Lotus \ + calc_QPro \ + calc_MS_Excel_40 \ + calc_MS_Excel_40_VorlageTemplate \ + calc_MS_Excel_5095 \ + calc_MS_Excel_5095_VorlageTemplate \ + calc_MS_Excel_95 \ + calc_MS_Excel_95_VorlageTemplate \ + calc_MS_Excel_97 \ + calc_MS_Excel_97_VorlageTemplate \ + writer_Rich_Text_Format \ + calc_SYLK \ + calc_StarOffice_XML_Calc \ + calc_StarOffice_XML_Calc_Template \ + pdf_Portable_Document_Format \ + calc_dBase\ + calc8 \ + calc8_template \ + MS_Excel_2007_XML \ + MS_Excel_2007_VBA_XML \ + MS_Excel_2007_XML_Template \ + MS_Excel_2007_Binary \ + calc_OOXML \ + calc_OOXML_Template \ + calc_MS_Works_Document \ + calc_WPS_Lotus_Document \ + calc_WPS_QPro_Document \ + calc_ClarisWorks \ + calc_Claris_Resolve \ + calc_Mac_Works \ + calc_AppleNumbers \ + MWAW_Database \ + MWAW_Spreadsheet \ + StarOffice_Spreadsheet \ + calc_MS_Multiplan \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_calc_filters.xcu,filter/source/config/fragments/filters,\ + DIF \ + HTML__StarCalc_ \ + ODS_FlatXML \ + Lotus \ + QPro \ + MS_Excel_4_0 \ + MS_Excel_4_0_Vorlage_Template \ + MS_Excel_5_0_95 \ + MS_Excel_5_0_95_Vorlage_Template \ + MS_Excel_95 \ + MS_Excel_95_Vorlage_Template \ + MS_Excel_97 \ + MS_Excel_97_Vorlage_Template \ + MS_Excel_2003_XML_Orcus \ + Rich_Text_Format__StarCalc_ \ + SYLK \ + StarOffice_XML__Calc_ \ + Text___txt___csv__StarCalc_ \ + calc_HTML_WebQuery \ + calc_StarOffice_XML_Calc_Template \ + calc_pdf_Export \ + dBase \ + calc8 \ + calc8_template \ + calc_Gnumeric \ + calc_MS_Excel_2007_XML \ + calc_MS_Excel_2007_VBA_XML \ + calc_MS_Excel_2007_XML_Template \ + calc_MS_Excel_2007_Binary \ + calc_OOXML \ + calc_OOXML_Template \ + MS_Works_Calc \ + WPS_Lotus_Calc \ + WPS_QPro_Calc \ + ClarisWorks_Calc \ + Claris_Resolve_Calc \ + Mac_Works_Calc \ + AppleNumbers \ + MWAW_Database \ + MWAW_Spreadsheet \ + StarOffice_Spreadsheet \ + MS_Multiplan \ +)) + +# fcfg_draw +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_draw_types.xcu,filter/source/config/fragments/types,\ + draw_ODG_FlatXML \ + draw_StarOffice_XML_Draw \ + draw_StarOffice_XML_Draw_Template \ + pdf_Portable_Document_Format \ + draw8 \ + draw8_template \ + draw_WordPerfect_Graphics \ + draw_Visio_Document \ + draw_Publisher_Document \ + draw_CorelDraw_Document \ + draw_Corel_Presentation_Exchange \ + draw_Freehand_Document \ + draw_Visio_Document \ + draw_ClarisWorks \ + draw_PageMaker_Document \ + draw_QXP_Document \ + draw_ZMF_Document \ + MWAW_Bitmap \ + MWAW_Drawing \ + StarOffice_Drawing \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_draw_filters.xcu,filter/source/config/fragments/filters,\ + ODG_FlatXML \ + StarOffice_XML__Draw_ \ + draw_StarOffice_XML_Draw_Template \ + draw_pdf_Export \ + draw8 \ + draw8_template \ + WordPerfectGraphics \ + VisioDocument \ + PublisherDocument \ + CorelDrawDocument \ + CorelPresentationExchange \ + FreehandDocument \ + ClarisWorks_Draw \ + PageMakerDocument \ + QXPDocument \ + ZMFDocument \ + MWAW_Bitmap \ + MWAW_Drawing \ + StarOffice_Drawing \ +)) + +# fcfg_impress +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_impress_types.xcu,filter/source/config/fragments/types,\ + draw_StarOffice_XML_Draw \ + impress_AppleKeynote \ + impress_MS_PowerPoint_97 \ + impress_MS_PowerPoint_97_AutoPlay \ + impress_MS_PowerPoint_97_Vorlage \ + impress_ODP_FlatXML \ + impress_StarOffice_XML_Impress \ + impress_StarOffice_XML_Impress_Template \ + pdf_Portable_Document_Format \ + impress8 \ + impress8_template \ + draw8 \ + MS_PowerPoint_2007_XML \ + MS_PowerPoint_2007_XML_AutoPlay \ + MS_PowerPoint_2007_XML_Template \ + MS_PowerPoint_2007_XML_VBA \ + impress_OOXML_Presentation \ + impress_OOXML_Presentation_Template \ + impress_OOXML_Presentation_AutoPlay \ + impress_ClarisWorks \ + StarOffice_Presentation \ + MWAW_Presentation \ + impress_PowerPoint3 \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_impress_filters.xcu,filter/source/config/fragments/filters,\ + AppleKeynote \ + MS_PowerPoint_97 \ + MS_PowerPoint_97_AutoPlay \ + MS_PowerPoint_97_Vorlage \ + impress_StarOffice_XML_Draw \ + ODP_FlatXML \ + StarOffice_XML__Impress_ \ + impress_StarOffice_XML_Impress_Template \ + impress_pdf_Export \ + impress8 \ + impress8_template \ + impress8_draw \ + impress_MS_PowerPoint_2007_XML \ + impress_MS_PowerPoint_2007_XML_AutoPlay \ + impress_MS_PowerPoint_2007_XML_Template \ + impress_MS_PowerPoint_2007_XML_VBA \ + impress_OOXML \ + impress_OOXML_Template \ + impress_OOXML_AutoPlay \ + ClarisWorks_Impress \ + StarOffice_Presentation \ + MWAW_Presentation \ + PowerPoint3 \ +)) + +# fcfg_chart +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_chart_types.xcu,filter/source/config/fragments/types,\ + chart_StarOffice_XML_Chart \ + chart8 \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_chart_filters.xcu,filter/source/config/fragments/filters,\ + StarOffice_XML__Chart_ \ + chart8 \ +)) + +$(eval $(call filter_Configuration_add_others,fcfg_langpack,fcfg_chart_others.xcu,filter/source/config/fragments,\ + frameloaders/com_sun_star_comp_chart2_ChartFrameLoader \ +)) + +# fcfg_math +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_math_types.xcu,filter/source/config/fragments/types,\ + math_MathML_XML_Math \ + math_MathType_3x \ + math_StarOffice_XML_Math \ + pdf_Portable_Document_Format \ + math8 \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_math_filters.xcu,filter/source/config/fragments/filters,\ + MathML_XML__Math_ \ + MathType_3_x \ + StarOffice_XML__Math_ \ + math_pdf_Export \ + math8 \ +)) + +# fcfg_drawgraphics +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_drawgraphics_types.xcu,filter/source/config/fragments/types,\ + bmp_MS_Windows \ + dxf_AutoCAD_Interchange \ + emf_MS_Windows_Metafile \ + eps_Encapsulated_PostScript \ + gif_Graphics_Interchange \ + graphic_HTML \ + jpg_JPEG \ + met_OS2_Metafile \ + mov_MOV \ + pbm_Portable_Bitmap \ + pcd_Photo_CD_Base \ + pcd_Photo_CD_Base16 \ + pcd_Photo_CD_Base4 \ + pct_Mac_Pict \ + pcx_Zsoft_Paintbrush \ + pgm_Portable_Graymap \ + png_Portable_Network_Graphic \ + ppm_Portable_Pixelmap \ + psd_Adobe_Photoshop \ + ras_Sun_Rasterfile \ + svg_Scalable_Vector_Graphics_Draw \ + svg_Scalable_Vector_Graphics \ + svm_StarView_Metafile \ + tga_Truevision_TARGA \ + tif_Tag_Image_File \ + webp_WebP \ + wmf_MS_Windows_Metafile \ + xbm_X_Consortium \ + xpm_XPM \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_drawgraphics_filters.xcu,filter/source/config/fragments/filters,\ + BMP___MS_Windows \ + DXF___AutoCAD_Interchange \ + EMF___MS_Windows_Metafile \ + EPS___Encapsulated_PostScript \ + GIF___Graphics_Interchange \ + JPG___JPEG \ + MET___OS_2_Metafile \ + mov__MOV \ + PBM___Portable_Bitmap \ + PCT___Mac_Pict \ + PCX___Zsoft_Paintbrush \ + PGM___Portable_Graymap \ + PNG___Portable_Network_Graphic \ + PPM___Portable_Pixelmap \ + PSD___Adobe_Photoshop \ + RAS___Sun_Rasterfile \ + SVG___Scalable_Vector_Graphics_Draw \ + SVG___Scalable_Vector_Graphics \ + SVM___StarView_Metafile \ + TGA___Truevision_TARGA \ + TIF___Tag_Image_File \ + WEBP___WebP \ + WMF___MS_Windows_Metafile \ + XBM___X_Consortium \ + XPM \ + draw_PCD_Photo_CD_Base \ + draw_PCD_Photo_CD_Base16 \ + draw_PCD_Photo_CD_Base4 \ + draw_bmp_Export \ + draw_emf_Export \ + draw_eps_Export \ + draw_gif_Export \ + draw_html_Export \ + draw_jpg_Export \ + draw_png_Export \ + draw_svg_Export \ + draw_tif_Export \ + draw_webp_Export \ + draw_wmf_Export \ +)) + +# fcfg_impressgraphics +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_impressgraphics_types.xcu,filter/source/config/fragments/types,\ + bmp_MS_Windows \ + emf_MS_Windows_Metafile \ + eps_Encapsulated_PostScript \ + gif_Graphics_Interchange \ + graphic_HTML \ + impress_CGM_Computer_Graphics_Metafile \ + jpg_JPEG \ + met_OS2_Metafile \ + pbm_Portable_Bitmap \ + pct_Mac_Pict \ + pgm_Portable_Graymap \ + png_Portable_Network_Graphic \ + ppm_Portable_Pixelmap \ + ras_Sun_Rasterfile \ + svg_Scalable_Vector_Graphics_Draw \ + svg_Scalable_Vector_Graphics \ + svm_StarView_Metafile \ + tif_Tag_Image_File \ + wmf_MS_Windows_Metafile \ + webp_WebP \ + xpm_XPM \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_impressgraphics_filters.xcu,filter/source/config/fragments/filters,\ + CGM___Computer_Graphics_Metafile \ + impress_bmp_Export \ + impress_emf_Export \ + impress_eps_Export \ + impress_gif_Export \ + impress_html_Export \ + impress_jpg_Export \ + impress_png_Export \ + impress_svg_Export \ + impress_tif_Export \ + impress_webp_Export \ + impress_wmf_Export \ +)) + +# fcfg_writergraphics +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_writergraphics_types.xcu,filter/source/config/fragments/types,\ + jpg_JPEG \ + png_Portable_Network_Graphic \ + svg_Scalable_Vector_Graphics \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_writergraphics_filters.xcu,filter/source/config/fragments/filters,\ + writer_jpg_Export \ + writer_png_Export \ + writer_svg_Export \ + writer_webp_Export \ +)) + +# fcfg_calcgraphics +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_calcgraphics_types.xcu,filter/source/config/fragments/types,\ + png_Portable_Network_Graphic \ + svg_Scalable_Vector_Graphics \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_calcgraphics_filters.xcu,filter/source/config/fragments/filters,\ + calc_jpg_Export \ + calc_png_Export \ + calc_svg_Export \ + calc_webp_Export \ +)) + +# fcfg_internalgraphics +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_internalgraphics_types.xcu,filter/source/config/fragments/types,\ + bmp_MS_Windows \ + dxf_AutoCAD_Interchange \ + emf_MS_Windows_Metafile \ + eps_Encapsulated_PostScript \ + gif_Graphics_Interchange \ + jpg_JPEG \ + met_OS2_Metafile \ + mov_MOV \ + pbm_Portable_Bitmap \ + pcd_Photo_CD_Base \ + pcd_Photo_CD_Base16 \ + pcd_Photo_CD_Base4 \ + pct_Mac_Pict \ + pcx_Zsoft_Paintbrush \ + pgm_Portable_Graymap \ + png_Portable_Network_Graphic \ + ppm_Portable_Pixelmap \ + psd_Adobe_Photoshop \ + ras_Sun_Rasterfile \ + svg_Scalable_Vector_Graphics \ + svm_StarView_Metafile \ + tga_Truevision_TARGA \ + tif_Tag_Image_File \ + webp_WebP \ + wmf_MS_Windows_Metafile \ + xbm_X_Consortium \ + xpm_XPM \ +)) + +$(eval $(call filter_Configuration_add_internal_filters,fcfg_langpack,fcfg_internalgraphics_filters.xcu,filter/source/config/fragments/internalgraphicfilters,\ + bmp_Export \ + bmp_Import \ + dxf_Import \ + emf_Export \ + emf_Import \ + eps_Export \ + eps_Import \ + gif_Export \ + gif_Import \ + jpg_Export \ + jpg_Import \ + met_Import \ + pbm_Import \ + pcd_Import_Base \ + pcd_Import_Base4 \ + pcd_Import_Base16 \ + pct_Import \ + pcx_Import \ + pdf_Export \ + pdf_Import \ + pgm_Import \ + png_Export \ + png_Import \ + ppm_Import \ + psd_Import \ + ras_Import \ + svg_Export \ + svg_Import \ + svm_Export \ + svm_Import \ + tga_Import \ + tif_Export \ + tif_Import \ + webp_Export \ + webp_Import \ + wmf_Export \ + wmf_Import \ + xbm_Import \ + xpm_Import \ + mov_Import \ +)) + +# fcfg_xslt +$(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_xslt_types.xcu,filter/source/config/fragments/types,\ + calc_ADO_rowset_XML \ + calc_MS_Excel_2003_XML \ + writer_DocBook_File \ + writer_MS_Word_2003_XML \ + XHTML_File \ + Unified_Office_Format_text \ + Unified_Office_Format_spreadsheet \ + Unified_Office_Format_presentation \ +)) + +$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_xslt_filters.xcu,filter/source/config/fragments/filters,\ + ADO_rowset_XML \ + DocBook_File \ + MS_Excel_2003_XML \ + MS_Word_2003_XML \ + XHTML_Calc_File \ + XHTML_Draw_File \ + XHTML_Impress_File \ + XHTML_Writer_File \ + UOF_text \ + UOF_spreadsheet \ + UOF_presentation \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CppunitTest_filter_dialogs_test.mk b/filter/CppunitTest_filter_dialogs_test.mk new file mode 100644 index 000000000..7ae73639c --- /dev/null +++ b/filter/CppunitTest_filter_dialogs_test.mk @@ -0,0 +1,68 @@ +# -*- 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/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitScreenShot,filter_dialogs_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,filter_dialogs_test, \ + filter/qa/unit/filter-dialogs-test \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,filter_dialogs_test)) + +$(eval $(call gb_CppunitTest_set_include,filter_dialogs_test,\ + -I$(SRCDIR)/filter/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,filter_dialogs_test, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + editeng \ + i18nlangtag \ + i18nutil \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sfx \ + sot \ + svl \ + svt \ + test \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_external,filter_dialogs_test,boost_headers)) + +$(eval $(call gb_CppunitTest_use_sdk_api,filter_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_ure,filter_dialogs_test)) +$(eval $(call gb_CppunitTest_use_vcl_non_headless_with_windows,filter_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_rdb,filter_dialogs_test,services)) + +$(eval $(call gb_CppunitTest_use_configuration,filter_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_uiconfigs,filter_dialogs_test,\ + filter \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CppunitTest_filter_msfilter.mk b/filter/CppunitTest_filter_msfilter.mk new file mode 100644 index 000000000..cf4347342 --- /dev/null +++ b/filter/CppunitTest_filter_msfilter.mk @@ -0,0 +1,44 @@ +# -*- 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,filter_msfilter)) + +$(eval $(call gb_CppunitTest_use_sdk_api,filter_msfilter)) +$(eval $(call gb_CppunitTest_use_ure,filter_msfilter)) + +$(eval $(call gb_CppunitTest_use_configuration,filter_msfilter)) + +$(eval $(call gb_CppunitTest_use_externals,filter_msfilter, \ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,filter_msfilter, \ + tl \ + comphelper \ + unotest \ + cppuhelper \ + cppu \ + msfilter \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_components,filter_msfilter,\ + configmgr/source/configmgr \ + filter/source/config/cache/filterconfig1 \ + framework/util/fwk \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,filter_msfilter, \ + filter/qa/cppunit/msfilter-test \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CppunitTest_filter_pdf.mk b/filter/CppunitTest_filter_pdf.mk new file mode 100644 index 000000000..e5c16ec60 --- /dev/null +++ b/filter/CppunitTest_filter_pdf.mk @@ -0,0 +1,48 @@ +# -*- 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/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,filter_pdf)) + +$(eval $(call gb_CppunitTest_use_externals,filter_pdf,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,filter_pdf, \ + filter/qa/pdf \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,filter_pdf, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + test \ + tl \ + unotest \ + utl \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,filter_pdf)) + +$(eval $(call gb_CppunitTest_use_ure,filter_pdf)) +$(eval $(call gb_CppunitTest_use_vcl,filter_pdf)) + +$(eval $(call gb_CppunitTest_use_rdb,filter_pdf,services)) + +$(eval $(call gb_CppunitTest_use_custom_headers,filter_pdf,\ + officecfg/registry \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,filter_pdf)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CppunitTest_filter_priority.mk b/filter/CppunitTest_filter_priority.mk new file mode 100644 index 000000000..d942f5d01 --- /dev/null +++ b/filter/CppunitTest_filter_priority.mk @@ -0,0 +1,41 @@ +# -*- 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,filter_priority)) + +$(eval $(call gb_CppunitTest_use_sdk_api,filter_priority)) +$(eval $(call gb_CppunitTest_use_ure,filter_priority)) +$(eval $(call gb_CppunitTest_use_vcl,filter_priority)) + +$(eval $(call gb_CppunitTest_use_configuration,filter_priority)) + +$(eval $(call gb_CppunitTest_use_external,filter_priority,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,filter_priority, \ + comphelper \ + unotest \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_components,filter_priority,\ + configmgr/source/configmgr \ + filter/source/config/cache/filterconfig1 \ + framework/util/fwk \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,filter_priority, \ + filter/qa/cppunit/priority-test \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CppunitTest_filter_svg.mk b/filter/CppunitTest_filter_svg.mk new file mode 100644 index 000000000..ec0841929 --- /dev/null +++ b/filter/CppunitTest_filter_svg.mk @@ -0,0 +1,47 @@ +# -*- 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/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,filter_svg)) + +$(eval $(call gb_CppunitTest_use_externals,filter_svg,\ + boost_headers \ + libxml2 \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,filter_svg, \ + filter/qa/unit/svg \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,filter_svg, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + test \ + unotest \ + utl \ + tl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,filter_svg)) + +$(eval $(call gb_CppunitTest_use_ure,filter_svg)) +$(eval $(call gb_CppunitTest_use_vcl,filter_svg)) + +$(eval $(call gb_CppunitTest_use_rdb,filter_svg,services)) + +$(eval $(call gb_CppunitTest_use_custom_headers,filter_svg,\ + officecfg/registry \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,filter_svg)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CppunitTest_filter_textfilterdetect.mk b/filter/CppunitTest_filter_textfilterdetect.mk new file mode 100644 index 000000000..6fb22f8b0 --- /dev/null +++ b/filter/CppunitTest_filter_textfilterdetect.mk @@ -0,0 +1,44 @@ +# -*- 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,filter_textfilterdetect)) + +$(eval $(call gb_CppunitTest_use_api,filter_textfilterdetect,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_external,filter_textfilterdetect,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,filter_textfilterdetect, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + sfx \ + test \ + textfd \ + tl \ + unotest \ + utl \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,filter_textfilterdetect, \ + filter/qa/unit/textfilterdetect \ +)) + +$(eval $(call gb_CppunitTest_use_ure,filter_textfilterdetect)) + +$(eval $(call gb_CppunitTest_use_vcl,filter_textfilterdetect)) + +$(eval $(call gb_CppunitTest_use_rdb,filter_textfilterdetect,services)) + +$(eval $(call gb_CppunitTest_use_configuration,filter_textfilterdetect)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CppunitTest_filter_xslt.mk b/filter/CppunitTest_filter_xslt.mk new file mode 100644 index 000000000..8bf69a0ae --- /dev/null +++ b/filter/CppunitTest_filter_xslt.mk @@ -0,0 +1,41 @@ +# -*- 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,filter_xslt)) + +$(eval $(call gb_CppunitTest_use_sdk_api,filter_xslt)) +$(eval $(call gb_CppunitTest_use_ure,filter_xslt)) +$(eval $(call gb_CppunitTest_use_vcl,filter_xslt)) + +$(eval $(call gb_CppunitTest_use_configuration,filter_xslt)) + +$(eval $(call gb_CppunitTest_use_external,filter_xslt,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,filter_xslt, \ + comphelper \ + test \ + unotest \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_components,filter_xslt,\ + configmgr/source/configmgr \ + filter/source/xsltfilter/xsltfilter \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,filter_xslt, \ + filter/qa/cppunit/xslt-test \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/CustomTarget_svg.mk b/filter/CustomTarget_svg.mk new file mode 100644 index 000000000..065e26e1b --- /dev/null +++ b/filter/CustomTarget_svg.mk @@ -0,0 +1,63 @@ +# -*- 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/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,filter/source/svg)) + +filter_SVGSRC := $(SRCDIR)/filter/source/svg +filter_SVGWORK := $(call gb_CustomTarget_get_workdir,filter/source/svg) + +filter_SRC_svg_Tokens := $(filter_SVGSRC)/tokens.txt +filter_SRC_svg_GenToken := $(filter_SVGSRC)/gentoken.py +filter_SRC_svg_PresentationEngine := $(filter_SVGSRC)/presentation_engine.js +filter_SRC_svg_Js2Hxx := $(filter_SVGSRC)/js2hxx.py + +filter_GEN_svg_Tokens_gperf := $(filter_SVGWORK)/tokens.gperf +filter_GEN_svg_Tokens_hxx := $(filter_SVGWORK)/tokens.hxx +filter_GEN_svg_Tokens_cxx := $(filter_SVGWORK)/tokens.cxx +filter_GEN_svg_Script_hxx := $(filter_SVGWORK)/svgscript.hxx + +$(filter_GEN_svg_Tokens_gperf) : \ + $(call gb_ExternalExecutable_get_dependencies,python) \ + $(filter_SRC_svg_GenToken) $(filter_SRC_svg_Tokens) \ + | $(filter_SVGWORK)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,GPF,3) + $(call gb_Helper_abbreviate_dirs, \ + $(call gb_ExternalExecutable_get_command,python) \ + $(filter_SRC_svg_GenToken) \ + $(filter_SRC_svg_Tokens) $(filter_GEN_svg_Tokens_hxx) \ + $(filter_GEN_svg_Tokens_gperf)) + +# dummy rule: both files generated by recipe above +$(filter_GEN_svg_Tokens_hxx) : $(filter_GEN_svg_Tokens_gperf) + +$(filter_GEN_svg_Tokens_cxx) : $(filter_GEN_svg_Tokens_gperf) + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,GPF,1) + $(call gb_Helper_abbreviate_dirs, \ + $(GPERF) --compare-strncmp -C -m 20 --switch=2 --readonly-tables $(filter_GEN_svg_Tokens_gperf) \ + | sed -e "s/(char\*)0/(char\*)0$(COMMA) 0/g" \ + > $(filter_GEN_svg_Tokens_cxx)) + +$(filter_GEN_svg_Script_hxx) : \ + $(call gb_ExternalExecutable_get_dependencies,python) \ + $(filter_SRC_svg_PresentationEngine) $(filter_SRC_svg_Js2Hxx) \ + | $(filter_SVGWORK)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1) + $(call gb_Helper_abbreviate_dirs, \ + $(call gb_ExternalExecutable_get_command,python) $(filter_SRC_svg_Js2Hxx) \ + $(filter_SRC_svg_PresentationEngine) \ + $(filter_GEN_svg_Script_hxx)) + +$(call gb_CustomTarget_get_target,filter/source/svg) : \ + $(filter_GEN_svg_Tokens_gperf) \ + $(filter_GEN_svg_Tokens_hxx) \ + $(filter_GEN_svg_Tokens_cxx) \ + $(filter_GEN_svg_Script_hxx) \ + +# vim: set noet sw=4 ts=4: diff --git a/filter/IwyuFilter_filter.yaml b/filter/IwyuFilter_filter.yaml new file mode 100644 index 000000000..14ae4e91a --- /dev/null +++ b/filter/IwyuFilter_filter.yaml @@ -0,0 +1,56 @@ +--- +assumeFilename: filter/source/msfilter/msdffimp.cxx +excludelist: + filter/source/graphicfilter/icgm/cgm.cxx: + # OSL_BIGENDIAN is being checked + - osl/endian.h + filter/source/graphicfilter/ieps/ieps.cxx: + # Needed on WIN32 + - o3tl/char16_t2wchar_t.hxx + filter/source/msfilter/mscodec.cxx: + # Actually used + - com/sun/star/beans/NamedValue.hpp + filter/source/msfilter/msdffimp.cxx: + # Needed for rtl::math::round + - rtl/math.hxx + filter/source/msfilter/mstoolbar.cxx: + # Needed for template + - com/sun/star/frame/XModel.hpp + filter/source/msfilter/svdfppt.cxx: + # OSL_BIGENDIAN is being checked + - osl/endian.h + filter/source/pdf/impdialog.cxx: + # Actually used + - com/sun/star/beans/XMaterialHolder.hpp + filter/source/pdf/pdfexport.cxx: + # Needed for direct member access + - com/sun/star/security/XCertificate.hpp + filter/source/pdf/pdfinteract.cxx: + # Actually used + - com/sun/star/task/XInteractionRequest.hpp + filter/source/svg/svgfilter.cxx: + # Actually used + - com/sun/star/io/IOException.hpp + filter/source/xmlfilteradaptor/XmlFilterAdaptor.cxx: + # Actually used + - comphelper/scopeguard.hxx + filter/source/xmlfilterdetect/filterdetect.cxx: + # Actually used + - com/sun/star/uno/XComponentContext.hpp + filter/source/xsltdialog/typedetectionimport.cxx: + # Actually used + - com/sun/star/xml/sax/XAttributeList.hpp + filter/source/xsltdialog/xmlfilterjar.cxx: + # Actually used + - com/sun/star/uno/XComponentContext.hpp + filter/source/xsltdialog/xmlfiltertabdialog.cxx: + # Actually used + - com/sun/star/uno/XComponentContext.hpp + filter/source/xsltdialog/xmlfiltersettingsdialog.cxx: + # Actually used + - com/sun/star/uno/XComponentContext.hpp + filter/source/xsltfilter/LibXSLTTransformer.cxx: + # Actually used + - com/sun/star/io/XInputStream.hpp + - com/sun/star/io/XOutputStream.hpp + - com/sun/star/io/XStreamListener.hpp diff --git a/filter/JunitTest_filter_complex.mk b/filter/JunitTest_filter_complex.mk new file mode 100644 index 000000000..c8f22e1bc --- /dev/null +++ b/filter/JunitTest_filter_complex.mk @@ -0,0 +1,33 @@ +# +# 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_JunitTest_JunitTest,filter_complex)) + +$(eval $(call gb_JunitTest_use_unoapi_jars,filter_complex)) + +$(eval $(call gb_JunitTest_add_sourcefiles,filter_complex,\ + filter/qa/complex/filter/misc/FinalizedMandatoryTest \ + filter/qa/complex/filter/misc/TypeDetection6FileFormat \ +)) + +$(eval $(call gb_JunitTest_add_classes,filter_complex,\ + complex.filter.misc.FinalizedMandatoryTest \ + complex.filter.misc.TypeDetection6FileFormat \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_filterconfig.mk b/filter/Library_filterconfig.mk new file mode 100644 index 000000000..38251aa31 --- /dev/null +++ b/filter/Library_filterconfig.mk @@ -0,0 +1,61 @@ +# -*- 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,filterconfig)) + +$(eval $(call gb_Library_set_componentfile,filterconfig,filter/source/config/cache/filterconfig1,services)) + +$(eval $(call gb_Library_use_external,filterconfig,boost_headers)) + +$(eval $(call gb_Library_use_custom_headers,filterconfig,officecfg/registry)) + +$(eval $(call gb_Library_use_sdk_api,filterconfig)) + +$(eval $(call gb_Library_set_include,filterconfig,\ + $$(INCLUDE) \ + -I$(SRCDIR)/filter/inc \ +)) + +$(eval $(call gb_Library_use_libraries,filterconfig,\ + fwk \ + utl \ + tl \ + comphelper \ + cppuhelper \ + cppu \ + sal \ + salhelper \ + i18nlangtag \ +)) + + +$(eval $(call gb_Library_add_exception_objects,filterconfig,\ + filter/source/config/cache/basecontainer \ + filter/source/config/cache/cacheitem \ + filter/source/config/cache/cacheupdatelistener \ + filter/source/config/cache/configflush \ + filter/source/config/cache/contenthandlerfactory \ + filter/source/config/cache/filtercache \ + filter/source/config/cache/filterfactory \ + filter/source/config/cache/frameloaderfactory \ + filter/source/config/cache/querytokenizer \ + filter/source/config/cache/typedetection \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_graphicfilter.mk b/filter/Library_graphicfilter.mk new file mode 100644 index 000000000..34f9662d0 --- /dev/null +++ b/filter/Library_graphicfilter.mk @@ -0,0 +1,53 @@ +# -*- 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,graphicfilter)) + +$(eval $(call gb_Library_set_componentfile,graphicfilter,filter/source/graphic/graphicfilter,services)) + +$(eval $(call gb_Library_use_external,graphicfilter,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,graphicfilter)) + +$(eval $(call gb_Library_set_include,graphicfilter,\ + $$(INCLUDE) \ + -I$(SRCDIR)/filter/inc \ +)) + +$(eval $(call gb_Library_use_libraries,graphicfilter,\ + svt \ + sfx \ + tk \ + vcl \ + utl \ + tl \ + svl \ + i18nlangtag \ + comphelper \ + basegfx \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,graphicfilter,\ + filter/source/graphic/GraphicExportFilter \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_icg.mk b/filter/Library_icg.mk new file mode 100644 index 000000000..44cb742a6 --- /dev/null +++ b/filter/Library_icg.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,icg)) + +$(eval $(call gb_Library_set_plugin_for_nodep,icg,sd)) + +$(eval $(call gb_Library_use_external,icg,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,icg)) + +$(eval $(call gb_Library_use_libraries,icg,\ + comphelper \ + cppuhelper \ + tk \ + vcl \ + utl \ + tl \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,icg,\ + filter/source/graphicfilter/icgm/actimpr \ + filter/source/graphicfilter/icgm/bitmap \ + filter/source/graphicfilter/icgm/bundles \ + filter/source/graphicfilter/icgm/cgm \ + filter/source/graphicfilter/icgm/chart \ + filter/source/graphicfilter/icgm/class0 \ + filter/source/graphicfilter/icgm/class1 \ + filter/source/graphicfilter/icgm/class2 \ + filter/source/graphicfilter/icgm/class3 \ + filter/source/graphicfilter/icgm/class4 \ + filter/source/graphicfilter/icgm/class5 \ + filter/source/graphicfilter/icgm/class7 \ + filter/source/graphicfilter/icgm/classx \ + filter/source/graphicfilter/icgm/elements \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_msfilter.mk b/filter/Library_msfilter.mk new file mode 100644 index 000000000..0429a6e31 --- /dev/null +++ b/filter/Library_msfilter.mk @@ -0,0 +1,72 @@ +# -*- 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,msfilter)) + +$(eval $(call gb_Library_set_componentfile,msfilter,filter/source/msfilter/msfilter,services)) + +$(eval $(call gb_Library_use_external,msfilter,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,msfilter)) + +$(eval $(call gb_Library_add_defs,msfilter,\ + -DMSFILTER_DLLIMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_libraries,msfilter,\ + svxcore \ + editeng \ + sfx \ + xo \ + sb \ + salhelper \ + svt \ + tk \ + vcl \ + svl \ + sot \ + xmlscript \ + utl \ + tl \ + comphelper \ + basegfx \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,msfilter,\ + filter/source/msfilter/countryid \ + filter/source/msfilter/dffpropset \ + filter/source/msfilter/dffrecordheader \ + filter/source/msfilter/escherex \ + filter/source/msfilter/eschesdo \ + filter/source/msfilter/mscodec \ + filter/source/msfilter/msdffimp \ + filter/source/msfilter/msocximex \ + filter/source/msfilter/msoleexp \ + filter/source/msfilter/mstoolbar \ + filter/source/msfilter/msvbahelper \ + filter/source/msfilter/svdfppt \ + filter/source/msfilter/svxmsbas2 \ + filter/source/msfilter/rtfutil \ + filter/source/msfilter/util \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_odfflatxml.mk b/filter/Library_odfflatxml.mk new file mode 100644 index 000000000..176530035 --- /dev/null +++ b/filter/Library_odfflatxml.mk @@ -0,0 +1,36 @@ +# -*- 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/. +# + +$(eval $(call gb_Library_Library,odfflatxml)) + +$(eval $(call gb_Library_set_componentfile,odfflatxml,filter/source/odfflatxml/odfflatxml,services)) + +$(eval $(call gb_Library_use_sdk_api,odfflatxml)) + +$(eval $(call gb_Library_set_include,odfflatxml,\ + $$(INCLUDE) \ + -I$(SRCDIR)/filter/inc \ +)) + +$(eval $(call gb_Library_use_libraries,odfflatxml,\ + xo \ + tl \ + ucbhelper \ + comphelper \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,odfflatxml,\ + filter/source/odfflatxml/OdfFlatXml \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_pdffilter.mk b/filter/Library_pdffilter.mk new file mode 100644 index 000000000..178a479d7 --- /dev/null +++ b/filter/Library_pdffilter.mk @@ -0,0 +1,66 @@ +# -*- 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,pdffilter)) + +$(eval $(call gb_Library_set_componentfile,pdffilter,filter/source/pdf/pdffilter,services)) + +$(eval $(call gb_Library_use_external,pdffilter,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,pdffilter)) + +$(eval $(call gb_Library_set_include,pdffilter,\ + -I$(SRCDIR)/filter/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Library_use_custom_headers,pdffilter,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_libraries,pdffilter,\ + svt \ + svx \ + sfx \ + tk \ + vcl \ + utl \ + tl \ + svl \ + i18nlangtag \ + comphelper \ + basegfx \ + cppuhelper \ + cppu \ + sal \ + salhelper \ + drawinglayer \ + drawinglayercore \ +)) + +$(eval $(call gb_Library_add_exception_objects,pdffilter,\ + filter/source/pdf/impdialog \ + filter/source/pdf/pdfdecomposer \ + filter/source/pdf/pdfdialog \ + filter/source/pdf/pdfexport \ + filter/source/pdf/pdffilter \ + filter/source/pdf/pdfinteract \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_storagefd.mk b/filter/Library_storagefd.mk new file mode 100644 index 000000000..4d2fd1dfe --- /dev/null +++ b/filter/Library_storagefd.mk @@ -0,0 +1,34 @@ +# -*- 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/. +# +#************************************************************************* + +$(eval $(call gb_Library_Library,storagefd)) + +$(eval $(call gb_Library_set_componentfile,storagefd,filter/source/storagefilterdetect/storagefd,services)) + +$(eval $(call gb_Library_use_external,storagefd,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,storagefd)) + +$(eval $(call gb_Library_use_libraries,storagefd,\ + comphelper \ + cppuhelper \ + cppu \ + sal \ + sfx \ + tl \ + utl \ +)) + +$(eval $(call gb_Library_add_exception_objects,storagefd,\ + filter/source/storagefilterdetect/filterdetect \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_svgfilter.mk b/filter/Library_svgfilter.mk new file mode 100644 index 000000000..37372b9d0 --- /dev/null +++ b/filter/Library_svgfilter.mk @@ -0,0 +1,79 @@ +# -*- 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,svgfilter)) + +$(eval $(call gb_Library_use_custom_headers,svgfilter,filter/source/svg)) + +$(eval $(call gb_Library_set_componentfile,svgfilter,filter/source/svg/svgfilter,services)) + +$(eval $(call gb_Library_add_defs,svgfilter,\ + -DBOOST_ALL_NO_LIB \ + -DUSE_MODERN_SPIRIT \ + -DFILTER_DLLIMPLEMENTATION \ +)) + +ifeq ($(COM),MSC) +$(eval $(call gb_Library_add_defs,svgfilter,\ + -D_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING \ + -D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING \ +)) +endif + +$(eval $(call gb_Library_set_include,svgfilter,\ + $$(INCLUDE) \ + -I$(SRCDIR)/filter/inc \ +)) + +$(eval $(call gb_Library_use_sdk_api,svgfilter)) + +$(eval $(call gb_Library_use_libraries,svgfilter,\ + svxcore \ + editeng \ + xo \ + svt \ + vcl \ + svl \ + utl \ + tl \ + i18nlangtag \ + sax \ + salhelper \ + comphelper \ + drawinglayercore \ + drawinglayer \ + basegfx \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_use_externals,svgfilter,\ + boost_headers \ + libxml2 \ +)) + +$(eval $(call gb_Library_add_exception_objects,svgfilter,\ + filter/source/svg/svgfilter \ + filter/source/svg/svgexport \ + filter/source/svg/svgfontexport \ + filter/source/svg/svgwriter \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_t602filter.mk b/filter/Library_t602filter.mk new file mode 100644 index 000000000..f8ad92b96 --- /dev/null +++ b/filter/Library_t602filter.mk @@ -0,0 +1,47 @@ +# -*- 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,t602filter)) + +$(eval $(call gb_Library_set_include,t602filter,\ + $$(INCLUDE) \ + -I$(SRCDIR)/filter/inc \ +)) + +$(eval $(call gb_Library_set_componentfile,t602filter,filter/source/t602/t602filter,services)) + +$(eval $(call gb_Library_use_external,t602filter,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,t602filter)) + +$(eval $(call gb_Library_use_libraries,t602filter,\ + xo \ + tl \ + utl \ + cppuhelper \ + cppu \ + sal \ + i18nlangtag \ +)) + +$(eval $(call gb_Library_add_exception_objects,t602filter,\ + filter/source/t602/t602filter \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_textfd.mk b/filter/Library_textfd.mk new file mode 100644 index 000000000..d3318dcbd --- /dev/null +++ b/filter/Library_textfd.mk @@ -0,0 +1,36 @@ +# -*- 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/. +# +#************************************************************************* + +$(eval $(call gb_Library_Library,textfd)) + +$(eval $(call gb_Library_set_componentfile,textfd,filter/source/textfilterdetect/textfd,services)) + +$(eval $(call gb_Library_use_external,textfd,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,textfd)) + +$(eval $(call gb_Library_use_libraries,textfd,\ + comphelper \ + ucbhelper \ + cppuhelper \ + cppu \ + sal \ + sfx \ + tl \ + utl \ + svt \ +)) + +$(eval $(call gb_Library_add_exception_objects,textfd,\ + filter/source/textfilterdetect/filterdetect \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_xmlfa.mk b/filter/Library_xmlfa.mk new file mode 100644 index 000000000..35a2dd9ff --- /dev/null +++ b/filter/Library_xmlfa.mk @@ -0,0 +1,42 @@ +# -*- 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,xmlfa)) + +$(eval $(call gb_Library_set_componentfile,xmlfa,filter/source/xmlfilteradaptor/xmlfa,services)) + +$(eval $(call gb_Library_use_external,xmlfa,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,xmlfa)) + +$(eval $(call gb_Library_use_libraries,xmlfa,\ + comphelper \ + cppuhelper \ + cppu \ + sal \ + tl \ + utl \ + xo \ +)) + +$(eval $(call gb_Library_add_exception_objects,xmlfa,\ + filter/source/xmlfilteradaptor/XmlFilterAdaptor \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_xmlfd.mk b/filter/Library_xmlfd.mk new file mode 100644 index 000000000..a5c1d190c --- /dev/null +++ b/filter/Library_xmlfd.mk @@ -0,0 +1,42 @@ +# -*- 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,xmlfd)) + +$(eval $(call gb_Library_set_componentfile,xmlfd,filter/source/xmlfilterdetect/xmlfd,services)) + +$(eval $(call gb_Library_use_external,xmlfd,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,xmlfd)) + +$(eval $(call gb_Library_use_libraries,xmlfd,\ + ucbhelper \ + cppuhelper \ + cppu \ + sal \ + svl \ + utl \ + tl \ +)) + +$(eval $(call gb_Library_add_exception_objects,xmlfd,\ + filter/source/xmlfilterdetect/filterdetect \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_xsltdlg.mk b/filter/Library_xsltdlg.mk new file mode 100644 index 000000000..fd5f480e7 --- /dev/null +++ b/filter/Library_xsltdlg.mk @@ -0,0 +1,60 @@ +# -*- 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,xsltdlg)) + +$(eval $(call gb_Library_set_componentfile,xsltdlg,filter/source/xsltdialog/xsltdlg,services)) + +$(eval $(call gb_Library_use_external,xsltdlg,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,xsltdlg)) + +$(eval $(call gb_Library_set_include,xsltdlg,\ + $$(INCLUDE) \ + -I$(SRCDIR)/filter/inc \ +)) + +$(eval $(call gb_Library_use_libraries,xsltdlg,\ + sfx \ + svt \ + tk \ + vcl \ + svl \ + utl \ + tl \ + i18nlangtag \ + comphelper \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,xsltdlg,\ + filter/source/xsltdialog/typedetectionexport \ + filter/source/xsltdialog/typedetectionimport \ + filter/source/xsltdialog/xmlfilterdialogcomponent \ + filter/source/xsltdialog/xmlfilterjar \ + filter/source/xsltdialog/xmlfiltersettingsdialog \ + filter/source/xsltdialog/xmlfiltertabdialog \ + filter/source/xsltdialog/xmlfiltertabpagebasic \ + filter/source/xsltdialog/xmlfiltertabpagexslt \ + filter/source/xsltdialog/xmlfiltertestdialog \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Library_xsltfilter.mk b/filter/Library_xsltfilter.mk new file mode 100644 index 000000000..42f426c94 --- /dev/null +++ b/filter/Library_xsltfilter.mk @@ -0,0 +1,52 @@ +# -*- 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,xsltfilter)) + +$(eval $(call gb_Library_set_componentfile,xsltfilter,filter/source/xsltfilter/xsltfilter,services)) + +$(eval $(call gb_Library_use_sdk_api,xsltfilter)) + +$(eval $(call gb_Library_use_libraries,xsltfilter,\ + xo \ + tl \ + package2 \ + sax \ + comphelper \ + ucbhelper \ + cppuhelper \ + cppu \ + salhelper \ + sal \ +)) + +$(eval $(call gb_Library_use_externals,xsltfilter,\ + boost_headers \ + libxml2 \ + libxslt \ + libexslt \ +)) + +$(eval $(call gb_Library_add_exception_objects,xsltfilter,\ + filter/source/xsltfilter/LibXSLTTransformer \ + filter/source/xsltfilter/OleHandler \ + filter/source/xsltfilter/XSLTFilter \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Makefile b/filter/Makefile new file mode 100644 index 000000000..0997e6284 --- /dev/null +++ b/filter/Makefile @@ -0,0 +1,14 @@ +# -*- 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/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/filter/Module_filter.mk b/filter/Module_filter.mk new file mode 100644 index 000000000..c28c72705 --- /dev/null +++ b/filter/Module_filter.mk @@ -0,0 +1,72 @@ +# +# 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_Module_Module,filter)) + +$(eval $(call gb_Module_add_targets,filter,\ + Configuration_filter \ + CustomTarget_svg \ + Library_filterconfig \ + Library_icg \ + Library_msfilter \ + Library_odfflatxml \ + Library_pdffilter \ + Library_storagefd \ + Library_svgfilter \ + Library_graphicfilter \ + Library_t602filter \ + Library_textfd \ + Library_xmlfa \ + Library_xmlfd \ + Library_xsltdlg \ + Library_xsltfilter \ + Package_docbook \ + Package_xhtml \ + Package_xslt \ + UIConfig_filter \ +)) + +$(eval $(call gb_Module_add_l10n_targets,filter,\ + AllLangMoTarget_flt \ +)) + +$(eval $(call gb_Module_add_check_targets,filter,\ + CppunitTest_filter_xslt \ + CppunitTest_filter_priority \ + CppunitTest_filter_msfilter \ + CppunitTest_filter_textfilterdetect \ + CppunitTest_filter_pdf \ +)) + +ifneq ($(DISABLE_CVE_TESTS),TRUE) +$(eval $(call gb_Module_add_check_targets,filter,\ + CppunitTest_filter_svg \ +)) +endif + +# TODO +#$(eval $(call gb_Module_add_subsequentcheck_targets,filter,\ + JunitTest_filter_complex \ +)) + +# screenshots +$(eval $(call gb_Module_add_screenshot_targets,filter,\ + CppunitTest_filter_dialogs_test \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Package_docbook.mk b/filter/Package_docbook.mk new file mode 100644 index 000000000..6548fd6a1 --- /dev/null +++ b/filter/Package_docbook.mk @@ -0,0 +1,27 @@ +# +# 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_Package_Package,filter_docbook,$(SRCDIR)/filter/source/docbook)) + +$(eval $(call gb_Package_add_files,filter_docbook,$(LIBO_SHARE_FOLDER)/xslt/docbook,\ + DocBookTemplate.stw \ + docbooktosoffheadings.xsl \ + sofftodocbookheadings.xsl \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Package_xhtml.mk b/filter/Package_xhtml.mk new file mode 100644 index 000000000..91f9ff9ac --- /dev/null +++ b/filter/Package_xhtml.mk @@ -0,0 +1,26 @@ +# +# 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_Package_Package,filter_xhtml,$(SRCDIR)/filter/source/xslt)) + +$(eval $(call gb_Package_add_file,filter_xhtml,$(LIBO_SHARE_FOLDER)/xslt/export/xhtml/body.xsl,odf2xhtml/export/xhtml/body.xsl)) +$(eval $(call gb_Package_add_file,filter_xhtml,$(LIBO_SHARE_FOLDER)/xslt/export/xhtml/header.xsl,odf2xhtml/export/xhtml/header.xsl)) +$(eval $(call gb_Package_add_file,filter_xhtml,$(LIBO_SHARE_FOLDER)/xslt/export/xhtml/opendoc2xhtml.xsl,odf2xhtml/export/xhtml/opendoc2xhtml.xsl)) +$(eval $(call gb_Package_add_file,filter_xhtml,$(LIBO_SHARE_FOLDER)/xslt/export/xhtml/table.xsl,odf2xhtml/export/xhtml/table.xsl)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Package_xslt.mk b/filter/Package_xslt.mk new file mode 100644 index 000000000..3fe8ff92f --- /dev/null +++ b/filter/Package_xslt.mk @@ -0,0 +1,70 @@ +# +# 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_Package_Package,filter_xslt,$(SRCDIR)/filter/source/xslt)) + +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/common/copy.xsl,common/copy.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/common/math.xsl,common/math.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/common/measure_conversion.xsl,common/measure_conversion.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/ooo2ms_docpr.xsl,export/common/ooo2ms_docpr.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/spreadsheetml/formular.xsl,export/spreadsheetml/formular.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/spreadsheetml/ooo2spreadsheetml.xsl,export/spreadsheetml/ooo2spreadsheetml.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/spreadsheetml/style_mapping.xsl,export/spreadsheetml/style_mapping.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/spreadsheetml/styles.xsl,export/spreadsheetml/styles.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/spreadsheetml/table.xsl,export/spreadsheetml/table.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/uof/odf2uof_presentation.xsl,export/uof/odf2uof_presentation.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/uof/odf2uof_spreadsheet.xsl,export/uof/odf2uof_spreadsheet.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/uof/odf2uof_text.xsl,export/uof/odf2uof_text.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml.xsl,export/wordml/ooo2wordml.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_border.xsl,export/wordml/ooo2wordml_border.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_custom_draw.xsl,export/wordml/ooo2wordml_custom_draw.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_draw.xsl,export/wordml/ooo2wordml_draw.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_field.xsl,export/wordml/ooo2wordml_field.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_list.xsl,export/wordml/ooo2wordml_list.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_page.xsl,export/wordml/ooo2wordml_page.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_path.xsl,export/wordml/ooo2wordml_path.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_settings.xsl,export/wordml/ooo2wordml_settings.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_table.xsl,export/wordml/ooo2wordml_table.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/wordml/ooo2wordml_text.xsl,export/wordml/ooo2wordml_text.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/common/ms2ooo_docpr.xsl,import/common/ms2ooo_docpr.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/spreadsheetml/spreadsheetml2ooo.xsl,import/spreadsheetml/spreadsheetml2ooo.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/spreadsheetml/adorowset2ods.xsl,import/spreadsheetml/adorowset2ods.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/uof/uof2odf_presentation.xsl,import/uof/uof2odf_presentation.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/uof/uof2odf_spreadsheet.xsl,import/uof/uof2odf_spreadsheet.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/uof/uof2odf_text.xsl,import/uof/uof2odf_text.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo.xsl,import/wordml/wordml2ooo.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_custom_draw.xsl,import/wordml/wordml2ooo_custom_draw.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_draw.xsl,import/wordml/wordml2ooo_draw.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_field.xsl,import/wordml/wordml2ooo_field.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_list.xsl,import/wordml/wordml2ooo_list.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_page.xsl,import/wordml/wordml2ooo_page.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_path.xsl,import/wordml/wordml2ooo_path.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_props.xsl,import/wordml/wordml2ooo_props.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_settings.xsl,import/wordml/wordml2ooo_settings.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_table.xsl,import/wordml/wordml2ooo_table.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/import/wordml/wordml2ooo_text.xsl,import/wordml/wordml2ooo_text.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/body.xsl,odf2xhtml/export/common/body.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/styles/style_collector.xsl,odf2xhtml/export/common/styles/style_collector.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/styles/style_mapping_css.xsl,odf2xhtml/export/common/styles/style_mapping_css.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/table/table.xsl,odf2xhtml/export/common/table/table.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/table/table_cells.xsl,odf2xhtml/export/common/table/table_cells.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/table/table_columns.xsl,odf2xhtml/export/common/table/table_columns.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/table/table_rows.xsl,odf2xhtml/export/common/table/table_rows.xsl)) +$(eval $(call gb_Package_add_file,filter_xslt,$(LIBO_SHARE_FOLDER)/xslt/export/common/table_of_content.xsl,odf2xhtml/export/common/table_of_content.xsl)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/README.md b/filter/README.md new file mode 100644 index 000000000..19caeb73e --- /dev/null +++ b/filter/README.md @@ -0,0 +1,25 @@ +# LibreOffice Filters + +Filter registration and some simple filters (also descriptions). + +Desperate splitting of code into small shared libraries for historical +reasons presumably (OS/2 and Windows 3.x). The libraries produced from +the code in each subdirectory of `filter/source/graphicfilter` are +graphic format import or export filters. But they don't have uniform +API. Some have either a `GraphicImport` or `GraphicExport` entry point, +and are loaded and used in a uniform fashion from code in +`svtools/source/filter/filter.cxx`. Others have different API and are +loaded from other places. For instance `icgm` has `ImportCGM`, and is +loaded and used by `sd/source/filter/cgm/sdcgmfilter.cxx` (!). +Svgreader is used for "File -> Open" and then to choose the svg file. +For "Insert -> Picture -> From File", see `svgio/source/svgreader` directory. + +## Filter Configuration + +The filter configuration consists of two parts, the type definition in +`filter/source/config/fragments/types/` and the actual filter definition +in `filter/source/config/fragments/filters/`. + +Each file type e.g. text file should be represented by exactly one +type definition. This type can then be referenced by several different +filters, e.g. calc text, writer text. diff --git a/filter/UIConfig_filter.mk b/filter/UIConfig_filter.mk new file mode 100644 index 000000000..7d34128f5 --- /dev/null +++ b/filter/UIConfig_filter.mk @@ -0,0 +1,28 @@ +# -*- 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/. +# + +$(eval $(call gb_UIConfig_UIConfig,filter)) + +$(eval $(call gb_UIConfig_add_uifiles,filter,\ + filter/uiconfig/ui/pdfgeneralpage \ + filter/uiconfig/ui/pdflinkspage \ + filter/uiconfig/ui/pdfoptionsdialog \ + filter/uiconfig/ui/pdfsecuritypage \ + filter/uiconfig/ui/pdfsignpage \ + filter/uiconfig/ui/pdfuserinterfacepage \ + filter/uiconfig/ui/pdfviewpage \ + filter/uiconfig/ui/testxmlfilter \ + filter/uiconfig/ui/warnpdfdialog \ + filter/uiconfig/ui/xmlfiltersettings \ + filter/uiconfig/ui/xmlfiltertabpagegeneral \ + filter/uiconfig/ui/xmlfiltertabpagetransformation \ + filter/uiconfig/ui/xsltfilterdialog \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/inc/strings.hrc b/filter/inc/strings.hrc new file mode 100644 index 000000000..eecfdb33e --- /dev/null +++ b/filter/inc/strings.hrc @@ -0,0 +1,76 @@ +/* -*- 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 . + */ + +#pragma once + +#define NC_(Context, String) TranslateId(Context, reinterpret_cast(u8##String)) + +#define STR_UNKNOWN_APPLICATION NC_("STR_UNKNOWN_APPLICATION", "Unknown") +#define STR_IMPORT_ONLY NC_("STR_IMPORT_ONLY", "import filter") +#define STR_IMPORT_EXPORT NC_("STR_IMPORT_EXPORT", "import/export filter") +#define STR_EXPORT_ONLY NC_("STR_EXPORT_ONLY", "export filter") +#define STR_WARN_DELETE NC_("STR_WARN_DELETE", "Do you really want to delete the XML Filter '%s'? This action cannot be undone.") +#define STR_ERROR_FILTER_NAME_EXISTS NC_("STR_ERROR_FILTER_NAME_EXISTS", "An XML filter with the name '%s' already exists. Please enter a different name.") +#define STR_ERROR_TYPE_NAME_EXISTS NC_("STR_ERROR_TYPE_NAME_EXISTS", "The name for the user interface '%s1' is already used by the XML filter '%s2'. Please enter a different name.") +#define STR_ERROR_EXPORT_XSLT_NOT_FOUND NC_("STR_ERROR_EXPORT_XSLT_NOT_FOUND", "The XSLT for export cannot be found. Please enter a valid path.") +#define STR_ERROR_IMPORT_XSLT_NOT_FOUND NC_("STR_ERROR_IMPORT_XSLT_NOT_FOUND", "The XSLT for import cannot be found. Please enter a valid path.") +#define STR_ERROR_IMPORT_TEMPLATE_NOT_FOUND NC_("STR_ERROR_IMPORT_TEMPLATE_NOT_FOUND", "The given import template cannot be found. Please enter a valid path.") +#define STR_DEFAULT_FILTER_NAME NC_("STR_DEFAULT_FILTER_NAME", "New Filter") +#define STR_DEFAULT_UI_NAME NC_("STR_DEFAULT_UI_NAME", "Untitled") +#define STR_UNDEFINED_FILTER NC_("STR_UNDEFINED_FILTER", "undefined filter") +#define STR_FILTER_HAS_BEEN_SAVED NC_("STR_FILTER_HAS_BEEN_SAVED", "The XML filter '%s' has been saved as package '%s'. ") +#define STR_FILTERS_HAVE_BEEN_SAVED NC_("STR_FILTERS_HAVE_BEEN_SAVED", "%s XML filters have been saved in the package '%s'.") +#define STR_FILTER_PACKAGE NC_("STR_FILTER_PACKAGE", "XSLT filter package") +#define STR_FILTER_INSTALLED NC_("STR_FILTER_INSTALLED", "The XML filter '%s' has been installed successfully.") +#define STR_FILTERS_INSTALLED NC_("STR_FILTERS_INSTALLED", "%s XML filters have been installed successfully.") +#define STR_NO_FILTERS_FOUND NC_("STR_NO_FILTERS_FOUND", "No XML filter could be installed because the package '%s' does not contain any XML filters.") +#define STR_XML_FILTER_LISTBOX NC_("STR_XML_FILTER_LISTBOX", "XML Filter List") + +#define T602FILTER_STR_IMPORT_DIALOG_TITLE NC_("T602FILTER_STR_IMPORT_DIALOG_TITLE", "Settings for T602 import") +#define T602FILTER_STR_ENCODING_LABEL NC_("T602FILTER_STR_ENCODING_LABEL", "Encoding") +#define T602FILTER_STR_ENCODING_AUTO NC_("T602FILTER_STR_ENCODING_AUTO", "Automatic") +#define T602FILTER_STR_ENCODING_CP852 NC_("T602FILTER_STR_ENCODING_CP852", "CP852 (Latin2)") +#define T602FILTER_STR_ENCODING_CP895 NC_("T602FILTER_STR_ENCODING_CP895", "CP895 (KEYB2CS, Kamenicky)") +#define T602FILTER_STR_ENCODING_KOI8CS2 NC_("T602FILTER_STR_ENCODING_KOI8CS2", "KOI8 CS2") +#define T602FILTER_STR_CYRILLIC_MODE NC_("T602FILTER_STR_CYRILLIC_MODE", "Mode for Russian language (Cyrillic)") +#define T602FILTER_STR_REFORMAT_TEXT NC_("T602FILTER_STR_REFORMAT_TEXT", "Reformat the text") +#define T602FILTER_STR_DOT_COMMANDS NC_("T602FILTER_STR_DOT_COMMANDS", "Display dot commands") +#define T602FILTER_STR_CANCEL_BUTTON NC_("T602FILTER_STR_CANCEL_BUTTON", "Cancel") +#define T602FILTER_STR_OK_BUTTON NC_("T602FILTER_STR_OK_BUTTON", "OK") + +#define PDF_PROGRESS_BAR NC_("PDF_PROGRESS_BAR", "Export as PDF") + +//strings used in encryption UI +//password dialog title +#define STR_PDF_EXPORT_UDPWD NC_("STR_PDF_EXPORT_UDPWD", "Set open password") +//password dialog title +#define STR_PDF_EXPORT_ODPWD NC_("STR_PDF_EXPORT_ODPWD", "Set permission password") +#define STR_WARN_PASSWORD_PDFA NC_("STR_WARN_PASSWORD_PDFA", "PDF/A does not allow encryption. The exported PDF file will not be password protected.") +#define STR_WARN_TRANSP_PDFA_SHORT NC_("STR_WARN_TRANSP_PDFA_SHORT", "PDF/A transparency") +#define STR_WARN_TRANSP_PDFA NC_("STR_WARN_TRANSP_PDFA", "PDF/A forbids transparency. A transparent object was painted opaque instead.") +#define STR_WARN_TRANSP_VERSION_SHORT NC_("STR_WARN_TRANSP_VERSION_SHORT", "PDF version conflict") +#define STR_WARN_TRANSP_VERSION NC_("STR_WARN_TRANSP_VERSION", "Transparency is not supported in PDF versions earlier than PDF 1.4. A transparent object was painted opaque instead") +#define STR_WARN_FORMACTION_PDFA_SHORT NC_("STR_WARN_FORMACTION_PDFA_SHORT", "PDF/A form action") +#define STR_WARN_FORMACTION_PDFA NC_("STR_WARN_FORMACTION_PDFA", "A form control contained an action not supported by the PDF/A standard. The action was skipped") +#define STR_WARN_TRANSP_CONVERTED NC_("STR_WARN_TRANSP_CONVERTED", "Some objects were converted to an image in order to remove transparencies, because the target PDF format does not support transparencies. Possibly better results can be achieved if you remove the transparent objects before exporting.") +#define STR_WARN_TRANSP_CONVERTED_SHORT NC_("STR_WARN_TRANSP_CONVERTED_SHORT", "Transparencies removed") +#define STR_ERR_SIGNATURE_FAILED NC_("STR_ERR_SIGNATURE_FAILED", "Signature generation failed") +#define STR_ERR_PDF_EXPORT_ABORTED NC_("STR_ERR_PDF_EXPORT_ABORTED", "PDF export aborted") + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/inc/strings.hxx b/filter/inc/strings.hxx new file mode 100644 index 000000000..eeeb161b9 --- /dev/null +++ b/filter/inc/strings.hxx @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#pragma once + +#include + +inline constexpr OUStringLiteral STR_APPL_NAME_WRITER = u"%PRODUCTNAME Writer (.sxw)"; +inline constexpr OUStringLiteral STR_APPL_NAME_CALC = u"%PRODUCTNAME Calc (.sxc)"; +inline constexpr OUStringLiteral STR_APPL_NAME_IMPRESS = u"%PRODUCTNAME Impress (.sxi)"; +inline constexpr OUStringLiteral STR_APPL_NAME_DRAW = u"%PRODUCTNAME Draw (.sxd)"; +inline constexpr OUStringLiteral STR_APPL_NAME_OASIS_WRITER = u"%PRODUCTNAME Writer (.odt)"; +inline constexpr OUStringLiteral STR_APPL_NAME_OASIS_CALC = u"%PRODUCTNAME Calc (.ods)"; +inline constexpr OUStringLiteral STR_APPL_NAME_OASIS_IMPRESS = u"%PRODUCTNAME Impress (.odp)"; +inline constexpr OUStringLiteral STR_APPL_NAME_OASIS_DRAW = u"%PRODUCTNAME Draw (.odg)"; +inline constexpr OUStringLiteral STR_DEFAULT_EXTENSION = u"xml"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/filter/qa/complex/filter/detection/typeDetection/Helper.java b/filter/qa/complex/filter/detection/typeDetection/Helper.java new file mode 100644 index 000000000..23eb07fc4 --- /dev/null +++ b/filter/qa/complex/filter/detection/typeDetection/Helper.java @@ -0,0 +1,431 @@ +/* + * 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 . + */ + +package complex.filter.detection.typeDetection; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.io.NotConnectedException; +import com.sun.star.io.XInputStream; + +import helper.StreamSimulator; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.ArrayList; + +import lib.TestParameters; +import share.LogWriter; +import util.PropertyName; +import util.utils; + + + +/** Helper class for "TypeDetection" + * This class do file handling. + */ +public class Helper { + + /** The runner log writer + * @member m_log for log purposes + * @member m_sTestDocPath directory for searching files to load + * @member m_vFiles list of all files described in "files.csv" + * @member m_hFileURLs contains the position of a file name in the m_vFiles Vector + * @member m_hFileTypes contains the position of a file type in the m_vFiles Vector + * @member m_param the test parameters + */ + + private final LogWriter m_log; + + private final String m_sTestDocPath; + + private final ArrayList> m_vFiles; + + private final HashMap m_hFileURLs = new HashMap(); + + private final HashMap m_hFileTypes = new HashMap(); + + private final TestParameters m_param; + + /** + * construct a new instance of this class + * It creates the "todo" list and position lists for URL and + * and Type inside the "todo" list + * + * @param param the test parameters + * + * @param log the log writer + */ + + public Helper(TestParameters param, LogWriter log) { + + m_param = param; + m_log = log; + + + // get all files from the given directory + m_sTestDocPath = (String)param.get("TestDocumentPath"); + + // get all files from "files.csv" + m_vFiles = getToDoList((String)m_param.get("csv.files")); + + createFilesList(); + } + + + /** Reads a comma separated file (CSV). Every line of the file is + * represented by an Vector entry. Every data entry of a row is + * also stored in a Vector. So the returned value is a + * Vector[][] where the first dimension represents a row + * and the second dimension includes the data values. + * @param csvFileName the name of the csv file + * @return Vector filled with Vector filled with data of a row + */ + public ArrayList> getToDoList(String csvFileName){ + + try { + + ArrayList> vAll = new ArrayList>(); + ArrayList vFields = new ArrayList(); + + // get content of file + ArrayList content = getCSVFileContent(csvFileName); + + // remove superfluous content like "#" started lines + content = removeSuperfluousContent(content); + + // replace all place holders in file + content = replacePlaceHolder(content); + + // create Enumeration + Iterator contentEnum = content.iterator(); + + // the first line contains field names of the columns + // split line by ";" + StringTokenizer fields = new StringTokenizer( + contentEnum.next(),";"); + int fieldCount = 0; + while (fields.hasMoreElements()){ + vFields.add(fields.nextToken()); + fieldCount++; + } + + // fill vData with data of CSV-row + while (contentEnum.hasNext()){ + ArrayList vData = new ArrayList(); + + StringTokenizer data = new StringTokenizer( + contentEnum.next(),";", true); + + // example: data = "firstData;secondData;;forthData" + // => three tokens => missing one data because the imagine + // "thirdData" was not received by data.nextToken() + // Therefore here comes a special handling for empty data + boolean nextIsData = false; + int dataCount = 0; + while (data.hasMoreTokens()) { + String myToken = data.nextToken(); + // if the "thirdData" will be received, myToken=";" but + // vData must add an empty String + if (myToken.equals(";")){ + if (nextIsData ) { + vData.add(""); + dataCount++; + nextIsData = false; + } + nextIsData = true; + } else { + vData.add(myToken); + dataCount++; + nextIsData = false; + } + } + for (int i=dataCount; i < fieldCount; i++) vData.add(""); + vAll.add(vData); + } + + + return vAll; + + } catch(ClassCastException e) { + e.printStackTrace(); + } + return null; + } + + /** The csv files "files", "preselectedFilter", "preselectedType" and + * "serviceName" are delivered beside this class. This function seeks for + * the csv files and read them. + * @param csvFileName the name of the csv file + * @return a Vector containing the content of the file. if the file + * cannot be read + */ + + private ArrayList getCSVFileContent(String csvFileName) { + try { + ArrayList content = new ArrayList(); + BufferedReader br; + String line; + if ( m_param.getBool(PropertyName.DEBUG_IS_ACTIVE) ) { + System.out.println("Looking for "+csvFileName); + } + + URL url = getClassURL(csvFileName); + + if (url != null) { + URLConnection connection = url.openConnection(); + InputStream in = connection.getInputStream(); + + br = new BufferedReader(new InputStreamReader(in)); + try { + while( ( line = br.readLine() ) != null ) { + content.add( line ); + } + } catch (IOException e) { + br.close(); + return null; + } + br.close(); + return content; + } + + }catch (IOException e) { + }catch(NullPointerException e) { + return null; + } + return null; + } + + /** returns a XInputStream of given file + * @param filePath the path to the file which should be loaded + * @return the XInputStream, if the + * file cannot be read + * @throws NotConnectedException was thrown if it was not possible to open filePath + */ + public XInputStream getFileStream( String filePath ) + throws NotConnectedException { + return new StreamSimulator(filePath, true, m_param); + } + + /** replaces place holder in preselectedFilter. + * Because of filter names depend on StarOffice version like + * "StarOffice 6.0 Textdokument" or ""StarSuite 7 Textdokument" + * The filter names must be changed. The place holder will be replaced + * by an equivalent in "typeDetection.props" + * @param content the content of a csv file + * @return changed file content + */ + private ArrayList replacePlaceHolder(ArrayList content){ + + ArrayList vReturn = new ArrayList(); + + ArrayList placeHolders = new ArrayList(); + Iterator paramsIter = m_param.keySet().iterator(); + String placeHolder = (String)m_param.get("placeHolder"); + + // get all place holders from typeDetection.csv + while (paramsIter.hasNext()){ + String holderKey = paramsIter.next(); + if (holderKey.startsWith(placeHolder)){ + placeHolders.add(holderKey); + } + } + + // replace all occurrences of place holders in 'CSVData' + Iterator cont = content.iterator(); + + while( cont.hasNext() ) { + + String line = cont.next(); + String newLine = line; + Iterator holders = placeHolders.iterator(); + + while( holders.hasNext() ) { + + String holder = holders.next(); + int startPos = line.indexOf(holder); + + if (startPos > -1){ + try{ + String holderValue = (String) m_param.get(holder); + + newLine = newLine.substring(0,startPos) + holderValue + + newLine.substring(startPos + holder.length()); + + } catch (java.lang.IndexOutOfBoundsException e){ + m_log.println("ERROR: problems while creating placeholder" + + " replaced list: "+ e); + } + } + } + vReturn.add(newLine); + } + return vReturn; + } + + /** Removes lines of an ascii file content which starts with "#" + * or are empty + * @param content content of a csv file + * @return a stripped Vector + */ + private ArrayList removeSuperfluousContent(ArrayList content){ + ArrayList newContent = new ArrayList(); + Iterator cont = content.iterator(); + while( cont.hasNext() ) { + String line = cont.next(); + if (( ! line.startsWith( "#" ))&& ( line.length() != 0 )) { + newContent.add( line ); + } + } + return newContent; + } + + /** returns a MediaDescriptor filled with given properties and + * values. + * @param propNames String Array of property names + * @param values Object Array of property values + * @return PropertyValue[] + * @see com.sun.star.beans.PropertyValue + * @see com.sun.star.document.MediaDescriptor + */ + public PropertyValue[] createMediaDescriptor(String[] propNames, Object[] values) { + PropertyValue[] props = new PropertyValue[propNames.length] ; + + for (int i = 0; i < props.length; i++) { + props[i] = new PropertyValue() ; + props[i].Name = propNames[i] ; + if (values != null && i < values.length) { + props[i].Value = values[i] ; + } + } + + return props ; + } + + /** Appends system file separator if needed + * @param s the system path + * @return system path with ending system file separator + */ + public String ensureEndingFileSep(String s){ + if(s != null && !s.equals("") && !s.endsWith(File.separator)){ + s = s.trim() + File.separator; + }else if(s == null) + s = ""; + return s; + } + + /** Returns the file URL for the given file name assembled by + * "TestDocumentPath" of typeDetection.props and "fileURL" of files.csv + * @param fileAlias the alias name of the file + * @return file URL + * @throws FileAliasNotFoundException was thrown if alias does not exist + */ + public String getURLforfileAlias(String fileAlias) + throws FileAliasNotFoundException{ + try{ + String fileURL = m_hFileURLs.get(fileAlias).toString(); + return utils.getFullURL(ensureEndingFileSep(m_sTestDocPath) + fileURL); + } catch (NullPointerException e){ + throw new FileAliasNotFoundException(fileAlias, e); + } + + } + + /** Returns the file type for the given file name containing in files.csv + * @param fileAlias the alias name of the file + * @return file type + * @throws FileAliasNotFoundException was thrown if not alias was thrown + */ + public String getTypeforfileAlias(String fileAlias) + throws FileAliasNotFoundException{ + try{ + return m_hFileTypes.get(fileAlias).toString(); + } catch (NullPointerException e){ + throw new FileAliasNotFoundException(fileAlias, e); + } + } + + /** + * Fills the Hashtable m_hFileURLs with all file names and their URL + * and the Hashtable m_hFileTypes with all file names and their file + * type name. This information is extracted from "files.csv" + * This is for faster access to get fileURL and fileType of fileAlias + */ + private void createFilesList(){ + for (int i = 0; i < m_vFiles.size();i++){ + ArrayList toDo = m_vFiles.get(i); + m_hFileURLs.put(toDo.get(0), toDo.get(1)); + m_hFileTypes.put(toDo.get(0), toDo.get(2)); + } + } + + + /** Validate the returned file type for the file alias with the + * possible file types + * @param currentFileType the returned file type + * @param fileTypes all possible file types + * @return true if valid + */ + public boolean checkFileType(String currentFileType, String fileTypes){ + + StringTokenizer data = new StringTokenizer(fileTypes,":", true); + + boolean found = false; + while (data.hasMoreElements()) { + + String actualFileType = data.nextElement().toString(); + + found = found || currentFileType.equals(actualFileType); + } + return found; + } + + /** creates an input/output parameter of PropertyValue[]. + * @return PropertyValue[][] + * @param PropVal a PropertyValue + */ + public PropertyValue[][] createInOutPropertyValue(PropertyValue[] PropVal){ + PropertyValue[][] dummy = new PropertyValue[1][]; + dummy[0] = PropVal; + return dummy; + } + + private URL getClassURL(String fileName){ + String PackagePath = this.getClass().getPackage().getName().replace('.','/'); + return this.getClass().getResource("/" + PackagePath +"/" + fileName); + } + + public String getClassURLString(String fileName){ + return getClassURL(fileName).toString().replaceAll("file:",""); + } + + +} + +/** This exception should be thrown if a method seeks for an invalid alias name */ +class FileAliasNotFoundException extends java.lang.Exception{ + /** throws error message with wrong alias name + * @param fileAlias the alias name + */ + public FileAliasNotFoundException(String fileAlias, Throwable cause){ + super("Could not get '"+fileAlias +"'", cause); + } +} diff --git a/filter/qa/complex/filter/detection/typeDetection/TypeDetection.java b/filter/qa/complex/filter/detection/typeDetection/TypeDetection.java new file mode 100644 index 000000000..2c7a6934a --- /dev/null +++ b/filter/qa/complex/filter/detection/typeDetection/TypeDetection.java @@ -0,0 +1,546 @@ +/* + * 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 . + */ +package complex.filter.detection.typeDetection; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.document.XTypeDetection; +import com.sun.star.io.NotConnectedException; +import com.sun.star.io.XInputStream; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import complexlib.ComplexTestCase; +import java.io.File; + +import java.util.Iterator; +import java.util.ArrayList; +import util.utils; + + + +/** Check "TypeDetection" + *

+ * This test will check the file type detection. This will be done by filling + * properties of a MediaDescriptor. + * + * In the test method checkByURLonly the + * MediaDescriptor was filled at once with the URL of a test + * file. At second it was filled with a XInputStream from test + * file. In both subtests the returned file type must match with an expected + * type. + * + * In the test method checkPreselectedType the + * MediaDescriptor was filled with the URL of the test file and + * with the name of a type which should be used. The returned type of the + * TypeDetection must match with an expected type. + * + * In the test method checkPreselectedFilter the + * MediaDescriptor was filled with the URL of the test file and + * with the name of a filter which should be used. The returned type of the + * TypeDetection must match with an expected type. + * + * In the test method checkPreselectedDocService the + * MediaDescriptor was filled with the URL of the test file and + * with the name of a document service which should be used. The returned type + * of the TypeDetection must match with an expected type. + * + * + * To get information on which test file should support which type, filter and + * document service, this information was collected from configuration files: + *

+ *

+ *

+ * typeDetection.props

+ * At first there will be the typeDetection.props. Here the following + * properties should be set (with example values): + * + * TestDocumentPath=file:///path/to/my/testdocuments + * placeHolder=% + * %SO6productname=StarOffice + * %SO6formatversion=6.0 + * + * TestDocumentPath: this is the path to your test documents. If + * you have grouped your documents ie. by writer, calc, ... then it should be + * the root path. To specify the particular sub folders you have to use + * csv.files + *

+ * files.csv: In this file all test documents are listed. + * Syntax: fileAlias;fileURL;defaultURLFileType;StreamFileTypes + * Example: + * + * Writer6_1;Writer/Writer6.sxw;writer_StarOffice_XML_Writer;writer_StarOffice_XML_Writer + * text1;Writer/Text.txt:generic_Text:generic_Text + * + * The first example shows you the following: + * Writer6_1 is a free chosen name + * Writer/Writer6.sxw is the document path. This will be assembled + * by TestDocumentPath from typeDetection.props. + * writer_StarOffice_XML_Writer: this is the default file type of + * this file + * + * The second example displays two document types for + * XInputStream (generic_Text). These + * two document types are listed by a colon ':' as separator. + * This is needed because XInputStream can detect a text file as + * generic_Text. + *

+ * + *

+ * preselectedFilter.csv

+ * In this file you can choose a special + * filter to detect the document. This makes sense ie. for csv-files: You can + * open csv files as Writer or as Calc. To check this case you have to specify + * in csv.files a fileAlias like ?csv_writer? and ?csv_calc? with + * the same fileURL and its specific defaultFileType. + * The returned file type by TypeDetection must be equal to the + * corresponding defaultFileType from csv.files + * + * Syntax: fileAlias;FilterName;FilterOptions;FilterData + * Example: Writer6_1;%SO6productname %SO6formatversion Textdocument; + * + * The example shows the following: + * Writer6_1 is the same as in csv.files + * %SO6productname %SO6formatversion Textdokument is the filter + * name which should be used. Here we have a special: %SO6productname + * %SO6formatversion will be replaced by the equals of + * typeDetection.props. The filter names depends on the Office + * name and version. So a future Office could be called ?StarSuite 8?. + * FilterOptions is not relevant for this filter. But ie. for csv + * filter this entry could be used to specify the separator of the csv file. + * FilterData if filter needs some FilterData arguments you can + * specify them here + * + *

+ *

+ * preselectedType.csv

+ * In this file you can preselect the type + * TypeDetection should use. + * The file type returned by TypeDetection must be equal to the + * preselected file type. + * Note: If you try to use invalid types you will get a failed test because + * TypeDetection tries to find out the type itself. + * + * Syntax: fileAlias;fileType + * Example: Writer6_1;writer_StarOffice_XML_Writer + * + * This example shows the following: + * Writer6_1 is the same as in csv.files + * writer_StarOffice_XML_Writer is the file type which was used as + * parameter in MediaDescriptor. This type must be returned from + * TypeDetection + * + *

+ *

+ * serviceName.csv

In this file you can preselect a service name + * to detect the file type. The file type returned by + * TypeDetection must be equal to the corresponding + * defaultFileType from csv.files + * + * Syntax: fileAlias;serviceName + * Example: Writer6_1;com.sun.star.text.FormatDetector + * + * This example shows the following: + * Writer6_1 is the same as in csv.files + * com.sun.star.text.FormatDetector is the service name which was + * used as parameter in MediaDescriptor. + * + * + *

+ * All these files will be copied by make file beside of + * typeDetection.class. + * @see com.sun.star.document.XTypeDetection + * @see com.sun.star.document.MediaDescriptor + */ +public class TypeDetection extends ComplexTestCase { + + /** + * @member m_xDetection the object to test + * @member helper instance of helper class + */ + + static XTypeDetection m_xDetection; + static Helper helper = null; + + /** + * A function to tell the framework, which test functions are available. + * @return All test methods. + */ + @Override + public String[] getTestMethodNames() { + return new String[]{"checkByURLonly", + "checkPreselectedType", + "checkPreselectedFilter", + "checkPreselectedDocService", + "checkStreamLoader", + "checkStreamLoader"}; + + } + + /** Create the environment for following tests. + * Use either a component loader from desktop or + * from frame + * @throws Exception Exception + */ + public void before() throws Exception { + + // create TypeDetection + XMultiServiceFactory xMSF = param.getMSF(); + assure("Could not get XMultiServiceFactory", xMSF != null); + + Object oInterface = xMSF.createInstance( + "com.sun.star.document.TypeDetection"); + + if (oInterface == null) { + failed("Service wasn't created") ; + } + + XInterface oObj = (XInterface) oInterface ; + log.println("ImplName: "+utils.getImplName(oObj)); + + m_xDetection = UnoRuntime.queryInterface(XTypeDetection.class, oInterface); + Iterator k = param.keySet().iterator(); + while (k.hasNext()){ + String kName = k.next(); + log.println(kName + ":" + param.get(kName).toString()); + } + // create instance of helper class + helper = new Helper(param, log); + + } + + /** + * close the environment + */ + public void after() { + } + + /** + * The MediaDescriptor was filled with the URL of a file. The + * type of the file is known and must be returned by + * MediaDescriptor + * + * Syntax of files.csv: + * fileAlias;fileURL;fileType + * + */ + public void checkByURLonly() { + try{ + log.println("### checkByURLonly() ###"); + ArrayList> CSVData = helper.getToDoList( + (String)param.get("csv.files")); + Iterator> allToDos = CSVData.iterator(); + + while (allToDos.hasNext()){ + ArrayList toDo = allToDos.next(); + + String fileAlias = toDo.get(0); + String fileURL = toDo.get(1); + String URLfileType = toDo.get(2); + String StreamfileType = toDo.get(3); + + fileURL = utils.getFullURL(helper.ensureEndingFileSep( + (String)param.get("TestDocumentPath")) + fileURL); + + log.println("actual '"+ fileAlias + + "' ['" + URLfileType + "']: '" + fileURL); + + checkMediaDescriptorURL(fileAlias, fileURL, URLfileType); + checkMediaDescriptorXInputStream(fileAlias, fileURL, StreamfileType); + } + + } catch (ClassCastException e){ + failed(e.toString(), ContinueWithTest.YES); + } + } + + /** To check the TypeDetection by URL the MediaDescriptor + * was filled at first with the URL only, at second with XInputStream + * only. The TypeDetection must return the expected value + * @param fileAlias the alias name of the test file + * @param fileURL the URL of the test file + * @param fileType the expected type of the test file + * @see com.sun.star.document.MediaDescriptor + */ + private void checkMediaDescriptorURL( + String fileAlias, String fileURL, String fileType){ + + PropertyValue[] MediaDescriptor = helper.createMediaDescriptor( + new String[] {"URL"}, + new Object[] {fileURL}); + log.println("check only by URL..."); + + String type = m_xDetection.queryTypeByDescriptor( + helper.createInOutPropertyValue(MediaDescriptor), true); + + boolean fileTypeOK = helper.checkFileType(type, fileType); + + assure("\nURL-test : " + fileAlias + ":\n\treturned type: '" + type + + "'\n\texpected type: '" + fileType + "'",fileTypeOK ,ContinueWithTest.YES); + } + + /** Fills a MediaDescriptor with a XInputStream of the test + * file given by URL. + * Then the MediaDescriptor was used as parameter for TypeDetection. + * The TypeDetection must return expected type + * @param fileAlias the alias name of the test file + * @param fileURL the URL of the test file + * @param fileType the expected type of the test file + * @see com.sun.star.document.MediaDescriptor + * @see com.sun.star.io.XInputStream + */ + private void checkMediaDescriptorXInputStream( + String fileAlias, String fileURL, String fileType){ + + XInputStream xStream = null; + + try{ + xStream = helper.getFileStream( fileURL ); + } catch (NotConnectedException e) { + failed("Could not get XInputStream from file :'" + fileURL + "'",ContinueWithTest.YES); + return; + } + + PropertyValue[] MediaDescriptor = helper.createMediaDescriptor( + new String[] {"InputStream"}, + new Object[] {xStream}); + log.println("check only by XInputStream..."); + + String type = m_xDetection.queryTypeByDescriptor( + helper.createInOutPropertyValue(MediaDescriptor), true); + + boolean fileTypeOK = helper.checkFileType(type, fileType); + + assure("\nXInputStream-test: " + fileAlias + ":\n\treturned type: '" + type + + "'\n\texpected type: '" + fileType + "'", fileTypeOK, ContinueWithTest.YES); + + } + + /** + * The MediaDescriptor was filled with the URL of a file. The + * type of the file is known and must be returned by + * MediaDescriptor + * + * Syntax of files.csv: + * fileAlias;fileURL;fileType + * + */ + public void checkPreselectedType() { + try{ + log.println("### checkPreselectedType() ###"); + + ArrayList> CSVData = helper.getToDoList( + (String)param.get("csv.preselectedType")); + Iterator> allToDos = CSVData.iterator(); + + while (allToDos.hasNext()){ + try{ + ArrayList toDo = allToDos.next(); + + String fileAlias = toDo.get(0); + String fileURL = helper.getURLforfileAlias(fileAlias); + String preselectFileType = toDo.get(1); + String expectedFileType = toDo.get(2); + + PropertyValue[] MediaDescriptor = helper.createMediaDescriptor( + new String[] {"URL", "MediaType"}, + new Object[] {fileURL, preselectFileType}); + log.println("check '" + fileAlias + "' with MediaType: '" + + preselectFileType + "'"); + + String type = m_xDetection.queryTypeByDescriptor( + helper.createInOutPropertyValue(MediaDescriptor), true); + + boolean fileTypeOK = helper.checkFileType(type, expectedFileType); + + assure("\n" + fileAlias + ":\n\treturned type: '" + type + + "'\n\texpected type: '" + expectedFileType + "'", + fileTypeOK, ContinueWithTest.YES); + + } catch (FileAliasNotFoundException e){ + failed(e.toString(),ContinueWithTest.YES); + } + + } + + } catch (ClassCastException e){ + failed(e.toString(), ContinueWithTest.YES); + } + } + + + /** + * Check loading from a stream. The source for the stream is the + * first fileAlias that matches "*.txt" in the file list + * of the given directory. + */ + public void checkPreselectedFilter() { + try{ + log.println("### checkPreselectedFilter() ###"); + + ArrayList> CSVData = helper.getToDoList( + (String)param.get("csv.preselectedFilter")); + Iterator> allToDos = CSVData.iterator(); + + while (allToDos.hasNext()){ + try{ + ArrayList toDo = allToDos.next(); + + String fileAlias = toDo.get(0); + String fileURL = helper.getURLforfileAlias(fileAlias); + String filterName = toDo.get(1); + String filterOptions = toDo.get(2); + String filterData = toDo.get(3); + String expectedType = toDo.get(4); + + PropertyValue[] MediaDescriptor = helper.createMediaDescriptor( + new String[] {"URL","FilterName", + "FilterOptions","FilterData"}, + new Object[] {fileURL, filterName, + filterOptions, filterData}); + + log.println("check '" + fileAlias + "' with filter: '" + + filterName + "'"); + + String type = m_xDetection.queryTypeByDescriptor( + helper.createInOutPropertyValue(MediaDescriptor), true); + + boolean fileTypeOK = helper.checkFileType(type, expectedType); + + assure("\n" + fileAlias + ":\n\treturned type: '" + type + + "'\n\texpected type: '" + expectedType + "'", + fileTypeOK,ContinueWithTest.YES); + + } catch (FileAliasNotFoundException e){ + failed(e.toString(),ContinueWithTest.YES); + } + + } + + } catch (ClassCastException e){ + failed(e.toString(), ContinueWithTest.YES); + } + } + + /** + * Check URL encoding. The first fileAlias that matches "*.sxw" + * is used as source for several encodings. + */ + public void checkPreselectedDocService() { + try{ + log.println("### checkPreselectedDocService() ###"); + + ArrayList> CSVData = helper.getToDoList((String)param.get("csv.serviceName")); + Iterator> allToDos = CSVData.iterator(); + + while (allToDos.hasNext()){ + try{ + ArrayList toDo = allToDos.next(); + + String fileAlias = toDo.get(0); + String fileURL = helper.getURLforfileAlias(fileAlias); + String serviceName = toDo.get(1); + String fileType = helper.getTypeforfileAlias(fileAlias); + + PropertyValue[] MediaDescriptor = helper.createMediaDescriptor( + new String[] {"URL", "DocumentService"}, + new Object[] {fileURL, serviceName}); + log.println("check " + fileAlias); + + String type = m_xDetection.queryTypeByDescriptor( + helper.createInOutPropertyValue(MediaDescriptor), true); + + boolean fileTypeOK = helper.checkFileType(type, fileType); + + assure("\n" + fileAlias + ":\n\treturned type: '" + type + + "'\t\nexpected type: '" + fileType + "'", + fileTypeOK, ContinueWithTest.YES); + + } catch (FileAliasNotFoundException e){ + failed(e.toString(),ContinueWithTest.YES); + } + + } + + } catch (ClassCastException e){ + failed(e.toString(), ContinueWithTest.YES); + } + } + + public void checkStreamLoader(){ + try{ + + /* + * As files, use the typeDetection.props and one of the csv files. + * Those can, via dmake, simply set rights on others. + * + */ + log.println("### checkStreamLoader() ###"); + String[] urls = new String[] { + helper.getClassURLString("TypeDetection.props"), + helper.getClassURLString("files.csv") }; + + for (int j=0; jcom.sun.star.document.FilterFactory and + * com.sun.star.document.TypeDetection. + * + * Each of these services represent a container of PropertyValue[]. + * The PropertyValue[] contains among others the properties called + * Finalized and Mandatory. If the property + * Finalized is set to true, a filter can be removed + * but will not be able to be changed. + * If the property Mandatory is set to true, the filter + * can not be removed. + * + * Every filter, which is registered to the office, will be tested. For every filter-test + * a new instance of the mentioned services will be created. + + * During the test the property UIName + * will be changed and the service will be flushed. The test checks for expected exceptions: + * If the property Finalized equals + * true the tests check if an Exception must be thrown. + * The next step of the test is the removal of the filter was removed, then the service + * will be flushed. The test checks for expected exceptions: If the property + * Mandatory equals true, an Exception must + * be thrown. + * This test results false state if there is no filter available with: + * Finalized=true + * Finalized=false + * Mandatory=true + * Mandatory=false + */ +public class FinalizedMandatoryTest +{ + + XMultiServiceFactory xMSF; + + /** Create the environment for following tests. + * Use either a component loader from desktop or + * from frame + * @throws Exception Exception + */ + @Before public void before() throws Exception + { + + // create TypeDetection + xMSF = getMSF(); + assertNotNull("Could not get XMultiServiceFactory", xMSF); + + } + + /** + * Creates an instance for the given serviceName + * @param serviceName the name of the service which should be created + * @throws Exception was thrown if creation fails + * @return XInterface of service + */ + private XInterface getTestObject(String serviceName) throws Exception + { + + Object oInterface = xMSF.createInstance(serviceName); + + assertNotNull("Service wasn't created", oInterface); + return (XInterface) oInterface; + } + + /** + * call the function checkReadonlySupport to test com.sun.star.document.FilterFactory + * @see com.sun.star.document.FilterFactory + */ + @Test public void checkReadonlySupportFilterFactory() throws Exception + { + checkReadonlySupport("com.sun.star.document.FilterFactory"); + } + + /* + * call the function checkReadonlySupport to test com.sun.star.document.TypeDetection + * @see com.sun.star.document.TypeDetection + */ + @Test public void checkReadonlySupportTypeDetection() throws Exception + { + checkReadonlySupport("com.sun.star.document.TypeDetection"); + } + + /* + * test the given service serviceName. + * For every filter a new instance was created and the tests started. + * @param serviceName the name of the service to test + */ + private void checkReadonlySupport(String serviceName) throws Exception + { + System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + System.out.println("testing service '" + serviceName + "'"); + + XInterface oObj = null; + oObj = getTestObject(serviceName); + System.out.println("ImplName: " + util.utils.getImplName(oObj)); + + boolean mandatoryTrue = false; + boolean mandatoryFalse = false; + boolean finalizedTrue = false; + boolean finalizedFalse = false; + + + XNameAccess xNA = UnoRuntime.queryInterface(XNameAccess.class, oObj); + String[] filterNames = xNA.getElementNames(); + + // XNameContainer; XNameReplace + String filterName = filterNames[0]; + Object[] instance = null; + + for (int i = 0; i < filterNames.length; i++) + { + System.out.println("------------------------------------------------"); + filterName = filterNames[i]; + System.out.println(filterName); + + // testobject must new created for every test. + // We change in a loop the container and try to flush this changes. + // If we get an expected exception this container is corrupt. It's + // similar to a document which could not be saved because of invalid + // content. While you don't remove the invalid content you will never + // be able to save the document. Same here. + oObj = getTestObject(serviceName); + + xNA = UnoRuntime.queryInterface(XNameAccess.class, oObj); + XNameContainer xNC = UnoRuntime.queryInterface(XNameContainer.class, oObj); + XNameReplace xNR = UnoRuntime.queryInterface(XNameReplace.class, oObj); + XFlushable xFlush = UnoRuntime.queryInterface(XFlushable.class, oObj); + + instance = (Object[]) xNA.getByName(filterName); + PropertyValue[] props = (PropertyValue[]) instance; + + printPropertyValues(props); + + boolean isMandatory = ((Boolean) getPropertyValueValue(props, "Mandatory")).booleanValue(); + boolean isFinalized = ((Boolean) getPropertyValueValue(props, "Finalized")).booleanValue(); + + // memory if every state is available + mandatoryTrue |= isMandatory; + mandatoryFalse |= !isMandatory; + + finalizedTrue |= isFinalized; + finalizedFalse |= !isFinalized; + + //change the filter + setPropertyValueValue((PropertyValue[]) instance, "UIName", "dummy"); + + // 1a.) try to change the filter in the container + xNR.replaceByName(filterName, instance); + + // 1b.) try to write the changed filter to the configuration. + // This must result in an exception if the filter is finalized. + boolean flushError = false; + try + { + xFlush.flush(); + } + catch (WrappedTargetRuntimeException e) + { + flushError = true; + assertTrue("Unexpected exception while flushing changed filter '" + filterName + "'", isFinalized); + } + assertTrue("Expected exception was not thrown while flushing changed filter '" + filterName + "' Finalized:" + isFinalized, + !(flushError ^ isFinalized)); + + + + // 2a.) try to remove the filter from the container + xNC.removeByName(filterName); + // 1b.) try to write the changed filter to the configuration. + // This must result in an exception if the filter is mandatory + flushError = false; + try + { + xFlush.flush(); + } + catch (WrappedTargetRuntimeException e) + { + flushError = true; + assertTrue("Unexpected exception while flushing removed filter '" + filterName + "'", isMandatory); + } + assertTrue("Expected exception was not thrown while flushing removed filter '" + filterName + "' Mandatory:" + isMandatory, + !(flushError ^ isMandatory)); + } + String preMsg = "Could not find filter with state "; + String postMsg = " Please check if such filter is installed!"; + assertTrue(preMsg + "'Mandatory=true'" + postMsg, mandatoryTrue); + assertTrue(preMsg + "'Mandatory=false'" + postMsg, mandatoryFalse); + assertTrue(preMsg + "'Finalized=true'" + postMsg, finalizedTrue); + assertTrue(preMsg + "'Finalized=false'" + postMsg, finalizedFalse); + } + + /** + * print all properties with its values to logger. For debug purposes. + * @see stats.SimpleLogWriter + * @see com.sun.star.beans.PropertyValue + * @param props Sequence of PropertyValue + */ + protected void printPropertyValues(PropertyValue[] props) + { + int i = 0; + while (i < props.length) + { + System.out.println(props[i].Name + ":" + props[i].Value.toString()); + i++; + } + if (i < props.length) + { + System.out.println(props[i].Name + ":" + props[i].Value.toString()); + } + } + + /** + * returns the value of the specified (pName) property from a sequence of PropertyValue + * @param props a sequence of PropertyValue + * @param pName the name of the property the value should be returned + * @return the value of the property + */ + protected Object getPropertyValueValue(PropertyValue[] props, String pName) + { + int i = 0; + while (i < props.length && !props[i].Name.equals(pName)) + { + i++; + } + return i < props.length ? props[i].Value : null; + } + + /** + * set a value of the specified (pName) property inside a sequence of PropertyValue + * @param props sequence of PropertyValue + * @param pName name of the property which should be changed + * @param pValue the value the property should be assigned + */ + protected void setPropertyValueValue(PropertyValue[] props, String pName, Object pValue) + { + int i = 0; + while (i < props.length && !props[i].Name.equals(pName)) + { + i++; + } + props[i].Value = pValue; + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + private static final OfficeConnection connection = new OfficeConnection(); +} diff --git a/filter/qa/complex/filter/misc/TypeDetection6FileFormat.java b/filter/qa/complex/filter/misc/TypeDetection6FileFormat.java new file mode 100644 index 000000000..009fd52cf --- /dev/null +++ b/filter/qa/complex/filter/misc/TypeDetection6FileFormat.java @@ -0,0 +1,127 @@ +/* + * 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 . + */ +package complex.filter.misc; + +import com.sun.star.container.XNameAccess; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import util.utils; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; +import static org.junit.Assert.*; + + +public class TypeDetection6FileFormat +{ + + XMultiServiceFactory xMSF; + + /** Create the environment for following tests. + * Use either a component loader from desktop or + * from frame + * @throws Exception Exception + */ + @Before public void before() throws Exception + { + xMSF = getMSF(); + assertNotNull("Could not get XMultiServiceFactory", xMSF); + } + + /** + * call the function checkFileFormatSupport to test com.sun.star.document.FilterFactory + * @see com.sun.star.document.FilterFactory + */ + @Test public void checkFilterFactory() throws Exception + { + checkFileFormatSupport("com.sun.star.document.FilterFactory"); + } + + /** + * call the function checkFileFormatSupport to test com.sun.star.document.TypeDetection + * @see com.sun.star.document.TypeDetection + */ + @Test public void checkTypeDetection() throws Exception + { + checkFileFormatSupport("com.sun.star.document.TypeDetection"); + } + + /** + * test the given service serviceName. + * The serve was created and the filter 'TypeDetection6FileFormat' was searched + * @param serviceName the name of the service to test + */ + private void checkFileFormatSupport(String serviceName) throws Exception + { + System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + System.out.println("testing service '" + serviceName + "'"); + + XInterface oObj = null; + oObj = getTestObject(serviceName); + System.out.println("ImplName: " + utils.getImplName(oObj)); + XNameAccess xNA = UnoRuntime.queryInterface(XNameAccess.class, oObj); + String msg = "Could not find filter 'TypeDetection6FileFormat'!"; + msg += "\nMaybe 'TypeDetection6FileFormat.xcu' is not registered."; + assertTrue(msg, xNA.hasByName("TypeDetection6FileFormat")); + } + + /** + * Creates an instance for the given serviceName + * @param serviceName the name of the service which should be created + * @throws Exception was thrown if creation fails + * @return XInterface of service + */ + public XInterface getTestObject(String serviceName) throws Exception + { + + Object oInterface = xMSF.createInstance(serviceName); + + if (oInterface == null) + { + fail("Service wasn't created"); + throw new Exception("could not create service '" + serviceName + "'"); + } + return (XInterface) oInterface; + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass public static void setUpConnection() throws Exception { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + + private static final OfficeConnection connection = new OfficeConnection(); + +} diff --git a/filter/qa/complex/filter/misc/TypeDetection6FileFormat.xcu b/filter/qa/complex/filter/misc/TypeDetection6FileFormat.xcu new file mode 100644 index 000000000..2206e6942 --- /dev/null +++ b/filter/qa/complex/filter/misc/TypeDetection6FileFormat.xcu @@ -0,0 +1,42 @@ + + + + + + + TypeDetection 6 FileFormat + TypeDetection 6 FileFormat + + + 1,,,,,, + + + + + + + FilterFactory 6 FileFormat + FilterFactory 6 FileFormat + + + 0,TypeDetection6FileFormat,,,,, + + + + diff --git a/filter/qa/cppunit/data/xslt/copy.xslt b/filter/qa/cppunit/data/xslt/copy.xslt new file mode 100644 index 000000000..d46172a41 --- /dev/null +++ b/filter/qa/cppunit/data/xslt/copy.xslt @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/filter/qa/cppunit/msfilter-test.cxx b/filter/qa/cppunit/msfilter-test.cxx new file mode 100644 index 000000000..439aad88b --- /dev/null +++ b/filter/qa/cppunit/msfilter-test.cxx @@ -0,0 +1,76 @@ +/* -*- 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/. + */ + +#include +#include +#include + +#include +#include +#include + +#include + +namespace { + +class MSFilterTest + : public test::BootstrapFixtureBase +{ +public: + void testTransColToIco(); + + CPPUNIT_TEST_SUITE(MSFilterTest); + CPPUNIT_TEST(testTransColToIco); + CPPUNIT_TEST_SUITE_END(); +}; + +void MSFilterTest::testTransColToIco() +{ + const sal_uInt32 aStdCol[] = { + 0xeeeeee, 0xffff99, 0xff6600, 0xff3333, 0xff00cc, 0xff33ff, 0x9900ff, 0x6666ff, 0x00ccff, 0x66ffff, 0x33ff99, 0x99ff66, 0xccff00, + 0xdddddd, 0xffff66, 0xffcc00, 0xff9999, 0xff66cc, 0xff99ff, 0xcc66ff, 0x9999ff, 0x9999ff, 0x99ffff, 0x66ff99, 0x99ff99, 0xccff66, + 0xcccccc, 0xffff00, 0xff9900, 0xff6666, 0xff3399, 0xff66ff, 0x9933ff, 0x3333ff, 0x3399ff, 0x00ffff, 0x00ff66, 0x66ff66, 0x99ff33, + 0xb2b2b2, 0xcc9900, 0xff3300, 0xff0000, 0xff0066, 0xff00ff, 0x6600ff, 0x0000ff, 0x0066ff, 0x00cccc, 0x00cc33, 0x00cc00, 0x66ff00, + 0x999999, 0x996600, 0xcc3300, 0xcc0000, 0xcc0066, 0xcc00cc, 0x6600cc, 0x0000cc, 0x0066cc, 0x009999, 0x009933, 0x009900, 0x66cc00, + 0x808080, 0x663300, 0x801900, 0x990000, 0x990066, 0x990099, 0x330099, 0x000099, 0x006699, 0x006666, 0x007826, 0x006600, 0x669900, + 0x666666, 0x333300, 0x461900, 0x330000, 0x330033, 0x660066, 0x000033, 0x000066, 0x000080, 0x003333, 0x00331a, 0x003300, 0x193300, + 0x333333, 0x666633, 0x661900, 0x663333, 0x660033, 0x663366, 0x330066, 0x333366, 0x003366, 0x336666, 0x006633, 0x336633, 0x336600 }; + + const sal_uInt16 aExpected[] = { + 8, 7, 6, 6, 5, 5, 5, 2, 3, 3, 10, 4, 7, + 16, 7, 7, 6, 5, 5, 5, 2, 2, 3, 4, 4, 7, + 16, 7, 7, 6, 12, 5, 12, 2, 10, 3, 4, 4, 14, + 16, 14, 6, 6, 6, 5, 2, 2, 2, 3, 4, 4, 4, + 15, 14, 6, 6, 12, 5, 12, 2, 10, 10, 11, 11, 14, + 15, 1, 13, 13, 12, 12, 9, 9, 10, 10, 11, 11, 14, + 15, 14, 13, 13, 12, 12, 9, 9, 9, 10, 10, 11, 11, + 1, 14, 13, 13, 1, 12, 1, 9, 1, 10, 1, 11, 1 }; + + for( size_t i = 0; i < SAL_N_ELEMENTS(aStdCol); ++i) + { + const OString sMessage = "Index of unmatched color: " + OString::number(i); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), aExpected[i], + static_cast(msfilter::util::TransColToIco( Color(ColorTransparency, aStdCol[i]) ))); + } + + // tdf#92471 + CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast(msfilter::util::TransColToIco( Color( 0x6666ff )))); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast(msfilter::util::TransColToIco( Color( 0x6566ff )))); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast(msfilter::util::TransColToIco( Color( 0x6665ff )))); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast(msfilter::util::TransColToIco( Color( 0x6666fe )))); + +} + +CPPUNIT_TEST_SUITE_REGISTRATION(MSFilterTest); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/qa/cppunit/priority-test.cxx b/filter/qa/cppunit/priority-test.cxx new file mode 100644 index 000000000..18e63c318 --- /dev/null +++ b/filter/qa/cppunit/priority-test.cxx @@ -0,0 +1,85 @@ +/* -*- 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/. + */ + +// Unit test to check that we get the right filters for the right extensions. + +#include +#include +#include + +#include + +#include +#include + +#include + + +using namespace css; + +namespace { + +class PriorityFilterTest + : public test::BootstrapFixtureBase +{ +public: + void testPriority(); + + CPPUNIT_TEST_SUITE(PriorityFilterTest); + CPPUNIT_TEST(testPriority); + CPPUNIT_TEST_SUITE_END(); +}; + +void PriorityFilterTest::testPriority() +{ + uno::Reference xDetection( + comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("No type detection component", xDetection.is()); + + static struct { + const char *pURL; + const char *pFormat; + } const aToCheck[] = { + { "file:///tmp/foo.xls", "calc_MS_Excel_97" } + // TODO: expand this to check more of these priorities + }; + + for (size_t i = 0; i < SAL_N_ELEMENTS(aToCheck); i++) + { + OUString aURL = OUString::createFromAscii(aToCheck[i].pURL); + try + { + OUString aTypeName = xDetection->queryTypeByURL(aURL); + + OUString aFormatCorrect = OUString::createFromAscii(aToCheck[i].pFormat); + OUString aMsg = "Mis-matching formats " + "'" + + aTypeName + + "' should be '" + + aFormatCorrect + + "'"; + CPPUNIT_ASSERT_EQUAL_MESSAGE(OUStringToOString(aMsg, + RTL_TEXTENCODING_UTF8).getStr(), + aFormatCorrect, aTypeName); + } + catch (const uno::Exception &e) + { + OUString aMsg = "Exception querying for type: '" + e.Message + "'"; + CPPUNIT_FAIL(OUStringToOString(aMsg, RTL_TEXTENCODING_UTF8).getStr()); + } + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(PriorityFilterTest); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/qa/cppunit/xslt-test.cxx b/filter/qa/cppunit/xslt-test.cxx new file mode 100644 index 000000000..4e0c621d6 --- /dev/null +++ b/filter/qa/cppunit/xslt-test.cxx @@ -0,0 +1,207 @@ +/* -*- 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/. + */ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include + +#include + + +using namespace ::com::sun::star; + + +namespace { + +class XsltFilterTest + : public test::BootstrapFixture +{ +public: + void testXsltCopyOld(); + void testXsltCopyNew(); + + CPPUNIT_TEST_SUITE(XsltFilterTest); + CPPUNIT_TEST(testXsltCopyOld); + CPPUNIT_TEST(testXsltCopyNew); + CPPUNIT_TEST_SUITE_END(); +}; + +class Listener : public ::cppu::WeakImplHelper +{ +public: + Listener() : m_bDone(false) {} + + void wait() { + std::unique_lock g(m_mutex); + m_cond.wait(g, [this]() { return m_bDone; }); + } + +private: + std::mutex m_mutex; + std::condition_variable m_cond; + bool m_bDone; + + virtual void SAL_CALL disposing(const lang::EventObject&) noexcept override {} + virtual void SAL_CALL started() noexcept override {} + virtual void SAL_CALL closed() noexcept override { notifyDone(); } + virtual void SAL_CALL terminated() noexcept override { notifyDone(); } + virtual void SAL_CALL error(const uno::Any& e) override + { + notifyDone(); // set on error too, otherwise main thread waits forever + SAL_WARN("filter.xslt", e); + CPPUNIT_FAIL("exception while in XSLT"); + } + + void notifyDone() { + std::scoped_lock g(m_mutex); + m_bDone = true; + m_cond.notify_all(); + } +}; + +void XsltFilterTest::testXsltCopyNew() +{ + OUString tempDirURL; + osl_getTempDirURL(&tempDirURL.pData); + oslFileHandle tempFile; + OUString tempURL; + osl::File::RC rc = osl::File::createTempFile(nullptr, &tempFile, &tempURL); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, rc); + osl_closeFile(tempFile); // close it so xSFA can open it on WNT + + OUString source( + m_directories.getURLFromSrc(u"/filter/source/xsltfilter/xsltfilter.component")); + uno::Sequence args{ + uno::Any(beans::NamedValue("StylesheetURL", + uno::Any(m_directories.getURLFromSrc(u"/filter/qa/cppunit/data/xslt/copy.xslt")))), + uno::Any(beans::NamedValue("SourceURL", uno::Any(source))), + uno::Any(beans::NamedValue("TargetURL", uno::Any(tempURL))), + uno::Any(beans::NamedValue("SourceBaseURL", + uno::Any(m_directories.getURLFromSrc(u"/filter/source/xsltfilter/")))), + uno::Any(beans::NamedValue("TargetBaseURL", uno::Any(tempDirURL))), + uno::Any(beans::NamedValue("SystemType", uno::Any(OUString()))), + uno::Any(beans::NamedValue("PublicType", uno::Any(OUString()))) + }; + + uno::Reference xSFA = + ucb::SimpleFileAccess::create(getComponentContext()); + + uno::Reference xIn = xSFA->openFileRead(source); + uno::Reference xOut = xSFA->openFileWrite(tempURL); + + rtl::Reference xListener = new Listener(); + + uno::Reference xXslt( + xml::xslt::XSLTTransformer::create(getComponentContext(), args)); + + xXslt->addListener(xListener); + xXslt->setInputStream(xIn); + xXslt->setOutputStream(xOut); + + xXslt->start(); + + xListener->wait(); + + xIn->closeInput(); + xOut->closeOutput(); + + osl::File foo(tempURL); // apparently it's necessary to open it again? + foo.open(osl_File_OpenFlag_Read); + sal_uInt64 size(0); + foo.getSize(size); + CPPUNIT_ASSERT(size > 1000); // check that something happened + foo.close(); + osl_removeFile(tempURL.pData); +} + +void XsltFilterTest::testXsltCopyOld() +{ + OUString tempDirURL; + osl_getTempDirURL(&tempDirURL.pData); + oslFileHandle tempFile; + OUString tempURL; + osl::File::RC rc = osl::File::createTempFile(nullptr, &tempFile, &tempURL); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, rc); + osl_closeFile(tempFile); // close it so xSFA can open it on WNT + + OUString source( + m_directories.getURLFromSrc(u"/filter/source/xsltfilter/xsltfilter.component")); + uno::Sequence args{ + uno::Any(beans::NamedValue("StylesheetURL", + uno::Any(m_directories.getURLFromSrc(u"/filter/qa/cppunit/data/xslt/copy.xslt")))), + uno::Any(beans::NamedValue("SourceURL", uno::Any(source))), + uno::Any(beans::NamedValue("TargetURL", uno::Any(tempURL))), + uno::Any(beans::NamedValue("SourceBaseURL", + uno::Any(m_directories.getURLFromSrc(u"/filter/source/xsltfilter/")))), + uno::Any(beans::NamedValue("TargetBaseURL", uno::Any(tempDirURL))), + uno::Any(beans::NamedValue("SystemType", uno::Any(OUString()))), + uno::Any(beans::NamedValue("PublicType", uno::Any(OUString()))) + }; + + uno::Reference xSFA = + ucb::SimpleFileAccess::create(getComponentContext()); + + uno::Reference xIn = xSFA->openFileRead(source); + uno::Reference xOut = xSFA->openFileWrite(tempURL); + + rtl::Reference xListener = new Listener(); + + uno::Reference xXslt( + getMultiServiceFactory()->createInstance( + "com.sun.star.comp.documentconversion.LibXSLTTransformer"), + uno::UNO_QUERY_THROW); + + uno::Reference xInit(xXslt, uno::UNO_QUERY_THROW); + xInit->initialize(args); + xXslt->addListener(xListener); + xXslt->setInputStream(xIn); + xXslt->setOutputStream(xOut); + + xXslt->start(); + + xListener->wait(); + + xIn->closeInput(); + xOut->closeOutput(); + + osl::File foo(tempURL); // apparently it's necessary to open it again? + foo.open(osl_File_OpenFlag_Read); + sal_uInt64 size(0); + foo.getSize(size); + CPPUNIT_ASSERT(size > 1000); // check that something happened + foo.close(); + osl_removeFile(tempURL.pData); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(XsltFilterTest); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/qa/data/picture.pdf b/filter/qa/data/picture.pdf new file mode 100644 index 000000000..79af2b349 Binary files /dev/null and b/filter/qa/data/picture.pdf differ diff --git a/filter/qa/pdf.cxx b/filter/qa/pdf.cxx new file mode 100644 index 000000000..ec5460b9f --- /dev/null +++ b/filter/qa/pdf.cxx @@ -0,0 +1,347 @@ +/* -*- 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/. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +/// Covers filter/source/pdf/ fixes. +class Test : public test::BootstrapFixture, public unotest::MacrosTest +{ +private: + uno::Reference mxComponent; + +public: + void setUp() override; + void tearDown() override; + uno::Reference& getComponent() { return mxComponent; } +}; + +void Test::setUp() +{ + test::BootstrapFixture::setUp(); + MacrosTest::setUpNssGpg(m_directories, "filter_pdf"); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void Test::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +constexpr OUStringLiteral DATA_DIRECTORY = u"/filter/qa/data/"; + +CPPUNIT_TEST_FIXTURE(Test, testSignCertificateSubjectName) +{ + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + + uno::Reference xSEInitializer + = xml::crypto::SEInitializer::create(mxComponentContext); + uno::Reference xSecurityContext + = xSEInitializer->createSecurityContext(OUString()); + uno::Reference xSecurityEnvironment + = xSecurityContext->getSecurityEnvironment(); + uno::Sequence aFilterData{ + comphelper::makePropertyValue("SignPDF", true), + comphelper::makePropertyValue( + "SignCertificateSubjectName", + OUString( + "CN=Xmlsecurity RSA Test example Alice,O=Xmlsecurity RSA Test,ST=England,C=UK")), + }; + if (!GetValidCertificate(xSecurityEnvironment->getPersonalCertificates(), aFilterData)) + { + return; + } + + // Given an empty document: + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting to PDF, and referring to a certificate using a subject name: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure the resulting PDF has a signature: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + // Without the accompanying fix in place, this test would have failed, as signing was enabled + // without configuring a certificate, so the whole export failed. + CPPUNIT_ASSERT(pPdfDocument); + CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getSignatureCount()); +} + +CPPUNIT_TEST_FIXTURE(Test, testPdfDecompositionSize) +{ + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + + // Given an empty Writer document: + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When inserting a 267 points wide PDF image into the document: + uno::Sequence aArgs = { + comphelper::makePropertyValue("FileName", + m_directories.getURLFromSrc(DATA_DIRECTORY) + "picture.pdf"), + }; + dispatchCommand(getComponent(), ".uno:InsertGraphic", aArgs); + + // Then make sure that its size is correct: + uno::Reference xDrawPageSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + auto xGraphic = xShape->getPropertyValue("Graphic").get>(); + CPPUNIT_ASSERT(xGraphic.is()); + Graphic aGraphic(xGraphic); + basegfx::B2DRange aRange = aGraphic.getVectorGraphicData()->getRange(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 9437 + // - Actual : 34176 + // i.e. the width was too large, it used all width of the body frame. + // 9437 mm100 is 267.507 points from the file. +#if defined MACOSX + // TODO the bitmap size is larger (75486) on macOS, but that should not affect the logic size. + (void)aRange; +#else + // Unfortunately, this test is DPI-dependent. + // Use some allowance (~1/2 pt) to let it pass on non-default DPI. + CPPUNIT_ASSERT_DOUBLES_EQUAL(9437, aRange.getWidth(), 20.0); +#endif +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkColor) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a red watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkColor", static_cast(0xff0000)), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark color is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + Color aFillColor = pFormObject->getFillColor(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: rgba[ff0000ff] + // - Actual : rgba[00ff00ff] + // i.e. the color was the (default) green, not red. + CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xff0000), aFillColor); +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkFontHeight) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a 100pt-sized watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + sal_Int32 nExpectedFontSize = 100; + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkFontHeight", nExpectedFontSize), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark font size is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + sal_Int32 nFontSize = pFormObject->getFontSize(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 100 + // - Actual : 594 + // i.e. the font size was automatic, could not specify an explicit size. + CPPUNIT_ASSERT_EQUAL(nExpectedFontSize, nFontSize); +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkFontName) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a serif watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + OUString aExpectedFontName("Liberation Serif"); + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkFontName", aExpectedFontName), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark font name is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + OUString aFontName = pFormObject->getFontName(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Liberation Serif + // - Actual : Helvetica + // i.e. the font name was sans, could not specify an explicit name. + CPPUNIT_ASSERT_EQUAL(aExpectedFontName, aFontName); +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkRotateAngle) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a rotated watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + // 45.0 degrees, counter-clockwise. + sal_Int32 nExpectedRotateAngle = 45; + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkRotateAngle", nExpectedRotateAngle * 10), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark rotation angle is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + basegfx::B2DHomMatrix aMatrix = pFormObject->getMatrix(); + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate{}; + double fShearX{}; + aMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + sal_Int32 nActualRotateAngle = NormAngle360(basegfx::rad2deg<1>(fRotate)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 45 + // - Actual : 270 + // i.e. the rotation angle was 270 for an A4 page, not the requested 45 degrees. + CPPUNIT_ASSERT_EQUAL(nExpectedRotateAngle, nActualRotateAngle); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/qa/unit/data/TransparentText.odg b/filter/qa/unit/data/TransparentText.odg new file mode 100644 index 000000000..d3027d17d Binary files /dev/null and b/filter/qa/unit/data/TransparentText.odg differ diff --git a/filter/qa/unit/data/attributeRedefinedTest.odp b/filter/qa/unit/data/attributeRedefinedTest.odp new file mode 100644 index 000000000..dfb814bfb Binary files /dev/null and b/filter/qa/unit/data/attributeRedefinedTest.odp differ diff --git a/filter/qa/unit/data/calc.ots b/filter/qa/unit/data/calc.ots new file mode 100644 index 000000000..d16d2307f Binary files /dev/null and b/filter/qa/unit/data/calc.ots differ diff --git a/filter/qa/unit/data/custom-bullet.fodp b/filter/qa/unit/data/custom-bullet.fodp new file mode 100644 index 000000000..4139260f9 --- /dev/null +++ b/filter/qa/unit/data/custom-bullet.fodp @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + hello + + + + + + + + diff --git a/filter/qa/unit/data/empty.doc b/filter/qa/unit/data/empty.doc new file mode 100644 index 000000000..e69de29bb diff --git a/filter/qa/unit/data/empty.odp b/filter/qa/unit/data/empty.odp new file mode 100644 index 000000000..e69de29bb diff --git a/filter/qa/unit/data/empty.ods b/filter/qa/unit/data/empty.ods new file mode 100644 index 000000000..e69de29bb diff --git a/filter/qa/unit/data/empty.odt b/filter/qa/unit/data/empty.odt new file mode 100644 index 000000000..e69de29bb diff --git a/filter/qa/unit/data/empty.pptx b/filter/qa/unit/data/empty.pptx new file mode 100644 index 000000000..e69de29bb diff --git a/filter/qa/unit/data/filter-dialogs-test.txt b/filter/qa/unit/data/filter-dialogs-test.txt new file mode 100644 index 000000000..22792ad28 --- /dev/null +++ b/filter/qa/unit/data/filter-dialogs-test.txt @@ -0,0 +1,49 @@ +# -*- 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 contains all dialogs that the unit tests in the module +# will work on if it is in script mode. It will read one-by-one, +# try to open it and create a screenshot that will be saved in +# workdir/screenshots using the pattern of the ui-file name. +# +# Syntax: +# - empty lines are allowed +# - lines starting with '#' are treated as comment +# - all other lines should contain a *.ui filename in the same +# notation as in the dialog constructors (see code) + +# +# The 'known' dialogs which have a hard-coded representation +# in registerKnownDialogsByID/createDialogByID +# + +# No known dialogs in filter for now + +# +# Dialogs without a hard-coded representation. These will +# be visualized using a fallback based on weld::Builder +# + +# currently deactivated, leads to problems and the test to not work +# This is typically a hint that these should be hard-coded in the +# test case since they need some document and model data to work + +filter/ui/pdfoptionsdialog.ui +filter/ui/xsltfilterdialog.ui +filter/ui/pdfgeneralpage.ui +filter/ui/pdfviewpage.ui +filter/ui/pdfuserinterfacepage.ui +filter/ui/pdfsecuritypage.ui +filter/ui/pdflinkspage.ui +filter/ui/pdfsignpage.ui +filter/ui/xmlfiltertabpagegeneral.ui +filter/ui/xmlfiltertabpagetransformation.ui +filter/ui/testxmlfilter.ui +filter/ui/warnpdfdialog.ui +filter/ui/xmlfiltersettings.ui diff --git a/filter/qa/unit/data/impress.otp b/filter/qa/unit/data/impress.otp new file mode 100644 index 000000000..199a5f9d4 Binary files /dev/null and b/filter/qa/unit/data/impress.otp differ diff --git a/filter/qa/unit/data/preserve-jpg.odt b/filter/qa/unit/data/preserve-jpg.odt new file mode 100644 index 000000000..83768bd47 Binary files /dev/null and b/filter/qa/unit/data/preserve-jpg.odt differ diff --git a/filter/qa/unit/data/semi-transparent-fill.odg b/filter/qa/unit/data/semi-transparent-fill.odg new file mode 100644 index 000000000..713f48991 Binary files /dev/null and b/filter/qa/unit/data/semi-transparent-fill.odg differ diff --git a/filter/qa/unit/data/semi-transparent-line.odg b/filter/qa/unit/data/semi-transparent-line.odg new file mode 100644 index 000000000..2d28a694c Binary files /dev/null and b/filter/qa/unit/data/semi-transparent-line.odg differ diff --git a/filter/qa/unit/data/shape-nographic.odp b/filter/qa/unit/data/shape-nographic.odp new file mode 100644 index 000000000..43186d614 Binary files /dev/null and b/filter/qa/unit/data/shape-nographic.odp differ diff --git a/filter/qa/unit/data/tdf114428.xhtml b/filter/qa/unit/data/tdf114428.xhtml new file mode 100644 index 000000000..f08f0fa4a --- /dev/null +++ b/filter/qa/unit/data/tdf114428.xhtml @@ -0,0 +1,9 @@ + + + + + Title of document + + hello world + diff --git a/filter/qa/unit/data/writer.ott b/filter/qa/unit/data/writer.ott new file mode 100644 index 000000000..1ded03150 Binary files /dev/null and b/filter/qa/unit/data/writer.ott differ diff --git a/filter/qa/unit/filter-dialogs-test.cxx b/filter/qa/unit/filter-dialogs-test.cxx new file mode 100644 index 000000000..946a1961d --- /dev/null +++ b/filter/qa/unit/filter-dialogs-test.cxx @@ -0,0 +1,61 @@ +/* -*- 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/. + */ + +#include +#include +#include + +using namespace ::com::sun::star; + +/// Test opening a dialog in filter +class FilterDialogsTest : public ScreenshotTest +{ +private: + /// helper method to populate KnownDialogs, called in setUp(). Needs to be + /// written and has to add entries to KnownDialogs + virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override; + + /// dialog creation for known dialogs by ID. Has to be implemented for + /// each registered known dialog + virtual VclPtr createDialogByID(sal_uInt32 nID) override; + +public: + FilterDialogsTest(); + + // try to open a dialog + void openAnyDialog(); + + CPPUNIT_TEST_SUITE(FilterDialogsTest); + CPPUNIT_TEST(openAnyDialog); + CPPUNIT_TEST_SUITE_END(); +}; + +FilterDialogsTest::FilterDialogsTest() {} + +void FilterDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/) +{ + // fill map of known dialogs +} + +VclPtr FilterDialogsTest::createDialogByID(sal_uInt32 /*nID*/) +{ + return nullptr; +} + +void FilterDialogsTest::openAnyDialog() +{ + /// process input file containing the UXMLDescriptions of the dialogs to dump + processDialogBatchFile(u"filter/qa/unit/data/filter-dialogs-test.txt"); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(FilterDialogsTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/qa/unit/svg.cxx b/filter/qa/unit/svg.cxx new file mode 100644 index 000000000..22695acd6 --- /dev/null +++ b/filter/qa/unit/svg.cxx @@ -0,0 +1,380 @@ +/* -*- 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/. + */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +constexpr OUStringLiteral DATA_DIRECTORY = u"/filter/qa/unit/data/"; + +/// SVG filter tests. +class SvgFilterTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools +{ +private: + uno::Reference mxComponent; + +public: + void setUp() override; + void tearDown() override; + void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override; + uno::Reference& getComponent() { return mxComponent; } + void load(std::u16string_view rURL); +}; + +void SvgFilterTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void SvgFilterTest::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +void SvgFilterTest::load(std::u16string_view rFileName) +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFileName; + mxComponent = loadFromDesktop(aURL); +} + +void SvgFilterTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) +{ + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("svg"), BAD_CAST("http://www.w3.org/2000/svg")); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testPreserveJpg) +{ +#if !defined(MACOSX) + // Load a document with a jpeg image in it. + load(u"preserve-jpg.odt"); + + // Select the image. + dispatchCommand(getComponent(), ".uno:JumpToNextFrame", {}); + + // Export the selection to SVG. + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_svg_Export"); + aMediaDescriptor["SelectionOnly"] <<= true; + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Make sure that the original JPG data is reused and we don't perform a PNG re-compress. + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + OUString aAttributeValue = getXPath(pXmlDoc, "//svg:image", "href"); + + // Without the accompanying fix in place, this test would have failed with: + // - Expression: aAttributeValue.startsWith("data:image/jpeg") + // i.e. the SVG export result re-compressed the image as PNG, even if the original and the + // transformed image is the same, so there is no need for that. + CPPUNIT_ASSERT(aAttributeValue.startsWith("data:image/jpeg")); +#endif +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentLine) +{ + // Load a document with a semi-transparent line shape. + load(u"semi-transparent-line.odg"); + + // Export it to SVG. + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Get the style of the group around the actual element. + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + OUString aStyle = getXPath( + pXmlDoc, "//svg:g[@class='com.sun.star.drawing.LineShape']/svg:g/svg:g", "style"); + // Without the accompanying fix in place, this test would have failed, as the style was + // "mask:url(#mask1)", not "opacity: ". + CPPUNIT_ASSERT(aStyle.startsWith("opacity: ", &aStyle)); + int nPercent = std::round(aStyle.toDouble() * 100); + // Make sure that the line is still 30% opaque, rather than completely invisible. + CPPUNIT_ASSERT_EQUAL(30, nPercent); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentFillWithTransparentLine) +{ + // Load a document with a shape with semi-transparent fill and line + load(u"semi-transparent-fill.odg"); + + // Export it to SVG. + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Get the style of the group around the actual element. + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + OUString aStyle = getXPath( + pXmlDoc, "//svg:g[@class='com.sun.star.drawing.EllipseShape']/svg:g/svg:g", "style"); + CPPUNIT_ASSERT(aStyle.startsWith("opacity: ", &aStyle)); + int nPercent = std::round(aStyle.toDouble() * 100); + // Make sure that the line is still 50% opaque + CPPUNIT_ASSERT_EQUAL(50, nPercent); + + // Get the stroke of the fill of the EllipseShape (it must be "none") + OUString aStroke = getXPath( + pXmlDoc, "//svg:g[@class='com.sun.star.drawing.EllipseShape']/svg:g/svg:path", "stroke"); + // Without the accompanying fix in place, this test would have failed, as the stroke was + // "rgb(255,255,255)", not "none". + CPPUNIT_ASSERT_EQUAL(OUString("none"), aStroke); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentText) +{ + // Two shapes, one with transparent text and the other one with + // opaque text. We expect both to be exported to the SVG with the + // correct transparency factor applied for the first shape. + + // Load draw document with transparent text in one box + load(u"TransparentText.odg"); + + // Export to SVG. + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + + // We expect 2 groups of class "TextShape" that + // have some svg:text node inside. + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 + // - Actual : 1 + // i.e. the 2nd shape lots its text. + + assertXPath(pXmlDoc, "//svg:g[@class='TextShape']//svg:text", 2); + + // First shape has semi-transparent text. + assertXPath(pXmlDoc, "//svg:text[1]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity='0.8']"); + + // Second shape has normal text. + assertXPath(pXmlDoc, "//svg:text[2]/svg:tspan/svg:tspan/svg:tspan[@fill-opacity]", 0); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentMultiParaText) +{ + // Given a shape with semi-transparent, multi-paragraph text: + getComponent() + = loadFromDesktop("private:factory/simpress", "com.sun.star.drawing.DrawingDocument"); + uno::Reference xFactory(getComponent(), uno::UNO_QUERY); + uno::Reference xShape( + xFactory->createInstance("com.sun.star.drawing.TextShape"), uno::UNO_QUERY); + uno::Reference xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + xDrawPage->add(xShape); + xShape->setSize(awt::Size(10000, 10000)); + uno::Reference xShapeText(xShape, uno::UNO_QUERY); + uno::Reference xCursor = xShapeText->createTextCursor(); + xShapeText->insertString(xCursor, "foo", /*bAbsorb=*/false); + xShapeText->insertControlCharacter(xCursor, text::ControlCharacter::APPEND_PARAGRAPH, + /*bAbsorb=*/false); + xShapeText->insertString(xCursor, "bar", /*bAbsorb=*/false); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("CharColor", uno::Any(static_cast(0xff0000))); + xShapeProps->setPropertyValue("CharTransparence", uno::Any(static_cast(20))); + + // When exporting to SVG: + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("draw_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Then make sure that the two semi-tranparent paragraphs have the same X position: + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + assertXPath(pXmlDoc, "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[1]", "x", + "250"); + assertXPath(pXmlDoc, + "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[1]/svg:tspan", + "fill-opacity", "0.8"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 250 + // - Actual : 8819 + // i.e. the X position of the second paragraph was wrong. + assertXPath(pXmlDoc, "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[2]", "x", + "250"); + assertXPath(pXmlDoc, + "(//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition'])[2]/svg:tspan", + "fill-opacity", "0.8"); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testShapeNographic) +{ + // Load a document containing a 3D shape. + load(u"shape-nographic.odp"); + + // Export to SVG. + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + + // Without the accompanying fix in place, this test would have failed with: + // An uncaught exception of type com.sun.star.io.IOException + // - SfxBaseModel::impl_store failed: 0xc10(Error Area:Io Class:Write Code:16) + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testCustomBullet) +{ + // Given a presentation with a custom bullet: + load(u"custom-bullet.fodp"); + + // When exporting that to SVG: + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + + // Then make sure the bullet glyph is not lost: + aStream.Seek(STREAM_SEEK_TO_BEGIN); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // - XPath '//svg:g[@class='BulletChars']//svg:path' number of nodes is incorrect + // i.e. the custom bullet used '', but nobody produced a bullet-char-template-45, + // instead we need the path of the glyph inline. + CPPUNIT_ASSERT(!getXPath(pXmlDoc, "//svg:g[@class='BulletChars']//svg:path", "d").isEmpty()); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, attributeRedefinedTest) +{ + // Load document containing empty paragraphs with ids. + load(u"attributeRedefinedTest.odp"); + + // Export to SVG. + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + + // We expect four paragraph + // 2 empty paragraphs with ids + // 2 paragraphs with text + // Without the accompanying fix the test would have failed with + // Expected : 4 + // Actual : 2 + // i.e. 2 of the empty paragraph do not get generated even if there + // is id imported for the paragraphs + // If we don't create the empty paragraphs the id attribute gets redefined like this: + // + + OString xPath = "//svg:g[@class='TextShape']//svg:text[@class='SVGTextShape']//" + "svg:tspan[@class='TextParagraph']"; + assertXPath(pXmlDoc, xPath, 4); + + //assert that each tspan element with TextParagraph class has id and the tspan element of + //each empty paragraph does not contain tspan element with class TextPosition + assertXPath(pXmlDoc, xPath + "[1]", "id", "id4"); + assertXPath(pXmlDoc, xPath + "[2]", "id", "id5"); + assertXPath(pXmlDoc, xPath + "[2]//svg:tspan[@class='TextPosition']", 0); + assertXPath(pXmlDoc, xPath + "[3]", "id", "id6"); + assertXPath(pXmlDoc, xPath + "[3]//svg:tspan[@class='TextPosition']", 0); + assertXPath(pXmlDoc, xPath + "[4]", "id", "id7"); +} + +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testTab) +{ + // Given a shape with "A\tB" text: + getComponent() = loadFromDesktop("private:factory/simpress", + "com.sun.star.presentation.PresentationDocument"); + uno::Reference xFactory(getComponent(), uno::UNO_QUERY); + uno::Reference xShape( + xFactory->createInstance("com.sun.star.drawing.TextShape"), uno::UNO_QUERY); + uno::Reference xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + xDrawPage->add(xShape); + xShape->setSize(awt::Size(10000, 10000)); + uno::Reference xShapeText(xShape, uno::UNO_QUERY); + xShapeText->setString("A\tB"); + + // When exporting that document to SVG: + uno::Reference xStorable(getComponent(), uno::UNO_QUERY_THROW); + SvMemoryStream aStream; + uno::Reference xOut = new utl::OOutputStreamWrapper(aStream); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_svg_Export"); + aMediaDescriptor["OutputStream"] <<= xOut; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + + // Then make sure the the tab is not lost: + aStream.Seek(STREAM_SEEK_TO_BEGIN); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 + // - Actual : 1 + // i.e. the 2nd text portion was not positioned, which looked as if the tab is lost. + assertXPath(pXmlDoc, "//svg:g[@class='TextShape']//svg:tspan[@class='TextPosition']", 2); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/qa/unit/textfilterdetect.cxx b/filter/qa/unit/textfilterdetect.cxx new file mode 100644 index 000000000..3c8daf2f2 --- /dev/null +++ b/filter/qa/unit/textfilterdetect.cxx @@ -0,0 +1,199 @@ +/* -*- 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/. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace com::sun::star::io +{ +class XInputStream; +} + +using namespace com::sun::star; + +namespace +{ +/// Test class for PlainTextFilterDetect. +class TextFilterDetectTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +public: + void setUp() override; +}; + +void TextFilterDetectTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +constexpr OUStringLiteral DATA_DIRECTORY = u"/filter/qa/unit/data/"; + +CPPUNIT_TEST_FIXTURE(TextFilterDetectTest, testTdf114428) +{ + uno::Reference xDetect( + getMultiServiceFactory()->createInstance("com.sun.star.comp.filters.PlainTextFilterDetect"), + uno::UNO_QUERY); + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf114428.xhtml"; + SvFileStream aStream(aURL, StreamMode::READ); + uno::Reference xStream(new utl::OStreamWrapper(aStream)); + uno::Sequence aDescriptor + = { comphelper::makePropertyValue("DocumentService", + OUString("com.sun.star.text.TextDocument")), + comphelper::makePropertyValue("InputStream", xStream), + comphelper::makePropertyValue("TypeName", OUString("generic_HTML")) }; + xDetect->detect(aDescriptor); + utl::MediaDescriptor aMediaDesc(aDescriptor); + OUString aFilterName = aMediaDesc.getUnpackedValueOrDefault("FilterName", OUString()); + // This was empty, XML declaration caused HTML detect to not handle XHTML. + CPPUNIT_ASSERT_EQUAL(OUString("HTML (StarWriter)"), aFilterName); +} + +CPPUNIT_TEST_FIXTURE(TextFilterDetectTest, testEmptyFile) +{ + const OUString sDataDirectory = m_directories.getURLFromSrc(DATA_DIRECTORY); + auto supportsService = [](const uno::Reference& x, const OUString& s) { + return uno::Reference(x, uno::UNO_QUERY_THROW)->supportsService(s); + }; + + // Given an empty file, with a pptx extension + // When loading the file + auto xComponent = loadFromDesktop(sDataDirectory + "empty.pptx"); + + // Then make sure it is opened in Impress. + // Without the accompanying fix in place, this test would have failed, as it was opened in + // Writer instead. + CPPUNIT_ASSERT(supportsService(xComponent, "com.sun.star.presentation.PresentationDocument")); + xComponent->dispose(); + + // Now also test ODT + xComponent = loadFromDesktop(sDataDirectory + "empty.odt"); + // Make sure it opens in Writer. + CPPUNIT_ASSERT(supportsService(xComponent, "com.sun.star.text.TextDocument")); + xComponent->dispose(); + + // ... and ODS + xComponent = loadFromDesktop(sDataDirectory + "empty.ods"); + // Make sure it opens in Calc. + CPPUNIT_ASSERT(supportsService(xComponent, "com.sun.star.sheet.SpreadsheetDocument")); + xComponent->dispose(); + + // ... and ODP + xComponent = loadFromDesktop(sDataDirectory + "empty.odp"); + // Without the accompanying fix in place, this test would have failed, as it was opened in + // Writer instead. + CPPUNIT_ASSERT(supportsService(xComponent, "com.sun.star.presentation.PresentationDocument")); + xComponent->dispose(); + + // ... and DOC + // Without the accompanying fix in place, this test would have failed, the import filter aborted + // loading. + xComponent = loadFromDesktop(sDataDirectory + "empty.doc"); + CPPUNIT_ASSERT(supportsService(xComponent, "com.sun.star.text.TextDocument")); + { + uno::Reference xModel(xComponent, uno::UNO_QUERY); + uno::Sequence aArgs = xModel->getArgs(); + comphelper::SequenceAsHashMap aMap(aArgs); + OUString aFilterName; + aMap["FilterName"] >>= aFilterName; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: MS Word 97 + // - Actual : MS WinWord 6.0 + // i.e. opening worked, but saving back failed instead of producing a WW8 binary file. + CPPUNIT_ASSERT_EQUAL(OUString("MS Word 97"), aFilterName); + } + xComponent->dispose(); + + // Now test with default templates set + + SfxObjectFactory::SetStandardTemplate("com.sun.star.presentation.PresentationDocument", + sDataDirectory + "impress.otp"); + SfxObjectFactory::SetStandardTemplate("com.sun.star.text.TextDocument", + sDataDirectory + "writer.ott"); + SfxObjectFactory::SetStandardTemplate("com.sun.star.sheet.SpreadsheetDocument", + sDataDirectory + "calc.ots"); + + xComponent = loadFromDesktop(sDataDirectory + "empty.pptx"); + { + uno::Reference xDoc(xComponent, uno::UNO_QUERY_THROW); + uno::Reference xPages(xDoc->getDrawPages(), uno::UNO_SET_THROW); + uno::Reference xPage(xPages->getByIndex(0), uno::UNO_QUERY_THROW); + uno::Reference xBox(xPage->getByIndex(0), uno::UNO_QUERY_THROW); + + // Make sure the template's text was loaded + CPPUNIT_ASSERT_EQUAL(OUString("Title of Impress template"), xBox->getString()); + } + xComponent->dispose(); + + xComponent = loadFromDesktop(sDataDirectory + "empty.odt"); + { + uno::Reference xDoc(xComponent, uno::UNO_QUERY_THROW); + uno::Reference xEA(xDoc->getText(), uno::UNO_QUERY_THROW); + uno::Reference xEnum(xEA->createEnumeration(), uno::UNO_SET_THROW); + uno::Reference xParagraph(xEnum->nextElement(), uno::UNO_QUERY_THROW); + + // Make sure the template's text was loaded + CPPUNIT_ASSERT_EQUAL(OUString(u"Writer template’s first line"), xParagraph->getString()); + } + xComponent->dispose(); + + xComponent = loadFromDesktop(sDataDirectory + "empty.ods"); + { + uno::Reference xDoc(xComponent, uno::UNO_QUERY_THROW); + uno::Reference xRA(xDoc->getSheets(), uno::UNO_QUERY_THROW); + uno::Reference xC(xRA->getCellByPosition(0, 0, 0), uno::UNO_QUERY_THROW); + + // Make sure the template's text was loaded + CPPUNIT_ASSERT_EQUAL(OUString(u"Calc template’s first cell"), xC->getString()); + } + xComponent->dispose(); + + xComponent = loadFromDesktop(sDataDirectory + "empty.odp"); + { + uno::Reference xDoc(xComponent, uno::UNO_QUERY_THROW); + uno::Reference xPages(xDoc->getDrawPages(), uno::UNO_SET_THROW); + uno::Reference xPage(xPages->getByIndex(0), uno::UNO_QUERY_THROW); + uno::Reference xBox(xPage->getByIndex(0), uno::UNO_QUERY_THROW); + + // Make sure the template's text was loaded + CPPUNIT_ASSERT_EQUAL(OUString("Title of Impress template"), xBox->getString()); + } + xComponent->dispose(); + + xComponent = loadFromDesktop(sDataDirectory + "empty.doc"); + { + uno::Reference xDoc(xComponent, uno::UNO_QUERY_THROW); + uno::Reference xEA(xDoc->getText(), uno::UNO_QUERY_THROW); + uno::Reference xEnum(xEA->createEnumeration(), uno::UNO_SET_THROW); + uno::Reference xParagraph(xEnum->nextElement(), uno::UNO_QUERY_THROW); + + // Make sure the template's text was loaded + CPPUNIT_ASSERT_EQUAL(OUString(u"Writer template’s first line"), xParagraph->getString()); + } + xComponent->dispose(); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/basecontainer.cxx b/filter/source/config/cache/basecontainer.cxx new file mode 100644 index 000000000..0dee9d4ba --- /dev/null +++ b/filter/source/config/cache/basecontainer.cxx @@ -0,0 +1,476 @@ +/* -*- 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 "basecontainer.hxx" + +#include +#include +#include +#include +#include +#include + +#define LOAD_IMPLICIT + +namespace filter::config{ + +BaseContainer::BaseContainer() + : m_eType() + , m_lListener (m_aMutex) +{ + GetTheFilterCache().load(FilterCache::E_CONTAINS_STANDARD); +} + + +BaseContainer::~BaseContainer() +{ +} + + +void BaseContainer::init(const OUString& sImplementationName, + const css::uno::Sequence< OUString >& lServiceNames , + FilterCache::EItemType eType ) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + m_sImplementationName = sImplementationName; + m_lServiceNames = lServiceNames ; + m_eType = eType ; + // <- SAFE +} + + +void BaseContainer::impl_loadOnDemand() +{ +#ifdef LOAD_IMPLICIT + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // A generic container needs all items of a set of our cache! + // Of course it can block for a while, till the cache is really filled. + // Note: don't load all sets supported by the cache here! + + FilterCache::EFillState eRequiredState = FilterCache::E_CONTAINS_NOTHING; + switch(m_eType) + { + case FilterCache::E_TYPE : + eRequiredState = FilterCache::E_CONTAINS_TYPES; + break; + + case FilterCache::E_FILTER : + eRequiredState = FilterCache::E_CONTAINS_FILTERS; + break; + + case FilterCache::E_FRAMELOADER : + eRequiredState = FilterCache::E_CONTAINS_FRAMELOADERS; + break; + + case FilterCache::E_CONTENTHANDLER : + eRequiredState = FilterCache::E_CONTAINS_CONTENTHANDLERS; + break; + } + + GetTheFilterCache().load(eRequiredState); + // <- SAFE +#endif +} + + +void BaseContainer::impl_initFlushMode() +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + if (!m_pFlushCache) + m_pFlushCache = GetTheFilterCache().clone(); + if (!m_pFlushCache) + throw css::uno::RuntimeException( "Can not create write copy of internal used cache on demand.", + static_cast< OWeakObject* >(this)); + // <- SAFE +} + + +FilterCache* BaseContainer::impl_getWorkingCache() const +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + if (m_pFlushCache) + return m_pFlushCache.get(); + else + return &GetTheFilterCache(); + // <- SAFE +} + + +OUString SAL_CALL BaseContainer::getImplementationName() +{ + return m_sImplementationName; +} + + +sal_Bool SAL_CALL BaseContainer::supportsService(const OUString& sServiceName) +{ + return cppu::supportsService(this, sServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL BaseContainer::getSupportedServiceNames() +{ + return m_lServiceNames; +} + + +void SAL_CALL BaseContainer::insertByName(const OUString& sItem , + const css::uno::Any& aValue) +{ + if (sItem.isEmpty()) + throw css::lang::IllegalArgumentException("empty value not allowed as item name.", + static_cast< css::container::XNameContainer* >(this), + 1); + + CacheItem aItem; + try + { + aItem << aValue; + } + catch(const css::uno::Exception& ex) + { + throw css::lang::IllegalArgumentException(ex.Message, static_cast< css::container::XNameContainer* >(this), 2); + } + + impl_loadOnDemand(); + + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + // create write copy of used cache on demand ... + impl_initFlushMode(); + + FilterCache* pCache = impl_getWorkingCache(); + if (pCache->hasItem(m_eType, sItem)) + throw css::container::ElementExistException(OUString(), static_cast< css::container::XNameContainer* >(this)); + pCache->setItem(m_eType, sItem, aItem); + // <- SAFE ---------------------------------- +} + + +void SAL_CALL BaseContainer::removeByName(const OUString& sItem) +{ + impl_loadOnDemand(); + + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + // create write copy of used cache on demand ... + impl_initFlushMode(); + + FilterCache* pCache = impl_getWorkingCache(); + pCache->removeItem(m_eType, sItem); // throw exceptions automatically + // <- SAFE ---------------------------------- +} + + +void SAL_CALL BaseContainer::replaceByName(const OUString& sItem , + const css::uno::Any& aValue) +{ + if (sItem.isEmpty()) + throw css::lang::IllegalArgumentException("empty value not allowed as item name.", + static_cast< css::container::XNameContainer* >(this), + 1); + + CacheItem aItem; + try + { + aItem << aValue; + } + catch(const css::uno::Exception& ex) + { + throw css::lang::IllegalArgumentException(ex.Message, static_cast< css::container::XNameContainer* >(this), 2); + } + + impl_loadOnDemand(); + + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + // create write copy of used cache on demand ... + impl_initFlushMode(); + + FilterCache* pCache = impl_getWorkingCache(); + if (!pCache->hasItem(m_eType, sItem)) + throw css::container::NoSuchElementException(OUString(), static_cast< css::container::XNameContainer* >(this)); + pCache->setItem(m_eType, sItem, aItem); + // <- SAFE ---------------------------------- +} + + +css::uno::Any SAL_CALL BaseContainer::getByName(const OUString& sItem) +{ + if (sItem.isEmpty()) + throw css::container::NoSuchElementException( "An empty item can't be part of this cache!", + static_cast< css::container::XNameAccess* >(this)); + + css::uno::Any aValue; + + impl_loadOnDemand(); + + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + try + { + FilterCache* pCache = impl_getWorkingCache(); + aValue = pCache->getItemWithStateProps(m_eType, sItem); + } + catch(const css::container::NoSuchElementException&) + { + throw; + } + catch(const css::uno::Exception&) + { + // TODO invalid cache!? How should it be handled right? + } + + // <- SAFE + + return aValue; +} + + +css::uno::Sequence< OUString > SAL_CALL BaseContainer::getElementNames() +{ + css::uno::Sequence< OUString > lNames; + + impl_loadOnDemand(); + + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + try + { + FilterCache* pCache = impl_getWorkingCache(); + std::vector lKeys = pCache->getItemNames(m_eType); + lNames = comphelper::containerToSequence(lKeys); + } + catch(const css::uno::Exception&) + { + // invalid cache!? + lNames.realloc(0); + } + + // <- SAFE + + return lNames; +} + + +sal_Bool SAL_CALL BaseContainer::hasByName(const OUString& sItem) +{ + bool bHasOne = false; + + impl_loadOnDemand(); + + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + try + { + FilterCache* pCache = impl_getWorkingCache(); + bHasOne = pCache->hasItem(m_eType, sItem); + } + catch(const css::uno::Exception&) + { + // invalid cache!? + bHasOne = false; + } + + // <- SAFE + + return bHasOne; +} + + +css::uno::Type SAL_CALL BaseContainer::getElementType() +{ + // no lock necessary - because the type of our items + // is fix! no internal call or member needed ... + return cppu::UnoType>::get(); +} + + +sal_Bool SAL_CALL BaseContainer::hasElements() +{ + bool bHasSome = false; + + impl_loadOnDemand(); + + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + try + { + FilterCache* pCache = impl_getWorkingCache(); + bHasSome = pCache->hasItems(m_eType); + } + catch(const css::uno::Exception&) + { + // invalid cache?! + bHasSome = false; + } + + // <- SAFE + + return bHasSome; +} + + +css::uno::Reference< css::container::XEnumeration > SAL_CALL BaseContainer::createSubSetEnumerationByQuery(const OUString& /* sQuery */ ) +{ + OSL_FAIL("not pure virtual ... but not really implemented .-)"); + + return new ::comphelper::OEnumerationByName(this, {}); +} + + +css::uno::Reference< css::container::XEnumeration > SAL_CALL BaseContainer::createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties) +{ + std::vector lKeys; + + impl_loadOnDemand(); + + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + try + { + // search the key names of all items, where its properties match + // the given ones in its minimum + FilterCache* pCache = impl_getWorkingCache(); + lKeys = pCache->getMatchingItemsByProps(m_eType, o3tl::span( lProperties.getConstArray(), lProperties.getLength() )); + } + catch(const css::uno::Exception&) + { + // invalid cache, internal failure, wrong conversion ...!? + // doesn't matter + lKeys.clear(); + } + + // <- SAFE + + // create a specialized enumeration helper, which + // provides the collected information outside. + // It hold a reference to us ... and call our container interface directly. + // be aware of some direct callbacks if it will be created :-) + + /* Note: It's not allowed to return NULL. Because an empty enumeration + transport the same information but make no trouble outside. + Further its easier to work directly with the return value + instead of checking of NULL returns! */ + + return new ::comphelper::OEnumerationByName(this, std::move(lKeys)); +} + + +void SAL_CALL BaseContainer::flush() +{ + // SAFE -> + osl::ClearableMutexGuard aLock(m_aMutex); + + if (!m_pFlushCache) + throw css::lang::WrappedTargetRuntimeException( + "Can not guarantee cache consistency. Special flush container does not exists!", + static_cast< OWeakObject* >(this), + css::uno::Any()); + + try + { + m_pFlushCache->flush(); + // Take over all changes into the global cache and + // forget the clone. + /* TODO + -think about me + If the global cache gets this information via listener, + we should remove this method! + */ + GetTheFilterCache().takeOver(*m_pFlushCache); + } + catch(const css::uno::Exception& ex) + { + // Don't remove the clone. May be the outside + // user wish to repair it now and calls flush() + // later again ... + + throw css::lang::WrappedTargetRuntimeException( "Flush rejected by internal container.", + static_cast< OWeakObject* >(this), + css::uno::Any(ex)); + } + + m_pFlushCache.reset(); + + aLock.clear(); + // <- SAFE + + // notify listener outside the lock! + // The used listener helper lives if we live + // and is threadsafe by itself. + // Further it's not a good idea to hold the own lock + // if an outside object is called :-) + css::lang::EventObject aSource (static_cast< css::util::XFlushable* >(this)); + comphelper::OInterfaceContainerHelper2* pContainer = m_lListener.getContainer(cppu::UnoType::get()); + if (!pContainer) + return; + + comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer); + while (pIterator.hasMoreElements()) + { + try + { + // ... this pointer can be interesting to find out, where will be called as listener + // Don't optimize it to a direct iterator cast :-) + css::util::XFlushListener* pListener = static_cast(pIterator.next()); + pListener->flushed(aSource); + } + catch(const css::uno::Exception&) + { + // ignore any "damaged" flush listener! + // May its remote reference is broken ... + pIterator.remove(); + } + } +} + + +void SAL_CALL BaseContainer::addFlushListener(const css::uno::Reference< css::util::XFlushListener >& xListener) +{ + // no locks necessary + // used helper lives if we live and is threadsafe by itself ... + m_lListener.addInterface(cppu::UnoType::get(), xListener); +} + + +void SAL_CALL BaseContainer::removeFlushListener(const css::uno::Reference< css::util::XFlushListener >& xListener) +{ + // no locks necessary + // used helper lives if we live and is threadsafe by itself ... + m_lListener.removeInterface(cppu::UnoType::get(), xListener); +} + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/basecontainer.hxx b/filter/source/config/cache/basecontainer.hxx new file mode 100644 index 000000000..6691c1b49 --- /dev/null +++ b/filter/source/config/cache/basecontainer.hxx @@ -0,0 +1,256 @@ +/* -*- 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 . + */ +#pragma once + +#include + +#include "filtercache.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace filter::config { + + +/** @short implements the interface css::container::XNameContainer + on top of a FilterCache reference. + + @descr This class can be used as base for own service implementations, + which must provide read/write access to the filter configuration. + Parameters regulate read/write access, which sub set of information + should be available etc. + + @attention The base class BaseLock must be the first of declared ones. + Otherwise we can't be sure, that our own mutex member (which is + present by this base class!) was full initialized inside our own + ctor as first! + */ +class BaseContainer : public cppu::BaseMutex + , public ::cppu::WeakImplHelper< css::lang::XServiceInfo , + css::container::XNameContainer , // => XNameReplace => XNameAccess => XElementAccess + css::container::XContainerQuery , + css::util::XFlushable > +{ + + // member + + protected: + + /** @short the implementation name of our derived class, which we provide + at the interface XServiceInfo of our class... */ + OUString m_sImplementationName; + + /** @short the list of supported uno service names of our derived class, which we provide + at the interface XServiceInfo of our class... */ + css::uno::Sequence< OUString > m_lServiceNames; + + /** @short local filter cache, which is used to collect changes on the + filter configuration first and flush it later. + + @descr Normally this member isn't used nor initialized. That's true, + if this container is used for reading only. The first write access + (e.g. by calling insertByName()) creates a copy of the current + global cache m_rCache to initialize the m_pFlushCache member. + + Afterwards only the flush cache copy is used. Inside flush() this + copy will be removed and m_rCache can be used again. + + m_pFlushCache and m_rCache must not be synchronized manually here. + m_rCache listen on the global configuration, where m_pFlushCache + write its data. m_rCache update itself automatically. + */ + std::unique_ptr m_pFlushCache; + + /** @short specify, which sub container of the used filter cache + must be wrapped by this container interface. */ + FilterCache::EItemType m_eType; + + /** @short holds all listener, which are registered at this instance. */ + comphelper::OMultiTypeInterfaceContainerHelper2 m_lListener; + + + // native interface + + public: + + + // ctor/dtor + + /** @short standard ctor. + + @descr Because mostly this class is used as base class for own service + implementations in combination with an ImplInheritanceHelper template... + there is no way to provide some initializing data through the ctor :-( + This base class will be created inside its default ctor and must be + initialized with its needed parameters explicitly by calling: "init()". + + @see init() + */ + BaseContainer(); + + + /** @short standard dtor. + */ + virtual ~BaseContainer() override; + + + /** @short initialize this generic instance with some specialized values + from our derived object. + + @descr Because an outside class must use ImplInheritanceHelper template to + use us a base class... and there is no way to pass such initializing + parameters through a required default ctor... we must be initialized + by this special method. Of course this method must be called first before + any other interface method is used. + + @param rxContext + reference to the uno service manager, which created this service instance. + + @param sImplementationName + the implementation name of our derived class, which we provide + at the interface XServiceInfo of our class... + + @param lServiceNames + the list of supported uno service names of our derived class, which we provide + at the interface XServiceInfo of our class... + + @param eType + specify, which sub container of the used filter cache + must be wrapped by this container interface. + */ + void init( const OUString& sImplementationName, + const css::uno::Sequence< OUString >& lServiceNames , + FilterCache::EItemType eType ); + + + // helper + + protected: + + + /** @short check if the underlying configuration data was already loaded + and do it if necessary automatically. + */ + void impl_loadOnDemand(); + + + /** @short it creates the global instance m_pFilterCache, which is a copy + of the global instance m_rCache, and will be used to change the + configuration. + + @descr If no exception occurs, its guaranteed, that the member m_rFlushCache + was initialized right and can be used further. + + @throws css::uno::RuntimeException + */ + void impl_initFlushMode(); + + + /** @short returns a pointer to the current used cache member. + + @descr It's a point to the FilterCache instance behind m_pFlushCache + or m_rCache. + + @note The lifetime of this pointer is restricted to the time, where + the mutex of this BaseContainer instance is locked. + Otherwise may be the interface method flush() will destroy + m_pFlushCache and the here returned pointer will be invalid! + + Use: + + Guard aLock(m_aLock); + FilterCache* p = impl_getWorkingCache(); + p->doSomething(); + aLock.clear(); + // after this point p can't b e guaranteed any longer! + */ + FilterCache* impl_getWorkingCache() const; + + + // uno interface + + public: + + + // XServiceInfo + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + + // XNameContainer + + virtual void SAL_CALL insertByName(const OUString& sItem , + const css::uno::Any& aValue) override; + + virtual void SAL_CALL removeByName(const OUString& sItem) override; + + + // XNameReplace + + virtual void SAL_CALL replaceByName(const OUString& sItem , + const css::uno::Any& aValue) override; + + + // XElementAccess + + virtual css::uno::Any SAL_CALL getByName(const OUString& sItem) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override; + + virtual sal_Bool SAL_CALL hasByName(const OUString& sItem) override; + + virtual css::uno::Type SAL_CALL getElementType() override; + + virtual sal_Bool SAL_CALL hasElements() override; + + + // XContainerQuery + + // must be implemented really by derived class... + // We implement return of an empty result here only! + // But we show an assertion :-) + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByQuery(const OUString& sQuery) override; + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties) override; + + + // XFlushable + + virtual void SAL_CALL flush() override; + + virtual void SAL_CALL addFlushListener(const css::uno::Reference< css::util::XFlushListener >& xListener) override; + + virtual void SAL_CALL removeFlushListener(const css::uno::Reference< css::util::XFlushListener >& xListener) override; +}; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/cacheitem.cxx b/filter/source/config/cache/cacheitem.cxx new file mode 100644 index 000000000..595d3891a --- /dev/null +++ b/filter/source/config/cache/cacheitem.cxx @@ -0,0 +1,325 @@ +/* -*- 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 "cacheitem.hxx" +#include "constant.hxx" + +#include + +#include +#include + +#include +#include + + +namespace filter::config{ + +CacheItem::CacheItem() +{ +} + + +void CacheItem::update(const CacheItem& rUpdateItem) +{ + for (auto const& elem : rUpdateItem) + (*this)[elem.first] = elem.second; +} + + +void CacheItem::validateUINames(const OUString& sActLocale) +{ + if (sActLocale.isEmpty()) + return; + + // 1) check UINames first + const_iterator pUINames = find(PROPNAME_UINAMES); + const_iterator pUIName = find(PROPNAME_UINAME ); + + ::comphelper::SequenceAsHashMap lUINames; + if (pUINames != end()) + lUINames << pUINames->second; + + OUString sUIName; + if (pUIName != end()) + pUIName->second >>= sUIName; + + if (!sUIName.isEmpty()) + { + // 1a) set UIName inside list of UINames for current locale + lUINames[sActLocale] <<= sUIName; + } + else if (!lUINames.empty()) + { + // 1b) or get it from this list, if it not exist! + lUINames[sActLocale] >>= sUIName; + } + + (*this)[PROPNAME_UINAMES] <<= lUINames.getAsConstPropertyValueList(); + (*this)[PROPNAME_UINAME ] <<= sUIName; +} + + +css::uno::Sequence< css::beans::PropertyValue > CacheItem::getAsPackedPropertyValueList(bool bFinalized, bool bMandatory) const +{ + sal_Int32 c = static_cast(size()); + sal_Int32 i = 0; + + css::uno::Sequence< css::beans::PropertyValue > lList(c+2); + css::beans::PropertyValue* pList = lList.getArray(); + + for (const_iterator pProp = begin(); + pProp != end() ; + ++pProp ) + { + const OUString& rName = pProp->first.maString; + const css::uno::Any& rValue = pProp->second; + + if (!rValue.hasValue()) + continue; + assert (rName != PROPNAME_FINALIZED && rName != PROPNAME_MANDATORY); + + pList[i].Name = rName ; + pList[i].Value = rValue; + ++i; + } + pList[i].Name = PROPNAME_FINALIZED ; + pList[i].Value <<= bFinalized; + ++i; + pList[i].Name = PROPNAME_MANDATORY ; + pList[i].Value <<= bMandatory; + ++i; + lList.realloc(i); + + return lList; +} + + +static bool isSubSet(const css::uno::Any& aSubSet, + const css::uno::Any& aSet ) +{ + const css::uno::Type& aT1 = aSubSet.getValueType(); + const css::uno::Type& aT2 = aSet.getValueType(); + + if (!aT1.equals(aT2)) + { + return false; + } + + if (aSubSet.hasValue() && aSet.hasValue()) + { + css::uno::TypeClass aTypeClass = aT1.getTypeClass(); + switch(aTypeClass) + { + + case css::uno::TypeClass_BOOLEAN : + case css::uno::TypeClass_BYTE : + case css::uno::TypeClass_SHORT : + case css::uno::TypeClass_UNSIGNED_SHORT : + case css::uno::TypeClass_LONG : + case css::uno::TypeClass_UNSIGNED_LONG : + case css::uno::TypeClass_HYPER : + case css::uno::TypeClass_UNSIGNED_HYPER : + case css::uno::TypeClass_FLOAT : + case css::uno::TypeClass_DOUBLE : + { + bool bIs = (aSubSet == aSet); + return bIs; + } + + + case css::uno::TypeClass_STRING : + return aSubSet == aSet; + break; + + + case css::uno::TypeClass_STRUCT : + { + css::beans::PropertyValue p1; + css::beans::PropertyValue p2; + + if ( + (aSubSet >>= p1) && + (aSet >>= p2) + ) + { + bool bIs = (p1.Name == p2.Name) && isSubSet(p1.Value, p2.Value); + return bIs; + } + + css::beans::NamedValue n1; + css::beans::NamedValue n2; + + if ( + (aSubSet >>= n1) && + (aSet >>= n2) + ) + { + bool bIs = (n1.Name == n2.Name) && isSubSet(n1.Value, n2.Value); + return bIs; + } + } + break; + + + case css::uno::TypeClass_SEQUENCE : + { + css::uno::Sequence< OUString > uno_s1; + css::uno::Sequence< OUString > uno_s2; + + if ( + (aSubSet >>= uno_s1) && + (aSet >>= uno_s2) + ) + { + auto s2Begin = uno_s2.getConstArray(); + auto s2End = uno_s2.getConstArray() + uno_s2.getLength(); + + for (auto const& elem : uno_s1) + { + if (::std::find(s2Begin, s2End, elem) == s2End) + { + return false; + } + } + return true; + } + + css::uno::Sequence< css::beans::PropertyValue > uno_p1; + css::uno::Sequence< css::beans::PropertyValue > uno_p2; + + if ( + (aSubSet >>= uno_p1) && + (aSet >>= uno_p2) + ) + { + ::comphelper::SequenceAsHashMap stl_p1(uno_p1); + ::comphelper::SequenceAsHashMap stl_p2(uno_p2); + + for (auto const& elem : stl_p1) + { + ::comphelper::SequenceAsHashMap::const_iterator it2 = stl_p2.find(elem.first); + if (it2 == stl_p2.end()) + { + return false; + } + if (!isSubSet(elem.second, it2->second)) + { + return false; + } + } + return true; + } + + css::uno::Sequence< css::beans::NamedValue > uno_n1; + css::uno::Sequence< css::beans::NamedValue > uno_n2; + + if ( + (aSubSet >>= uno_n1) && + (aSet >>= uno_n2) + ) + { + ::comphelper::SequenceAsHashMap stl_n1(uno_n1); + ::comphelper::SequenceAsHashMap stl_n2(uno_n2); + + for (auto const& elem : stl_n1) + { + ::comphelper::SequenceAsHashMap::const_iterator it2 = stl_n2.find(elem.first); + if (it2 == stl_n2.end()) + { + return false; + } + if (!isSubSet(elem.second, it2->second)) + { + return false; + } + } + return true; + } + } + break; + default: break; + } + } + OSL_FAIL("isSubSet() ... this point should not be reached!"); + return false; +} + + +bool CacheItem::haveProps(o3tl::span< const css::beans::NamedValue > lProps) const +{ + for (auto const& prop : lProps) + { + // i) one required property does not exist at this item => return false + const_iterator pItThis = find(prop.Name); + if (pItThis == end()) + { + return false; + } + + // ii) one item does not have the right value => return false + if (!isSubSet(prop.Value, pItThis->second)) + { + return false; + } + } + + // this method was not broken before => + // the given property set seems to match with our + // own properties in its minimum => return TRUE + return true; +} + + +bool CacheItem::dontHaveProps(o3tl::span< const css::beans::NamedValue > lProps) const +{ + for (auto const& prop : lProps) + { + // i) one item does not exist in general + // => continue with next one, because + // "excluding" means... "don't have it". + // And "not exists" matches to "don't have it". + const_iterator pItThis = find(prop.Name); + if (pItThis == end()) + { + continue; + } + + // ii) one item have the right value => return false + // because this item has the requested property... + // But we checked for "don't have it" here. + if (isSubSet(prop.Value, pItThis->second)) + { + return false; + } + } + + // this method was not broken before => + // That means: this item has no matching property + // of the given set. It "don't have" it ... => return true. + return true; +} + +FlatDetectionInfo::FlatDetectionInfo() : + bMatchByExtension(false), bMatchByPattern(false), bPreselectedByDocumentService(false) {} + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/cacheitem.hxx b/filter/source/config/cache/cacheitem.hxx new file mode 100644 index 000000000..b20bf72c8 --- /dev/null +++ b/filter/source/config/cache/cacheitem.hxx @@ -0,0 +1,177 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace filter::config { + + +/** @short represent an item of a FilterCache + instance. + + @descr This class is not threadsafe tp perform + operations, which use many instances of + this class! Synchronizations must be done outside. + */ +class CacheItem : public ::comphelper::SequenceAsHashMap +{ + + public: + + + /** @short creates an empty item. + */ + CacheItem(); + + + /** @short update only properties, which are given by the + specified rItem. + + @descr Update means: - add new properties + - change existing values + + @param rUpdateItem + another cache item, which contains some special + properties, which should by used for updating + this one. + */ + void update(const CacheItem& rUpdateItem); + + + /** @short check, if the given properties exist + at this item. + + @descr All properties are compared in its minimum. + E.g: string lists => only the requested items + are checked. Additional existing items are ignored. + + @param lProps + contains all properties, which must exist at this item. + + @return sal_True if all given properties exists + at this item; sal_False otherwise. + */ + bool haveProps(o3tl::span< const css::beans::NamedValue > lProps) const; + + + /** @short check, if the given properties don't exist + at this item. + + @descr All properties are compared in its minimum. + E.g: string lists => only the requested items + are checked. Additional existing items are ignored. + + @param lProps + contains all properties, which should not exist at this item. + + @return sal_False if at least on property exists at this item(!); + sal_True otherwise. + */ + bool dontHaveProps(o3tl::span< const css::beans::NamedValue > lProps) const; + + + /** @short because we know two UIName properties + (a list with all locales and the value + for the current locale only), we must be sure + that the correspond together. + + @param sActLocale + must specify the current office locale. + It's needed to address the UIName property inside + the list of possible ones. + */ + void validateUINames(const OUString& sActLocale); + + + /** @short convert this structure to a seq< PropertyValue > + and ignore all empty properties! + + @descr Normally the converter routines of the base class + SequenceAsHashMap do this job already. + But it doesn't provide a "pack" mechanism to + ignore properties with empty (means "void") values. + + @return css::uno::Sequence< css::beans::PropertyValue > + as a list of all properties of this cacheitem, + where empty properties was removed. + */ + css::uno::Sequence< css::beans::PropertyValue > getAsPackedPropertyValueList(bool bFinalized, bool bMandatory) const; +}; + + +/** @short represent an item list of a FilterCache + instance. + */ +typedef std::unordered_map< OUString, + CacheItem > CacheItemList; + + +/** @short supports registration of multiple key to + another string information. + + @descr E.g. a list of internal type names can be registered + to an extension. Organization as an hash makes it + faster than searching inside vectors. + + On the other side e.g. URLPattern can't be really addressed + by a hash value ... because the use wildcards. But + there we need key-value pairs too, which can't be provided + by a pure vector! + */ +typedef std::unordered_map< OUString, + std::vector > CacheItemRegistration; + + +/** @short is used to collect all matching types of a URL + during type detection. + + @descr Every type in this list is combined with an information, + which property matched to the given URL. The user of this + structure can decide then, if a deep detection should be + suppressed e.g. if a URLPattern was used. + */ +struct FlatDetectionInfo +{ + // the internal type name + OUString sType; + + // this type was found by a matching the URL extension + bool bMatchByExtension; + + // this type was found by a matching URL Pattern + bool bMatchByPattern; + + // the user selected this type implicit by selecting a corresponding office module + bool bPreselectedByDocumentService; + + FlatDetectionInfo(); +}; + +typedef ::std::vector< FlatDetectionInfo > FlatDetection; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/cacheupdatelistener.cxx b/filter/source/config/cache/cacheupdatelistener.cxx new file mode 100644 index 000000000..c613d0549 --- /dev/null +++ b/filter/source/config/cache/cacheupdatelistener.cxx @@ -0,0 +1,182 @@ +/* -*- 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 "cacheupdatelistener.hxx" +#include "configflush.hxx" + +#include +#include +#include +#include +#include +#include + + +namespace filter::config{ + +CacheUpdateListener::CacheUpdateListener(FilterCache &rFilterCache, + css::uno::Reference< css::uno::XInterface > xConfigAccess, + FilterCache::EItemType eConfigType) + : m_rCache(rFilterCache) + , m_xConfig(std::move(xConfigAccess)) + , m_eConfigType(eConfigType) +{ +} + +CacheUpdateListener::~CacheUpdateListener() +{ +} + +void CacheUpdateListener::startListening() +{ + // SAFE -> + std::unique_lock aLock(m_aMutex); + css::uno::Reference< css::util::XChangesNotifier > xNotifier(m_xConfig, css::uno::UNO_QUERY); + aLock.unlock(); + // <- SAFE + + if (!xNotifier.is()) + return; + + css::uno::Reference< css::util::XChangesListener > xThis(this); + xNotifier->addChangesListener(xThis); +} + + +void CacheUpdateListener::stopListening() +{ + // SAFE -> + std::unique_lock aLock(m_aMutex); + css::uno::Reference< css::util::XChangesNotifier > xNotifier(m_xConfig, css::uno::UNO_QUERY); + aLock.unlock(); + // <- SAFE + + if (!xNotifier.is()) + return; + + css::uno::Reference< css::util::XChangesListener > xThis(this); + xNotifier->removeChangesListener(xThis); +} + + +void SAL_CALL CacheUpdateListener::changesOccurred(const css::util::ChangesEvent& aEvent) +{ + // SAFE -> + std::unique_lock aLock(m_aMutex); + + // disposed ? + if ( ! m_xConfig.is()) + return; + + FilterCache::EItemType eType = m_eConfigType; + + aLock.unlock(); + // <- SAFE + + std::vector lChangedItems; + sal_Int32 c = aEvent.Changes.getLength(); + sal_Int32 i = 0; + + for (i=0; i + 1) Filters/Filter["filtername"]/Property + 2) Filters/Filter["filtername"]/LocalizedProperty/Locale + */ + + aChange.Accessor >>= sOrgPath; + if ( ! ::utl::splitLastFromConfigurationPath(sOrgPath, sTempPath, sLocale)) + continue; + sOrgPath = sTempPath; + if ( ! ::utl::splitLastFromConfigurationPath(sOrgPath, sTempPath, sProperty)) + { + sNode = sLocale; + sProperty.clear(); + sLocale.clear(); + } + else + { + sOrgPath = sTempPath; + if ( ! ::utl::splitLastFromConfigurationPath(sOrgPath, sTempPath, sNode)) + { + sNode = sProperty; + sProperty = sLocale; + sLocale.clear(); + } + } + + if ( sNode.isEmpty() ) + continue; + + auto pIt = ::std::find(lChangedItems.cbegin(), lChangedItems.cend(), sNode); + if (pIt == lChangedItems.cend()) + lChangedItems.push_back(sNode); + } + + bool bNotifyRefresh = false; + for (auto const& changedItem : lChangedItems) + { + try + { + m_rCache.refreshItem(eType, changedItem); + } + catch(const css::container::NoSuchElementException&) + { + // can be ignored! Because we must be aware that + // sItem was removed from the configuration and we forced an update of the cache. + // But we know, that the cache is up-to-date know and has thrown this exception afterwards .-) + } + // NO FLUSH! Otherwise we start a never ending story here .-) + bNotifyRefresh = true; + } + + // notify sfx cache about the changed filter cache .-) + if (bNotifyRefresh) + { + rtl::Reference< ConfigFlush > xRefreshBroadcaster = new ConfigFlush(); + xRefreshBroadcaster->refresh(); + } +} + + +void SAL_CALL CacheUpdateListener::disposing(const css::lang::EventObject& aEvent) +{ + // SAFE -> + std::unique_lock aLock(m_aMutex); + if (aEvent.Source == m_xConfig) + m_xConfig.clear(); + // <- SAFE +} + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/cacheupdatelistener.hxx b/filter/source/config/cache/cacheupdatelistener.hxx new file mode 100644 index 000000000..3870b9916 --- /dev/null +++ b/filter/source/config/cache/cacheupdatelistener.hxx @@ -0,0 +1,113 @@ +/* -*- 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 . + */ +#pragma once + +#include "filtercache.hxx" +#include +#include +#include + + +namespace filter::config { + + +/** @short implements a listener, which will update the + global filter cache, if the underlying configuration + wa changed by other processes. + */ +class CacheUpdateListener : public ::cppu::WeakImplHelper< css::util::XChangesListener > +{ + + // member + + private: + + std::mutex m_aMutex; + + /** @short reference to the singleton(!) filter cache implementation, + which should be updated by this thread. */ + FilterCache &m_rCache; + + /** @short holds the configuration access, where we listen alive. */ + css::uno::Reference< css::uno::XInterface > m_xConfig; + + /** @short every instance of this update listener listen on + a special sub set of the filter configuration. + So it should know, which type of configuration entry + it must put into the filter cache, if the configuration notifies changes ... */ + FilterCache::EItemType m_eConfigType; + + + // native interface + + public: + + + // ctor/dtor + + /** @short initialize new instance of this class. + + @descr Listening won't be started here. It can be done + by calling startListening() on this instance. + + @see startListening() + + @param xConfigAccess + the configuration access, where this instance should listen for changes. + + @param eConfigType + specify the type of configuration. + */ + CacheUpdateListener(FilterCache &rFilterCache, + css::uno::Reference< css::uno::XInterface > xConfigAccess, + FilterCache::EItemType eConfigType); + + + /** @short standard dtor. + */ + virtual ~CacheUpdateListener() override; + + + /** @short starts listening. + */ + void startListening(); + + + /** @short stop listening. + */ + void stopListening(); + + + // uno interface + + public: + + + // XChangesListener + + virtual void SAL_CALL changesOccurred(const css::util::ChangesEvent& aEvent) override; + + + // lang.XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override; +}; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/configflush.cxx b/filter/source/config/cache/configflush.cxx new file mode 100644 index 000000000..34ac28782 --- /dev/null +++ b/filter/source/config/cache/configflush.cxx @@ -0,0 +1,112 @@ +/* -*- 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 "configflush.hxx" +#include +#include +#include + + +namespace filter::config{ + +ConfigFlush::ConfigFlush() + : m_lListener(m_aMutex) +{ +} + +ConfigFlush::~ConfigFlush() +{ +} + +OUString SAL_CALL ConfigFlush::getImplementationName() +{ + return "com.sun.star.comp.filter.config.ConfigFlush"; + // <- SAFE +} + +sal_Bool SAL_CALL ConfigFlush::supportsService(const OUString& sServiceName) +{ + return cppu::supportsService(this, sServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ConfigFlush::getSupportedServiceNames() +{ + return { "com.sun.star.document.FilterConfigRefresh" }; +} + +void SAL_CALL ConfigFlush::refresh() +{ + // notify listener outside the lock! + // The used listener helper lives if we live + // and is threadsafe by itself. + // Further it's not a good idea to hold the own lock + // if an outside object is called :-) + css::lang::EventObject aSource (static_cast< css::util::XRefreshable* >(this)); + comphelper::OInterfaceContainerHelper2* pContainer = m_lListener.getContainer(cppu::UnoType::get()); + if (!pContainer) + return; + + comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer); + while (pIterator.hasMoreElements()) + { + try + { + // ... this pointer can be interesting to find out, where will be called as listener + // Don't optimize it to a direct iterator cast :-) + css::util::XRefreshListener* pListener = static_cast(pIterator.next()); + pListener->refreshed(aSource); + } + catch(const css::uno::Exception&) + { + // ignore any "damaged" flush listener! + // May its remote reference is broken ... + pIterator.remove(); + } + } +} + + +void SAL_CALL ConfigFlush::addRefreshListener(const css::uno::Reference< css::util::XRefreshListener >& xListener) +{ + // no locks necessary + // used helper lives if we live and is threadsafe by itself ... + m_lListener.addInterface(cppu::UnoType::get(), + xListener); +} + + +void SAL_CALL ConfigFlush::removeRefreshListener(const css::uno::Reference< css::util::XRefreshListener >& xListener) +{ + // no locks necessary + // used helper lives if we live and is threadsafe by itself ... + m_lListener.removeInterface(cppu::UnoType::get(), + xListener); +} + + +} // namespace filter::config + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_ConfigFlush_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new filter::config::ConfigFlush()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/configflush.hxx b/filter/source/config/cache/configflush.hxx new file mode 100644 index 000000000..d03351673 --- /dev/null +++ b/filter/source/config/cache/configflush.hxx @@ -0,0 +1,89 @@ +/* -*- 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 . + */ +#pragma once + +#include +#include +#include +#include +#include + + +namespace filter::config { + + +/** @short supports registration of XRefreshListener + on the global filter configuration. + + @descr Such refresh listener will be called in case the + type/filter configuration will be changed at runtime. + */ +class ConfigFlush final : public cppu::BaseMutex + , public ::cppu::WeakImplHelper< + css::util::XRefreshable, + css::lang::XServiceInfo + > +{ + /** @short holds all listener, which are registered at this instance. */ + comphelper::OMultiTypeInterfaceContainerHelper2 m_lListener; + + + // native interface + + public: + + + // ctor/dtor + + /** @short standard ctor. + */ + ConfigFlush(); + + + /** @short standard dtor. + */ + virtual ~ConfigFlush() override; + + + // uno interface + + public: + + + // XServiceInfo + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + + // XRefreshable + + virtual void SAL_CALL refresh() override; + + virtual void SAL_CALL addRefreshListener(const css::uno::Reference< css::util::XRefreshListener >& xListener) override; + + virtual void SAL_CALL removeRefreshListener(const css::uno::Reference< css::util::XRefreshListener >& xListener) override; +}; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/constant.hxx b/filter/source/config/cache/constant.hxx new file mode 100644 index 000000000..86e6e6de9 --- /dev/null +++ b/filter/source/config/cache/constant.hxx @@ -0,0 +1,153 @@ +/* -*- 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 . + */ +#pragma once + +#include + +/* disable impl_loadOnDemand function of BaseContainer for certain + functions, where it the feature "impl_loadItemOnDemand() of class FilterCache + can be used instead of loadAll()!*/ +// #define LOAD_IMPLICIT + + +/** @short used to identify a some generic item properties against the + configuration API and can be used at all name containers + (based on this filtercache) too. + */ +inline constexpr OUStringLiteral PROPNAME_NAME = u"Name"; + +/** @short used to identify a type item property against the + configuration API and can be used at all name containers + (based on this filtercache) too. + */ +inline constexpr OUStringLiteral PROPNAME_UINAME = u"UIName"; +inline constexpr OUStringLiteral PROPNAME_UINAMES = u"UINames"; +inline constexpr OUStringLiteral PROPNAME_PREFERRED = u"Preferred"; +inline constexpr OUStringLiteral PROPNAME_PREFERREDFILTER = u"PreferredFilter"; +inline constexpr OUStringLiteral PROPNAME_DETECTSERVICE = u"DetectService"; +inline constexpr OUStringLiteral PROPNAME_MEDIATYPE = u"MediaType"; +inline constexpr OUStringLiteral PROPNAME_CLIPBOARDFORMAT = u"ClipboardFormat"; +inline constexpr OUStringLiteral PROPNAME_URLPATTERN = u"URLPattern"; +inline constexpr OUStringLiteral PROPNAME_EXTENSIONS = u"Extensions"; + +/** @short used to identify a filter item property against the + configuration API and can be used at all name containers + (based on this filtercache) too. + */ +inline constexpr OUStringLiteral PROPNAME_TYPE = u"Type"; +inline constexpr OUStringLiteral PROPNAME_DOCUMENTSERVICE = u"DocumentService"; +inline constexpr OUStringLiteral PROPNAME_FILTERSERVICE = u"FilterService"; +inline constexpr OUStringLiteral PROPNAME_UICOMPONENT = u"UIComponent"; +inline constexpr OUStringLiteral PROPNAME_FLAGS = u"Flags"; +inline constexpr OUStringLiteral PROPNAME_USERDATA = u"UserData"; +inline constexpr OUStringLiteral PROPNAME_TEMPLATENAME = u"TemplateName"; +inline constexpr OUStringLiteral PROPNAME_FILEFORMATVERSION = u"FileFormatVersion"; +inline constexpr OUStringLiteral PROPNAME_EXPORTEXTENSION = u"ExportExtension"; +inline constexpr OUStringLiteral PROPNAME_ENABLED = u"Enabled"; + +/** @short used to identify a frame loader or detect service item + property against the configuration API and can be used + at all name containers (based on this filtercache) too. + */ +inline constexpr OUStringLiteral PROPNAME_TYPES = u"Types"; + +/** @short used to identify the list of sorted filters for a specific + office module + */ +inline constexpr OUStringLiteral PROPNAME_SORTEDFILTERLIST = u"SortedFilterList"; + +/** @short implicit properties. which are used at the container interface only. + */ +inline constexpr OUStringLiteral PROPNAME_FINALIZED = u"Finalized"; +inline constexpr OUStringLiteral PROPNAME_MANDATORY = u"Mandatory"; + +/** @short used to identify a set of items against the configuration API. */ +inline constexpr OUStringLiteral CFGSET_TYPES = u"Types"; +inline constexpr OUStringLiteral CFGSET_FILTERS = u"Filters"; +inline constexpr OUStringLiteral CFGSET_FRAMELOADERS = u"FrameLoaders"; +inline constexpr OUStringLiteral CFGSET_CONTENTHANDLERS = u"ContentHandlers"; + +/** @short used to address some configuration keys directly. + + @descr Such direct keys should be used with function + FilterCache::impl_getDirectCFGValue() only! + + @TODO define these direct keys ... + */ +inline constexpr OUStringLiteral CFGDIRECTKEY_OFFICELOCALE = u"/org.openoffice.Setup/L10N/ooLocale"; +inline constexpr OUStringLiteral CFGDIRECTKEY_DEFAULTFRAMELOADER = u"/org.openoffice.TypeDetection.Misc/Defaults/DefaultFrameLoader"; +#define CFGDIRECTKEY_PRODUCTNAME "/org.openoffice.Setup/Product/ooName" + +// Note that these flag bits have parallel names in +// comphelper/inc/comphelper/documentconstants.hxx . See that file for +// documentation on their meaning. + +/** @short names of filter flags, sorted in alphabetical order */ +inline constexpr OUStringLiteral FLAGNAME_3RDPARTYFILTER = u"3RDPARTYFILTER"; +inline constexpr OUStringLiteral FLAGNAME_ALIEN = u"ALIEN"; +inline constexpr OUStringLiteral FLAGNAME_CONSULTSERVICE = u"CONSULTSERVICE"; +inline constexpr OUStringLiteral FLAGNAME_DEFAULT = u"DEFAULT"; +inline constexpr OUStringLiteral FLAGNAME_ENCRYPTION = u"ENCRYPTION"; +inline constexpr OUStringLiteral FLAGNAME_EXPORT = u"EXPORT"; +inline constexpr OUStringLiteral FLAGNAME_GPGENCRYPTION = u"GPGENCRYPTION"; +inline constexpr OUStringLiteral FLAGNAME_IMPORT = u"IMPORT"; +inline constexpr OUStringLiteral FLAGNAME_INTERNAL = u"INTERNAL"; +inline constexpr OUStringLiteral FLAGNAME_NOTINFILEDIALOG = u"NOTINFILEDIALOG"; +inline constexpr OUStringLiteral FLAGNAME_NOTINSTALLED = u"NOTINSTALLED"; +inline constexpr OUStringLiteral FLAGNAME_OWN = u"OWN"; +inline constexpr OUStringLiteral FLAGNAME_PACKED = u"PACKED"; +inline constexpr OUStringLiteral FLAGNAME_PASSWORDTOMODIFY = u"PASSWORDTOMODIFY"; +inline constexpr OUStringLiteral FLAGNAME_PREFERRED = u"PREFERRED"; +inline constexpr OUStringLiteral FLAGNAME_STARTPRESENTATION = u"STARTPRESENTATION"; +inline constexpr OUStringLiteral FLAGNAME_READONLY = u"READONLY"; +inline constexpr OUStringLiteral FLAGNAME_SUPPORTSSELECTION = u"SUPPORTSSELECTION"; +inline constexpr OUStringLiteral FLAGNAME_TEMPLATE = u"TEMPLATE"; +inline constexpr OUStringLiteral FLAGNAME_TEMPLATEPATH = u"TEMPLATEPATH"; +inline constexpr OUStringLiteral FLAGNAME_COMBINED = u"COMBINED"; +inline constexpr OUStringLiteral FLAGNAME_SUPPORTSSIGNING = u"SUPPORTSSIGNING"; +inline constexpr OUStringLiteral FLAGNAME_EXOTIC = u"EXOTIC"; + +/** @short some uno service names. + */ +inline constexpr OUStringLiteral SERVICE_CONFIGURATIONUPDATEACCESS = u"com.sun.star.configuration.ConfigurationUpdateAccess"; +inline constexpr OUStringLiteral SERVICE_CONFIGURATIONACCESS = u"com.sun.star.configuration.ConfigurationAccess"; + +/** @short some configuration paths. + */ +inline constexpr OUStringLiteral CFGPACKAGE_TD_TYPES = u"/org.openoffice.TypeDetection.Types"; +inline constexpr OUStringLiteral CFGPACKAGE_TD_FILTERS = u"/org.openoffice.TypeDetection.Filter"; +inline constexpr OUStringLiteral CFGPACKAGE_TD_OTHERS = u"/org.openoffice.TypeDetection.Misc"; +inline constexpr OUStringLiteral CFGPACKAGE_TD_OLD = u"/org.openoffice.Office.TypeDetection"; + +/** @short some default values. + */ +inline constexpr OUStringLiteral DEFAULT_OFFICELOCALE = u"en-US"; + +/** @short used for the queries of the FilterFactory service. + */ +inline constexpr OUStringLiteral QUERY_IDENTIFIER_MATCHBYDOCUMENTSERVICE = u"matchByDocumentService"; +inline constexpr OUStringLiteral QUERY_IDENTIFIER_GETPREFERREDFILTERFORTYPE = u"getDefaultFilterForType"; +inline constexpr OUStringLiteral QUERY_IDENTIFIER_GET_SORTED_FILTERLIST = u"getSortedFilterList()"; + +inline constexpr OUStringLiteral QUERY_PARAM_IFLAGS = u"iflags"; +inline constexpr OUStringLiteral QUERY_PARAM_EFLAGS = u"eflags"; +inline constexpr OUStringLiteral QUERY_PARAM_MODULE = u"module"; +#define QUERY_CONSTVALUE_ALL "all" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/contenthandlerfactory.cxx b/filter/source/config/cache/contenthandlerfactory.cxx new file mode 100644 index 000000000..089f8db5f --- /dev/null +++ b/filter/source/config/cache/contenthandlerfactory.cxx @@ -0,0 +1,103 @@ +/* -*- 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 "contenthandlerfactory.hxx" + +#include +#include + + +namespace filter::config{ + +ContentHandlerFactory::ContentHandlerFactory(const css::uno::Reference< css::uno::XComponentContext >& rxContext) + : m_xContext(rxContext) +{ + BaseContainer::init("com.sun.star.comp.filter.config.ContentHandlerFactory" , + { "com.sun.star.frame.ContentHandlerFactory" }, + FilterCache::E_CONTENTHANDLER ); +} + + +ContentHandlerFactory::~ContentHandlerFactory() +{ +} + + +css::uno::Reference< css::uno::XInterface > SAL_CALL ContentHandlerFactory::createInstance(const OUString& sHandler) +{ + return createInstanceWithArguments(sHandler, css::uno::Sequence< css::uno::Any >()); +} + + +css::uno::Reference< css::uno::XInterface > SAL_CALL ContentHandlerFactory::createInstanceWithArguments(const OUString& sHandler , + const css::uno::Sequence< css::uno::Any >& lArguments) +{ + css::uno::Reference< css::uno::XInterface > xHandler; + + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + auto & cache = GetTheFilterCache(); + + // search handler on cache + CacheItem aHandler = cache.getItem(FilterCache::E_CONTENTHANDLER, sHandler); + + // create service instance + xHandler = m_xContext->getServiceManager()->createInstanceWithContext(sHandler, m_xContext); + + // initialize filter + css::uno::Reference< css::lang::XInitialization > xInit(xHandler, css::uno::UNO_QUERY); + if (xInit.is()) + { + // format: lInitData[0] = seq, which contains all configuration properties of this handler + // lInitData[1] = lArguments[0] + // ... + // lInitData[n] = lArguments[n-1] + css::uno::Sequence< css::beans::PropertyValue > lConfig; + aHandler >> lConfig; + + ::std::vector< css::uno::Any > stlArguments(comphelper::sequenceToContainer< ::std::vector< css::uno::Any > >(lArguments)); + stlArguments.insert(stlArguments.begin(), css::uno::Any(lConfig)); + + xInit->initialize(comphelper::containerToSequence(stlArguments)); + } + + return xHandler; + // <- SAFE +} + + +css::uno::Sequence< OUString > SAL_CALL ContentHandlerFactory::getAvailableServiceNames() +{ + // must be the same list as ((XNameAccess*)this)->getElementNames() return! + return BaseContainer::getElementNames(); +} + +} // namespace filter::config + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_ContentHandlerFactory_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new filter::config::ContentHandlerFactory(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/contenthandlerfactory.hxx b/filter/source/config/cache/contenthandlerfactory.hxx new file mode 100644 index 000000000..5c3ecd760 --- /dev/null +++ b/filter/source/config/cache/contenthandlerfactory.hxx @@ -0,0 +1,99 @@ +/* -*- 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 . + */ + +#pragma once + +#include "basecontainer.hxx" +#include +#include + + +namespace filter::config { + + +/** @short implements the service ContentHandlerFactory. + */ +class ContentHandlerFactory : public ::cppu::ImplInheritanceHelper< BaseContainer , + css::frame::XLoaderFactory > +{ + + // native interface + + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + public: + + + // ctor/dtor + + /** @short standard ctor to connect this interface wrapper to + the global filter cache instance ... + + @param rxContext + reference to the uno service manager, which created this service instance. + */ + explicit ContentHandlerFactory(const css::uno::Reference< css::uno::XComponentContext >& rxContext); + + + /** @short standard dtor. + */ + virtual ~ContentHandlerFactory() override; + + + // uno interface + + public: + + + // XMultiServiceFactory + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance(const OUString& sHandler) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments(const OUString& sHandler , + const css::uno::Sequence< css::uno::Any >& lArguments) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + + + public: + + // Overrides to resolve ambiguity + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override + { return BaseContainer::getByName(aName); } + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override + { return BaseContainer::getElementNames(); } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { return BaseContainer::hasByName(aName); } + + virtual css::uno::Type SAL_CALL getElementType() override + { return BaseContainer::getElementType(); } + virtual sal_Bool SAL_CALL hasElements() override + { return BaseContainer::hasElements(); } + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByQuery( const OUString& Query ) override + { return BaseContainer::createSubSetEnumerationByQuery(Query); } + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByProperties( const css::uno::Sequence< css::beans::NamedValue >& Properties ) override + { return BaseContainer::createSubSetEnumerationByProperties(Properties); } + + +}; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/filtercache.cxx b/filter/source/config/cache/filtercache.cxx new file mode 100644 index 000000000..b32586162 --- /dev/null +++ b/filter/source/config/cache/filtercache.cxx @@ -0,0 +1,2236 @@ +/* -*- 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 +#include +#include "filtercache.hxx" +#include "constant.hxx" +#include "cacheupdatelistener.hxx" + +/*TODO see using below ... */ +#define AS_ENABLE_FILTER_UINAMES + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace filter::config{ + +FilterCache::FilterCache() + : m_eFillState(E_CONTAINS_NOTHING ) +{ + int i = 0; + OUString sStandardProps[10]; + + sStandardProps[i++] = PROPNAME_USERDATA; + sStandardProps[i++] = PROPNAME_TEMPLATENAME; + sStandardProps[i++] = PROPNAME_ENABLED; + // E_READ_UPDATE only above + sStandardProps[i++] = PROPNAME_TYPE; + sStandardProps[i++] = PROPNAME_FILEFORMATVERSION; + sStandardProps[i++] = PROPNAME_UICOMPONENT; + sStandardProps[i++] = PROPNAME_FILTERSERVICE; + sStandardProps[i++] = PROPNAME_DOCUMENTSERVICE; + sStandardProps[i++] = PROPNAME_EXPORTEXTENSION; + sStandardProps[i++] = PROPNAME_FLAGS; // must be last. + assert(i == SAL_N_ELEMENTS(sStandardProps)); + + // E_READ_NOTHING -> creative nothingness. + m_aStandardProps[E_READ_STANDARD] = + css::uno::Sequence< OUString >(sStandardProps + 3, 7); + m_aStandardProps[E_READ_UPDATE] = + css::uno::Sequence< OUString >(sStandardProps, 3); + m_aStandardProps[E_READ_ALL] = + css::uno::Sequence< OUString >(sStandardProps, + SAL_N_ELEMENTS(sStandardProps)); + + i = 0; + OUString sTypeProps[7]; + sTypeProps[i++] = PROPNAME_MEDIATYPE; + // E_READ_UPDATE only above + sTypeProps[i++] = PROPNAME_PREFERREDFILTER; + sTypeProps[i++] = PROPNAME_DETECTSERVICE; + sTypeProps[i++] = PROPNAME_URLPATTERN; + sTypeProps[i++] = PROPNAME_EXTENSIONS; + sTypeProps[i++] = PROPNAME_PREFERRED; + sTypeProps[i++] = PROPNAME_CLIPBOARDFORMAT; + assert(i == SAL_N_ELEMENTS(sTypeProps)); + + // E_READ_NOTHING -> more creative nothingness. + m_aTypeProps[E_READ_STANDARD] = + css::uno::Sequence< OUString >(sTypeProps + 1, 6); + m_aTypeProps[E_READ_UPDATE] = + css::uno::Sequence< OUString >(sTypeProps, 1); + m_aTypeProps[E_READ_ALL] = + css::uno::Sequence< OUString >(sTypeProps, + SAL_N_ELEMENTS(sTypeProps)); +} + + +FilterCache::~FilterCache() +{ + if (m_xTypesChglisteners.is()) + m_xTypesChglisteners->stopListening(); + if (m_xFiltersChgListener.is()) + m_xFiltersChgListener->stopListening(); +} + + +std::unique_ptr FilterCache::clone() const +{ + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + auto pClone = std::make_unique(); + + // Don't copy the configuration access points here. + // They will be created on demand inside the cloned instance, + // if they are needed. + + pClone->m_lTypes = m_lTypes; + pClone->m_lFilters = m_lFilters; + pClone->m_lFrameLoaders = m_lFrameLoaders; + pClone->m_lContentHandlers = m_lContentHandlers; + pClone->m_lExtensions2Types = m_lExtensions2Types; + pClone->m_lURLPattern2Types = m_lURLPattern2Types; + + pClone->m_sActLocale = m_sActLocale; + + pClone->m_eFillState = m_eFillState; + + pClone->m_lChangedTypes = m_lChangedTypes; + pClone->m_lChangedFilters = m_lChangedFilters; + pClone->m_lChangedFrameLoaders = m_lChangedFrameLoaders; + pClone->m_lChangedContentHandlers = m_lChangedContentHandlers; + + return pClone; + // <- SAFE ---------------------------------- +} + + +void FilterCache::takeOver(const FilterCache& rClone) +{ + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + // a) + // Don't copy the configuration access points here! + // We must use our own ones... + + // b) + // Further we can ignore the uno service manager. + // We should already have a valid instance. + + // c) + // Take over only changed items! + // Otherwise we risk the following scenario: + // c1) clone_1 contains changed filters + // c2) clone_2 container changed types + // c3) clone_1 take over changed filters and unchanged types + // c4) clone_2 take over unchanged filters(!) and changed types(!) + // c5) c4 overwrites c3! + + if (!rClone.m_lChangedTypes.empty()) + m_lTypes = rClone.m_lTypes; + if (!rClone.m_lChangedFilters.empty()) + m_lFilters = rClone.m_lFilters; + if (!rClone.m_lChangedFrameLoaders.empty()) + m_lFrameLoaders = rClone.m_lFrameLoaders; + if (!rClone.m_lChangedContentHandlers.empty()) + m_lContentHandlers = rClone.m_lContentHandlers; + + m_lChangedTypes.clear(); + m_lChangedFilters.clear(); + m_lChangedFrameLoaders.clear(); + m_lChangedContentHandlers.clear(); + + m_sActLocale = rClone.m_sActLocale; + + m_eFillState = rClone.m_eFillState; + + // renew all dependencies and optimizations + // Because we can't be sure, that changed filters on one clone + // and changed types of another clone work together. + // But here we can check against the later changes... + impl_validateAndOptimize(); + // <- SAFE ---------------------------------- +} + +void FilterCache::load(EFillState eRequired) +{ + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + // check if required fill state is already reached ... + // There is nothing to do then. + if ((m_eFillState & eRequired) == eRequired) + return; + + // Otherwise load the missing items. + + + // a) load some const values from configuration. + // These values are needed there for loading + // config items ... + // Further we load some std items from the + // configuration so we can try to load the first + // office document with a minimal set of values. + if (m_eFillState == E_CONTAINS_NOTHING) + { + impl_getDirectCFGValue(CFGDIRECTKEY_OFFICELOCALE) >>= m_sActLocale; + if (m_sActLocale.isEmpty()) + { + m_sActLocale = DEFAULT_OFFICELOCALE; + } + + // Support the old configuration support. Read it only one times during office runtime! + impl_readOldFormat(); + } + + + // b) If the required fill state was not reached + // but std values was already loaded ... + // we must load some further missing items. + impl_load(eRequired); + // <- SAFE +} + +bool FilterCache::isFillState(FilterCache::EFillState eState) const +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + return ((m_eFillState & eState) == eState); + // <- SAFE +} + + +std::vector FilterCache::getMatchingItemsByProps( EItemType eType , + o3tl::span< const css::beans::NamedValue > lIProps, + o3tl::span< const css::beans::NamedValue > lEProps) const +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // search for right list + // An exception is thrown - "eType" is unknown. + // => rList will be valid everytimes next line is reached. + const CacheItemList& rList = impl_getItemList(eType); + + std::vector lKeys; + lKeys.reserve(rList.size()); + + // search items, which provides all needed properties of set "lIProps" + // but not of set "lEProps"! + for (auto const& elem : rList) + { + if ( + (elem.second.haveProps(lIProps) ) && + (elem.second.dontHaveProps(lEProps)) + ) + { + lKeys.push_back(elem.first); + } + } + + return lKeys; + // <- SAFE +} + + +bool FilterCache::hasItems(EItemType eType) const +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // search for right list + // An exception is thrown - "eType" is unknown. + // => rList will be valid everytimes next line is reached. + const CacheItemList& rList = impl_getItemList(eType); + + return !rList.empty(); + // <- SAFE +} + + +std::vector FilterCache::getItemNames(EItemType eType) const +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // search for right list + // An exception is thrown - "eType" is unknown. + // => rList will be valid everytimes next line is reached. + const CacheItemList& rList = impl_getItemList(eType); + + std::vector lKeys; + for (auto const& elem : rList) + { + lKeys.push_back(elem.first); + } + return lKeys; + // <- SAFE +} + + +bool FilterCache::hasItem( EItemType eType, + const OUString& sItem) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // search for right list + // An exception is thrown - "eType" is unknown. + // => rList will be valid everytimes next line is reached. + const CacheItemList& rList = impl_getItemList(eType); + + // if item could not be found - check if it can be loaded + // from the underlying configuration layer. Might it was not already + // loaded into this FilterCache object before. + CacheItemList::const_iterator pIt = rList.find(sItem); + if (pIt != rList.end()) + return true; + + try + { + impl_loadItemOnDemand(eType, sItem); + // no exception => item could be loaded! + return true; + } + catch(const css::container::NoSuchElementException&) + {} + + return false; + // <- SAFE +} + + +CacheItem FilterCache::getItem( EItemType eType, + const OUString& sItem) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + CacheItem aItem = impl_getItem(eType, sItem); + // <- SAFE + return aItem; +} + + +CacheItem& FilterCache::impl_getItem( EItemType eType, + const OUString& sItem) +{ + // search for right list + // An exception is thrown if "eType" is unknown. + // => rList will be valid everytimes next line is reached. + CacheItemList& rList = impl_getItemList(eType); + + // check if item exists ... + CacheItemList::iterator pIt = rList.find(sItem); + if (pIt == rList.end()) + { + // ... or load it on demand from the + // underlying configuration layer. + // Note: NoSuchElementException is thrown automatically here if + // item could not be loaded! + pIt = impl_loadItemOnDemand(eType, sItem); + } + + /* Workaround for #137955# + Draw types and filters are installed ... but draw was disabled during setup. + We must suppress accessing these filters. Otherwise the office can crash. + Solution for the next major release: do not install those filters ! + */ + if (eType == E_FILTER) + { + CacheItem& rFilter = pIt->second; + OUString sDocService; + rFilter[PROPNAME_DOCUMENTSERVICE] >>= sDocService; + + // In Standalone-Impress the module WriterWeb is not installed + // but it is there to load help pages + bool bIsHelpFilter = sItem == "writer_web_HTML_help"; + + if ( !bIsHelpFilter && !impl_isModuleInstalled(sDocService) ) + { + OUString sMsg("The requested filter '" + sItem + + "' exists ... but it should not; because the corresponding LibreOffice module was not installed."); + throw css::container::NoSuchElementException(sMsg, css::uno::Reference< css::uno::XInterface >()); + } + } + + return pIt->second; +} + + +void FilterCache::removeItem( EItemType eType, + const OUString& sItem) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // search for right list + // An exception is thrown - "eType" is unknown. + // => rList will be valid everytimes next line is reached. + CacheItemList& rList = impl_getItemList(eType); + + CacheItemList::iterator pItem = rList.find(sItem); + if (pItem == rList.end()) + pItem = impl_loadItemOnDemand(eType, sItem); // throws NoSuchELementException! + rList.erase(pItem); + + impl_addItem2FlushList(eType, sItem); +} + + +void FilterCache::setItem( EItemType eType , + const OUString& sItem , + const CacheItem& aValue) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // search for right list + // An exception is thrown - "eType" is unknown. + // => rList will be valid everytimes next line is reached. + CacheItemList& rList = impl_getItemList(eType); + + // name must be part of the property set too ... otherwise our + // container query can't work correctly + CacheItem aItem = aValue; + aItem[PROPNAME_NAME] <<= sItem; + aItem.validateUINames(m_sActLocale); + + // remove implicit properties as e.g. FINALIZED or MANDATORY + // They can't be saved here and must be read on demand later, if they are needed. + removeStatePropsFromItem(aItem); + + rList[sItem] = aItem; + + impl_addItem2FlushList(eType, sItem); +} + + +void FilterCache::refreshItem( EItemType eType, + const OUString& sItem) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + impl_loadItemOnDemand(eType, sItem); +} + + +css::uno::Any FilterCache::getItemWithStateProps( EItemType eType, + const OUString& sItem) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + const CacheItem& rItem = impl_getItem(eType, sItem); + + // Note: Opening of the configuration layer throws some exceptions + // if it failed. So we mustn't check any reference here... + css::uno::Reference< css::container::XNameAccess > xPackage; + css::uno::Reference< css::container::XNameAccess > xSet; + switch(eType) + { + case E_TYPE : + { + xPackage.set(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW); + xPackage->getByName(CFGSET_TYPES) >>= xSet; + } + break; + + case E_FILTER : + { + xPackage.set(impl_openConfig(E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW); + xPackage->getByName(CFGSET_FILTERS) >>= xSet; + } + break; + + case E_FRAMELOADER : + { + /* TODO + Hack --> + The default frame loader can't be located inside the normal set of frame loaders. + It's an atomic property inside the misc cfg package. So we can't retrieve the information + about FINALIZED and MANDATORY very easy ... :-( + => set it to readonly/required everytimes :-) + */ + css::uno::Any aDirectValue = impl_getDirectCFGValue(CFGDIRECTKEY_DEFAULTFRAMELOADER); + OUString sDefaultFrameLoader; + if ( + (aDirectValue >>= sDefaultFrameLoader) && + (!sDefaultFrameLoader.isEmpty() ) && + (sItem == sDefaultFrameLoader ) + ) + { + css::uno::Sequence aProps = rItem.getAsPackedPropertyValueList(true, true); + return css::uno::Any(aProps); + } + /* <-- HACK */ + + xPackage.set(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW); + xPackage->getByName(CFGSET_FRAMELOADERS) >>= xSet; + } + break; + + case E_CONTENTHANDLER : + { + xPackage.set(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW); + xPackage->getByName(CFGSET_CONTENTHANDLERS) >>= xSet; + } + break; + default: break; + } + + bool bFinalized, bMandatory; + try + { + css::uno::Reference< css::beans::XProperty > xItem; + xSet->getByName(sItem) >>= xItem; + css::beans::Property aDescription = xItem->getAsProperty(); + + bFinalized = ((aDescription.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY ); + bMandatory = ((aDescription.Attributes & css::beans::PropertyAttribute::REMOVABLE) != css::beans::PropertyAttribute::REMOVABLE); + + } + catch(const css::container::NoSuchElementException&) + { + /* Ignore exceptions for missing elements inside configuration. + May by the following reason exists: + - The item does not exists inside the new configuration package org.openoffice.TypeDetection - but + we got it from the old package org.openoffice.Office/TypeDetection. We don't migrate such items + automatically to the new format. Because it will disturb e.g. the deinstallation of an external filter + package. Because such external filter can remove the old file - but not the automatically created new one ... + + => mark item as FINALIZED / MANDATORY, we don't support writing to the old format + */ + bFinalized = true; + bMandatory = true; + } + + css::uno::Sequence aProps = rItem.getAsPackedPropertyValueList(bFinalized, bMandatory); + + return css::uno::Any(aProps); + // <- SAFE +} + + +void FilterCache::removeStatePropsFromItem(CacheItem& rItem) +{ + CacheItem::iterator pIt = rItem.find(PROPNAME_FINALIZED); + if (pIt != rItem.end()) + rItem.erase(pIt); + pIt = rItem.find(PROPNAME_MANDATORY); + if (pIt != rItem.end()) + rItem.erase(pIt); +} + + +void FilterCache::flush() +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // renew all dependencies and optimizations + impl_validateAndOptimize(); + + if (!m_lChangedTypes.empty()) + { + css::uno::Reference< css::container::XNameAccess > xConfig(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::container::XNameAccess > xSet ; + + xConfig->getByName(CFGSET_TYPES) >>= xSet; + impl_flushByList(xSet, E_TYPE, m_lTypes, m_lChangedTypes); + + css::uno::Reference< css::util::XChangesBatch > xFlush(xConfig, css::uno::UNO_QUERY); + xFlush->commitChanges(); + } + + if (!m_lChangedFilters.empty()) + { + css::uno::Reference< css::container::XNameAccess > xConfig(impl_openConfig(E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::container::XNameAccess > xSet ; + + xConfig->getByName(CFGSET_FILTERS) >>= xSet; + impl_flushByList(xSet, E_FILTER, m_lFilters, m_lChangedFilters); + + css::uno::Reference< css::util::XChangesBatch > xFlush(xConfig, css::uno::UNO_QUERY); + xFlush->commitChanges(); + } + + /*TODO FrameLoader/ContentHandler must be flushed here too ... */ +} + + +void FilterCache::impl_flushByList(const css::uno::Reference< css::container::XNameAccess >& xSet , + EItemType eType , + const CacheItemList& rCache, + const std::vector& lItems) +{ + css::uno::Reference< css::container::XNameContainer > xAddRemoveSet(xSet, css::uno::UNO_QUERY); + css::uno::Reference< css::lang::XSingleServiceFactory > xFactory(xSet, css::uno::UNO_QUERY); + + for (auto const& item : lItems) + { + EItemFlushState eState = impl_specifyFlushOperation(xSet, rCache, item); + switch(eState) + { + case E_ITEM_REMOVED : + { + xAddRemoveSet->removeByName(item); + } + break; + + case E_ITEM_ADDED : + { + css::uno::Reference< css::container::XNameReplace > xItem (xFactory->createInstance(), css::uno::UNO_QUERY); + + // special case. no exception - but not a valid item => set must be finalized or mandatory! + // Reject flush operation by throwing an exception. At least one item couldn't be flushed. + if (!xItem.is()) + throw css::uno::Exception("Can not add item. Set is finalized or mandatory!", + css::uno::Reference< css::uno::XInterface >()); + + CacheItemList::const_iterator pItem = rCache.find(item); + impl_saveItem(xItem, eType, pItem->second); + xAddRemoveSet->insertByName(item, css::uno::Any(xItem)); + } + break; + + case E_ITEM_CHANGED : + { + css::uno::Reference< css::container::XNameReplace > xItem; + xSet->getByName(item) >>= xItem; + + // special case. no exception - but not a valid item => it must be finalized or mandatory! + // Reject flush operation by throwing an exception. At least one item couldn't be flushed. + if (!xItem.is()) + throw css::uno::Exception("Can not change item. It's finalized or mandatory!", + css::uno::Reference< css::uno::XInterface >()); + + CacheItemList::const_iterator pItem = rCache.find(item); + impl_saveItem(xItem, eType, pItem->second); + } + break; + default: break; + } + } +} + + +void FilterCache::detectFlatForURL(const css::util::URL& aURL , + FlatDetection& rFlatTypes) const +{ + // extract extension from URL, so it can be used directly as key into our hash map! + // Note further: It must be converted to lower case, because the optimize hash + // (which maps extensions to types) work with lower case key strings! + INetURLObject aParser (aURL.Main); + OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT , + true , + INetURLObject::DecodeMechanism::WithCharset); + sExtension = sExtension.toAsciiLowerCase(); + + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + + // i) Step over all well known URL pattern + // and add registered types to the return list too + // Do it as first one - because: if a type match by a + // pattern a following deep detection can be suppressed! + // Further we can stop after first match ... + for (auto const& pattern : m_lURLPattern2Types) + { + WildCard aPatternCheck(pattern.first); + if (aPatternCheck.Matches(aURL.Main)) + { + const std::vector& rTypesForPattern = pattern.second; + + FlatDetectionInfo aInfo; + aInfo.sType = *(rTypesForPattern.begin()); + aInfo.bMatchByPattern = true; + + rFlatTypes.push_back(aInfo); +// return; + } + } + + + // ii) search types matching to the given extension. + // Copy every matching type without changing its order! + // Because preferred types was added as first one during + // loading configuration. + CacheItemRegistration::const_iterator pExtReg = m_lExtensions2Types.find(sExtension); + if (pExtReg != m_lExtensions2Types.end()) + { + const std::vector& rTypesForExtension = pExtReg->second; + for (auto const& elem : rTypesForExtension) + { + FlatDetectionInfo aInfo; + aInfo.sType = elem; + aInfo.bMatchByExtension = true; + + rFlatTypes.push_back(aInfo); + } + } + + // <- SAFE ---------------------------------- +} + +const CacheItemList& FilterCache::impl_getItemList(EItemType eType) const +{ + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + switch(eType) + { + case E_TYPE : return m_lTypes ; + case E_FILTER : return m_lFilters ; + case E_FRAMELOADER : return m_lFrameLoaders ; + case E_CONTENTHANDLER : return m_lContentHandlers; + + } + + throw css::uno::RuntimeException("unknown sub container requested.", + css::uno::Reference< css::uno::XInterface >()); + // <- SAFE ---------------------------------- +} + +CacheItemList& FilterCache::impl_getItemList(EItemType eType) +{ + // SAFE -> ---------------------------------- + osl::MutexGuard aLock(m_aMutex); + + switch(eType) + { + case E_TYPE : return m_lTypes ; + case E_FILTER : return m_lFilters ; + case E_FRAMELOADER : return m_lFrameLoaders ; + case E_CONTENTHANDLER : return m_lContentHandlers; + + } + + throw css::uno::RuntimeException("unknown sub container requested.", + css::uno::Reference< css::uno::XInterface >()); + // <- SAFE ---------------------------------- +} + +css::uno::Reference< css::uno::XInterface > FilterCache::impl_openConfig(EConfigProvider eProvider) +{ + osl::MutexGuard aLock(m_aMutex); + + OUString sPath ; + css::uno::Reference< css::uno::XInterface >* pConfig = nullptr; + css::uno::Reference< css::uno::XInterface > xOld ; + OString sRtlLog ; + + switch(eProvider) + { + case E_PROVIDER_TYPES : + { + if (m_xConfigTypes.is()) + return m_xConfigTypes; + sPath = CFGPACKAGE_TD_TYPES; + pConfig = &m_xConfigTypes; + sRtlLog = "impl_openconfig(E_PROVIDER_TYPES)"; + } + break; + + case E_PROVIDER_FILTERS : + { + if (m_xConfigFilters.is()) + return m_xConfigFilters; + sPath = CFGPACKAGE_TD_FILTERS; + pConfig = &m_xConfigFilters; + sRtlLog = "impl_openconfig(E_PROVIDER_FILTERS)"; + } + break; + + case E_PROVIDER_OTHERS : + { + if (m_xConfigOthers.is()) + return m_xConfigOthers; + sPath = CFGPACKAGE_TD_OTHERS; + pConfig = &m_xConfigOthers; + sRtlLog = "impl_openconfig(E_PROVIDER_OTHERS)"; + } + break; + + case E_PROVIDER_OLD : + { + // This special provider is used to work with + // the old configuration format only. It's not cached! + sPath = CFGPACKAGE_TD_OLD; + pConfig = &xOld; + sRtlLog = "impl_openconfig(E_PROVIDER_OLD)"; + } + break; + + default : throw css::uno::RuntimeException("These configuration node is not supported here for open!", nullptr); + } + + { + SAL_INFO( "filter.config", "" << sRtlLog); + *pConfig = impl_createConfigAccess(sPath , + false, // bReadOnly + true ); // bLocalesMode + } + + + // Start listening for changes on that configuration access. + switch(eProvider) + { + case E_PROVIDER_TYPES: + { + m_xTypesChglisteners.set(new CacheUpdateListener(*this, *pConfig, FilterCache::E_TYPE)); + m_xTypesChglisteners->startListening(); + } + break; + case E_PROVIDER_FILTERS: + { + m_xFiltersChgListener.set(new CacheUpdateListener(*this, *pConfig, FilterCache::E_FILTER)); + m_xFiltersChgListener->startListening(); + } + break; + default: + break; + } + + return *pConfig; +} + +css::uno::Any FilterCache::impl_getDirectCFGValue(const OUString& sDirectKey) +{ + OUString sRoot; + OUString sKey ; + + if ( + (!::utl::splitLastFromConfigurationPath(sDirectKey, sRoot, sKey)) || + (sRoot.isEmpty() ) || + (sKey.isEmpty() ) + ) + return css::uno::Any(); + + css::uno::Reference< css::uno::XInterface > xCfg = impl_createConfigAccess(sRoot , + true , // bReadOnly + false); // bLocalesMode + if (!xCfg.is()) + return css::uno::Any(); + + css::uno::Reference< css::container::XNameAccess > xAccess(xCfg, css::uno::UNO_QUERY); + if (!xAccess.is()) + return css::uno::Any(); + + css::uno::Any aValue; + try + { + aValue = xAccess->getByName(sKey); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION( "filter.config", ""); + aValue.clear(); + } + + return aValue; +} + + +css::uno::Reference< css::uno::XInterface > FilterCache::impl_createConfigAccess(const OUString& sRoot , + bool bReadOnly , + bool bLocalesMode) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + css::uno::Reference< css::uno::XInterface > xCfg; + + if (!utl::ConfigManager::IsFuzzing()) + { + try + { + css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get( comphelper::getProcessComponentContext() ) ); + + ::std::vector< css::uno::Any > lParams; + css::beans::NamedValue aParam; + + // set root path + aParam.Name = "nodepath"; + aParam.Value <<= sRoot; + lParams.push_back(css::uno::Any(aParam)); + + // enable "all locales mode" ... if required + if (bLocalesMode) + { + aParam.Name = "locale"; + aParam.Value <<= OUString("*"); + lParams.push_back(css::uno::Any(aParam)); + } + + // open it + if (bReadOnly) + xCfg = xConfigProvider->createInstanceWithArguments(SERVICE_CONFIGURATIONACCESS, + comphelper::containerToSequence(lParams)); + else + xCfg = xConfigProvider->createInstanceWithArguments(SERVICE_CONFIGURATIONUPDATEACCESS, + comphelper::containerToSequence(lParams)); + + // If configuration could not be opened... but factory method did not throw an exception + // trigger throwing of our own CorruptedFilterConfigurationException. + // Let message empty. The normal exception text show enough information to the user. + if (! xCfg.is()) + throw css::uno::Exception( + "Got NULL reference on opening configuration file ... but no exception.", + css::uno::Reference< css::uno::XInterface >()); + } + catch(const css::uno::Exception& ex) + { + throw css::document::CorruptedFilterConfigurationException( + "filter configuration, caught: " + ex.Message, + css::uno::Reference< css::uno::XInterface >(), + ex.Message); + } + } + + return xCfg; + // <- SAFE +} + + +void FilterCache::impl_validateAndOptimize() +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // First check if any filter or type could be read + // from the underlying configuration! + bool bSomeTypesShouldExist = ((m_eFillState & E_CONTAINS_STANDARD ) == E_CONTAINS_STANDARD ); + bool bAllFiltersShouldExist = ((m_eFillState & E_CONTAINS_FILTERS ) == E_CONTAINS_FILTERS ); + +#if OSL_DEBUG_LEVEL > 0 + + sal_Int32 nWarnings = 0; + +// sal_Bool bAllTypesShouldExist = ((m_eFillState & E_CONTAINS_TYPES ) == E_CONTAINS_TYPES ); + bool bAllLoadersShouldExist = ((m_eFillState & E_CONTAINS_FRAMELOADERS ) == E_CONTAINS_FRAMELOADERS ); + bool bAllHandlersShouldExist = ((m_eFillState & E_CONTAINS_CONTENTHANDLERS) == E_CONTAINS_CONTENTHANDLERS); +#endif + + if ( + ( + bSomeTypesShouldExist && m_lTypes.empty() + ) || + ( + bAllFiltersShouldExist && m_lFilters.empty() + ) + ) + { + throw css::document::CorruptedFilterConfigurationException( + "filter configuration: the list of types or filters is empty", + css::uno::Reference< css::uno::XInterface >(), + "The list of types or filters is empty." ); + } + + // Create a log for all detected problems, which + // occur in the next few lines. + // If there are some real errors throw a RuntimException! + // If there are some warnings only, show an assertion. + sal_Int32 nErrors = 0; + OUStringBuffer sLog(256); + + for (auto const& elem : m_lTypes) + { + const OUString & sType = elem.first; + const CacheItem & aType = elem.second; + + // get its registration for file Extensions AND(!) URLPattern ... + // It doesn't matter if these items exists or if our + // used index access create some default ones ... + // only in case there is no filled set of Extensions AND + // no filled set of URLPattern -> we must try to remove this invalid item + // from this cache! + css::uno::Sequence< OUString > lExtensions; + css::uno::Sequence< OUString > lURLPattern; + auto it = aType.find(PROPNAME_EXTENSIONS); + if (it != aType.end()) + it->second >>= lExtensions; + it = aType.find(PROPNAME_URLPATTERN); + if (it != aType.end()) + it->second >>= lURLPattern; + sal_Int32 ce = lExtensions.getLength(); + sal_Int32 cu = lURLPattern.getLength(); + +#if OSL_DEBUG_LEVEL > 0 + + OUString sInternalTypeNameCheck; + it = aType.find(PROPNAME_NAME); + if (it != aType.end()) + it->second >>= sInternalTypeNameCheck; + if (sInternalTypeNameCheck != sType) + { + sLog.append("Warning\t:\t" "The type \"" + sType + "\" does support the property \"Name\" correctly.\n"); + ++nWarnings; + } + + if (!ce && !cu) + { + sLog.append("Warning\t:\t" "The type \"" + sType + "\" does not contain any URL pattern nor any extensions.\n"); + ++nWarnings; + } +#endif + + // create an optimized registration for this type to + // its set list of extensions/url pattern. If it's a "normal" type + // set it at the end of this optimized list. But if it's + // a "Preferred" one - set it to the front of this list. + // Of course multiple "Preferred" registrations can occur + // (they shouldn't - but they can!) ... Ignore it. The last + // preferred type is usable in the same manner then every + // other type! + bool bPreferred = false; + it = aType.find(PROPNAME_PREFERRED); + if (it != aType.end()) + it->second >>= bPreferred; + + const OUString* pExtensions = lExtensions.getConstArray(); + for (sal_Int32 e=0; e& lTypesForExtension = m_lExtensions2Types[sNormalizedExtension]; + if (::std::find(lTypesForExtension.begin(), lTypesForExtension.end(), sType) != lTypesForExtension.end()) + continue; + + if (bPreferred) + lTypesForExtension.insert(lTypesForExtension.begin(), sType); + else + lTypesForExtension.push_back(sType); + } + + const OUString* pURLPattern = lURLPattern.getConstArray(); + for (sal_Int32 u=0; u& lTypesForURLPattern = m_lURLPattern2Types[pURLPattern[u]]; + if (::std::find(lTypesForURLPattern.begin(), lTypesForURLPattern.end(), sType) != lTypesForURLPattern.end()) + continue; + + if (bPreferred) + lTypesForURLPattern.insert(lTypesForURLPattern.begin(), sType); + else + lTypesForURLPattern.push_back(sType); + } + +#if OSL_DEBUG_LEVEL > 0 + + // Don't check cross references between types and filters, if + // not all filters read from disk! + // OK - this cache can read single filters on demand too ... + // but then the fill state of this cache should not be set to E_CONTAINS_FILTERS! + if (!bAllFiltersShouldExist) + continue; + + OUString sPrefFilter; + it = aType.find(PROPNAME_PREFERREDFILTER); + if (it != aType.end()) + it->second >>= sPrefFilter; + if (sPrefFilter.isEmpty()) + { + // OK - there is no filter for this type. But that's not an error. + // Maybe it can be handled by a ContentHandler... + // But at this time it's not guaranteed that there is any ContentHandler + // or FrameLoader inside this cache... but on disk... + bool bReferencedByLoader = true; + bool bReferencedByHandler = true; + if (bAllLoadersShouldExist) + bReferencedByLoader = !impl_searchFrameLoaderForType(sType).isEmpty(); + + if (bAllHandlersShouldExist) + bReferencedByHandler = !impl_searchContentHandlerForType(sType).isEmpty(); + + if ( + (!bReferencedByLoader ) && + (!bReferencedByHandler) + ) + { + sLog.append("Warning\t:\t" "The type \"" + sType + "\" is not used by any filter, loader or content handler.\n"); + ++nWarnings; + } + } + + if (!sPrefFilter.isEmpty()) + { + CacheItemList::const_iterator pIt2 = m_lFilters.find(sPrefFilter); + if (pIt2 == m_lFilters.end()) + { + if (bAllFiltersShouldExist) + { + ++nWarnings; // preferred filters can point to a non-installed office module ! no error ... it's a warning only .-( + sLog.append("error\t:\t"); + } + else + { + ++nWarnings; + sLog.append("warning\t:\t"); + } + + sLog.append("The type \"" + sType + "\" points to an invalid filter \"" + sPrefFilter + "\".\n"); + continue; + } + + CacheItem aPrefFilter = pIt2->second; + OUString sFilterTypeReg; + aPrefFilter[PROPNAME_TYPE] >>= sFilterTypeReg; + if (sFilterTypeReg != sType) + { + sLog.append("error\t:\t" "The preferred filter \"" + + sPrefFilter + "\" of type \"" + sType + + "\" is registered for another type \"" + sFilterTypeReg + + "\".\n"); + ++nErrors; + } + + sal_Int32 nFlags = 0; + aPrefFilter[PROPNAME_FLAGS] >>= nFlags; + if (!(static_cast(nFlags) & SfxFilterFlags::IMPORT)) + { + sLog.append("error\t:\t" "The preferred filter \"" + sPrefFilter + "\" of type \"" + + sType + "\" is not an IMPORT filter!\n"); + ++nErrors; + } + + OUString sInternalFilterNameCheck; + aPrefFilter[PROPNAME_NAME] >>= sInternalFilterNameCheck; + if (sInternalFilterNameCheck != sPrefFilter) + { + sLog.append("Warning\t:\t" "The filter \"" + sPrefFilter + + "\" does support the property \"Name\" correctly.\n"); + ++nWarnings; + } + } +#endif + } + + // create dependencies between the global default frame loader + // and all types (and of course if registered filters), which + // does not registered for any other loader. + css::uno::Any aDirectValue = impl_getDirectCFGValue(CFGDIRECTKEY_DEFAULTFRAMELOADER); + OUString sDefaultFrameLoader; + + if ( + (!(aDirectValue >>= sDefaultFrameLoader)) || + (sDefaultFrameLoader.isEmpty() ) + ) + { + sLog.append("error\t:\t" "There is no valid default frame loader!?\n"); + ++nErrors; + } + + // a) get list of all well known types + // b) step over all well known frame loader services + // and remove all types from list a), which already + // referenced by a loader b) + std::vector lTypes = getItemNames(E_TYPE); + for (auto & frameLoader : m_lFrameLoaders) + { + // Note: of course the default loader must be ignored here. + // Because we replace its registration later completely with all + // types, which are not referenced by any other loader. + // So we can avoid our code against the complexity of a diff! + OUString sLoader = frameLoader.first; + if (sLoader == sDefaultFrameLoader) + continue; + + CacheItem& rLoader = frameLoader.second; + css::uno::Any& rTypesReg = rLoader[PROPNAME_TYPES]; + const css::uno::Sequence lTypesReg = rTypesReg.get >(); + + for (auto const& typeReg : lTypesReg) + { + auto pTypeCheck = ::std::find(lTypes.begin(), lTypes.end(), typeReg); + if (pTypeCheck != lTypes.end()) + lTypes.erase(pTypeCheck); + } + } + + CacheItem& rDefaultLoader = m_lFrameLoaders[sDefaultFrameLoader]; + rDefaultLoader[PROPNAME_NAME ] <<= sDefaultFrameLoader; + rDefaultLoader[PROPNAME_TYPES] <<= comphelper::containerToSequence(lTypes); + + OUString sLogOut = sLog.makeStringAndClear(); + OSL_ENSURE(!nErrors, OUStringToOString(sLogOut,RTL_TEXTENCODING_UTF8).getStr()); + if (nErrors>0) + throw css::document::CorruptedFilterConfigurationException( + "filter configuration: " + sLogOut, + css::uno::Reference< css::uno::XInterface >(), + sLogOut); +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE(!nWarnings, OUStringToOString(sLogOut,RTL_TEXTENCODING_UTF8).getStr()); +#endif + + // <- SAFE +} + +void FilterCache::impl_addItem2FlushList( EItemType eType, + const OUString& sItem) +{ + std::vector* pList = nullptr; + switch(eType) + { + case E_TYPE : + pList = &m_lChangedTypes; + break; + + case E_FILTER : + pList = &m_lChangedFilters; + break; + + case E_FRAMELOADER : + pList = &m_lChangedFrameLoaders; + break; + + case E_CONTENTHANDLER : + pList = &m_lChangedContentHandlers; + break; + + default : throw css::uno::RuntimeException("unsupported item type", nullptr); + } + + auto pItem = ::std::find(pList->cbegin(), pList->cend(), sItem); + if (pItem == pList->cend()) + pList->push_back(sItem); +} + +FilterCache::EItemFlushState FilterCache::impl_specifyFlushOperation(const css::uno::Reference< css::container::XNameAccess >& xSet , + const CacheItemList& rList, + const OUString& sItem) +{ + bool bExistsInConfigLayer = xSet->hasByName(sItem); + bool bExistsInMemory = (rList.find(sItem) != rList.end()); + + EItemFlushState eState( E_ITEM_UNCHANGED ); + + // !? ... such situation can occur, if an item was added and(!) removed before it was flushed :-) + if (!bExistsInConfigLayer && !bExistsInMemory) + eState = E_ITEM_UNCHANGED; + else if (!bExistsInConfigLayer && bExistsInMemory) + eState = E_ITEM_ADDED; + else if (bExistsInConfigLayer && bExistsInMemory) + eState = E_ITEM_CHANGED; + else if (bExistsInConfigLayer && !bExistsInMemory) + eState = E_ITEM_REMOVED; + + return eState; +} + +void FilterCache::impl_load(EFillState eRequiredState) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + // Attention: Detect services are part of the standard set! + // So there is no need to handle it separately. + + + // a) The standard set of config value is needed. + if ( + ((eRequiredState & E_CONTAINS_STANDARD) == E_CONTAINS_STANDARD) && + ((m_eFillState & E_CONTAINS_STANDARD) != E_CONTAINS_STANDARD) + ) + { + // Attention! If config couldn't be opened successfully + // and exception is thrown automatically and must be forwarded + // to our caller... + css::uno::Reference< css::container::XNameAccess > xTypes(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW); + { + SAL_INFO( "filter.config", "FilterCache::load std"); + impl_loadSet(xTypes, E_TYPE, E_READ_STANDARD, &m_lTypes); + } + } + + + // b) We need all type information ... + if ( + ((eRequiredState & E_CONTAINS_TYPES) == E_CONTAINS_TYPES) && + ((m_eFillState & E_CONTAINS_TYPES) != E_CONTAINS_TYPES) + ) + { + // Attention! If config couldn't be opened successfully + // and exception is thrown automatically and must be forwarded + // to our call... + css::uno::Reference< css::container::XNameAccess > xTypes(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW); + { + SAL_INFO( "filter.config", "FilterCache::load all types"); + impl_loadSet(xTypes, E_TYPE, E_READ_UPDATE, &m_lTypes); + } + } + + + // c) We need all filter information ... + if ( + ((eRequiredState & E_CONTAINS_FILTERS) == E_CONTAINS_FILTERS) && + ((m_eFillState & E_CONTAINS_FILTERS) != E_CONTAINS_FILTERS) + ) + { + // Attention! If config couldn't be opened successfully + // and exception is thrown automatically and must be forwarded + // to our call... + css::uno::Reference< css::container::XNameAccess > xFilters(impl_openConfig(E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW); + { + SAL_INFO( "filter.config", "FilterCache::load all filters"); + impl_loadSet(xFilters, E_FILTER, E_READ_ALL, &m_lFilters); + } + } + + + // c) We need all frame loader information ... + if ( + ((eRequiredState & E_CONTAINS_FRAMELOADERS) == E_CONTAINS_FRAMELOADERS) && + ((m_eFillState & E_CONTAINS_FRAMELOADERS) != E_CONTAINS_FRAMELOADERS) + ) + { + // Attention! If config couldn't be opened successfully + // and exception is thrown automatically and must be forwarded + // to our call... + css::uno::Reference< css::container::XNameAccess > xLoaders(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW); + { + SAL_INFO( "filter.config", "FilterCache::load all frame loader"); + impl_loadSet(xLoaders, E_FRAMELOADER, E_READ_ALL, &m_lFrameLoaders); + } + } + + + // d) We need all content handler information... + if ( + ((eRequiredState & E_CONTAINS_CONTENTHANDLERS) == E_CONTAINS_CONTENTHANDLERS) && + ((m_eFillState & E_CONTAINS_CONTENTHANDLERS) != E_CONTAINS_CONTENTHANDLERS) + ) + { + // Attention! If config couldn't be opened successfully + // and exception is thrown automatically and must be forwarded + // to our call... + css::uno::Reference< css::container::XNameAccess > xHandlers(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW); + { + SAL_INFO( "filter.config", "FilterCache::load all content handler"); + impl_loadSet(xHandlers, E_CONTENTHANDLER, E_READ_ALL, &m_lContentHandlers); + } + } + + // update fill state. Note: it's a bit field, which combines different parts. + m_eFillState = static_cast(static_cast(m_eFillState) | static_cast(eRequiredState)); + + // any data read? + // yes! => validate it and update optimized structures. + impl_validateAndOptimize(); + + // <- SAFE +} + +void FilterCache::impl_loadSet(const css::uno::Reference< css::container::XNameAccess >& xConfig, + EItemType eType , + EReadOption eOption, + CacheItemList* pCache ) +{ + // get access to the right configuration set + OUString sSetName; + switch(eType) + { + case E_TYPE : + sSetName = CFGSET_TYPES; + break; + + case E_FILTER : + sSetName = CFGSET_FILTERS; + break; + + case E_FRAMELOADER : + sSetName = CFGSET_FRAMELOADERS; + break; + + case E_CONTENTHANDLER : + sSetName = CFGSET_CONTENTHANDLERS; + break; + default: break; + } + + css::uno::Reference< css::container::XNameAccess > xSet; + css::uno::Sequence< OUString > lItems; + + try + { + css::uno::Any aVal = xConfig->getByName(sSetName); + if (!(aVal >>= xSet) || !xSet.is()) + { + OUString sMsg("Could not open configuration set \"" + sSetName + "\"."); + throw css::uno::Exception(sMsg, css::uno::Reference< css::uno::XInterface >()); + } + lItems = xSet->getElementNames(); + } + catch(const css::uno::Exception& ex) + { + throw css::document::CorruptedFilterConfigurationException( + "filter configuration, caught: " + ex.Message, + css::uno::Reference< css::uno::XInterface >(), + ex.Message); + } + + // get names of all existing sub items of this set + // step over it and fill internal cache structures. + + // But don't update optimized structures like e.g. hash + // for mapping extensions to its types! + + const OUString* pItems = lItems.getConstArray(); + sal_Int32 c = lItems.getLength(); + for (sal_Int32 i=0; ifind(pItems[i]); + switch(eOption) + { + // a) read a standard set of properties only or read all + case E_READ_STANDARD : + case E_READ_ALL : + { + try + { + (*pCache)[pItems[i]] = impl_loadItem(xSet, eType, pItems[i], eOption); + } + catch(const css::uno::Exception& ex) + { + throw css::document::CorruptedFilterConfigurationException( + "filter configuration, caught: " + ex.Message, + css::uno::Reference< css::uno::XInterface >(), + ex.Message); + } + } + break; + + // b) read optional properties only! + // All items must already exist inside our cache. + // But they must be updated. + case E_READ_UPDATE : + { + if (pItem == pCache->end()) + { + OUString sMsg("item \"" + pItems[i] + "\" not found for update!"); + throw css::uno::Exception(sMsg, css::uno::Reference< css::uno::XInterface >()); + } + try + { + CacheItem aItem = impl_loadItem(xSet, eType, pItems[i], eOption); + pItem->second.update(aItem); + } + catch(const css::uno::Exception& ex) + { + throw css::document::CorruptedFilterConfigurationException( + "filter configuration, caught: " + ex.Message, + css::uno::Reference< css::uno::XInterface >(), + ex.Message); + } + } + break; + default: break; + } + } +} + +void FilterCache::impl_readPatchUINames(const css::uno::Reference< css::container::XNameAccess >& xNode, + CacheItem& rItem) +{ + + // SAFE -> ---------------------------------- + osl::ClearableMutexGuard aLock(m_aMutex); + OUString sActLocale = m_sActLocale ; + aLock.clear(); + // <- SAFE ---------------------------------- + + css::uno::Any aVal = xNode->getByName(PROPNAME_UINAME); + css::uno::Reference< css::container::XNameAccess > xUIName; + if (!(aVal >>= xUIName) && !xUIName.is()) + return; + + const ::std::vector< OUString > lLocales(comphelper::sequenceToContainer< ::std::vector< OUString >>( + xUIName->getElementNames())); + ::std::vector< OUString >::const_iterator pLocale ; + ::comphelper::SequenceAsHashMap lUINames; + + for (auto const& locale : lLocales) + { + OUString sValue; + xUIName->getByName(locale) >>= sValue; + + lUINames[locale] <<= sValue; + } + + aVal <<= lUINames.getAsConstPropertyValueList(); + rItem[PROPNAME_UINAMES] = aVal; + + // find right UIName for current office locale + // Use fallbacks too! + pLocale = LanguageTag::getFallback(lLocales, sActLocale); + if (pLocale == lLocales.end()) + { +#if OSL_DEBUG_LEVEL > 0 + if ( sActLocale == "en-US" ) + return; + OUString sName = rItem.getUnpackedValueOrDefault(PROPNAME_NAME, OUString()); + + SAL_WARN("filter.config", "Fallback scenario for filter or type '" << sName << "' and locale '" << + sActLocale << "' failed. Please check your filter configuration."); +#endif + return; + } + + const OUString& sLocale = *pLocale; + ::comphelper::SequenceAsHashMap::const_iterator pUIName = lUINames.find(sLocale); + if (pUIName != lUINames.end()) + rItem[PROPNAME_UINAME] = pUIName->second; +} + +void FilterCache::impl_savePatchUINames(const css::uno::Reference< css::container::XNameReplace >& xNode, + const CacheItem& rItem) +{ + css::uno::Reference< css::container::XNameContainer > xAdd (xNode, css::uno::UNO_QUERY); + + css::uno::Sequence< css::beans::PropertyValue > lUINames = rItem.getUnpackedValueOrDefault(PROPNAME_UINAMES, css::uno::Sequence< css::beans::PropertyValue >()); + sal_Int32 c = lUINames.getLength(); + const css::beans::PropertyValue* pUINames = lUINames.getConstArray(); + + for (sal_Int32 i=0; ihasByName(pUINames[i].Name)) + xNode->replaceByName(pUINames[i].Name, pUINames[i].Value); + else + xAdd->insertByName(pUINames[i].Name, pUINames[i].Value); + } +} + +/*----------------------------------------------- + TODO + clarify, how the real problem behind the + wrong constructed CacheItem instance (which + will force a crash during destruction) + can be solved ... +-----------------------------------------------*/ +CacheItem FilterCache::impl_loadItem(const css::uno::Reference< css::container::XNameAccess >& xSet , + EItemType eType , + const OUString& sItem , + EReadOption eOption) +{ + // try to get an API object, which points directly to the + // requested item. If it fail an exception should occur and + // break this operation. Of course returned API object must be + // checked too. + css::uno::Reference< css::container::XNameAccess > xItem; + css::uno::Any aVal = xSet->getByName(sItem); + if (!(aVal >>= xItem) || !xItem.is()) + { + throw css::uno::RuntimeException("found corrupted item \"" + sItem + "\".", + css::uno::Reference< css::uno::XInterface >()); + } + + // set too. Of course it's already used as key into the e.g. outside + // used hash map... but some of our API methods provide + // this property set as result only. But the user of this CacheItem + // should know, which value the key names has :-) IT'S IMPORTANT! + CacheItem aItem; + aItem[PROPNAME_NAME] <<= sItem; + switch(eType) + { + case E_TYPE : + { + assert(eOption >= 0 && eOption <= E_READ_ALL); + css::uno::Sequence< OUString > &rNames = m_aTypeProps[eOption]; + + // read standard properties of a filter + if (rNames.hasElements()) + { + css::uno::Reference< css::beans::XMultiPropertySet > + xPropSet( xItem, css::uno::UNO_QUERY_THROW); + css::uno::Sequence< css::uno::Any > aValues = xPropSet->getPropertyValues(rNames); + + for (sal_Int32 i = 0; i < aValues.getLength(); i++) + aItem[rNames[i]] = aValues[i]; + } + + // read optional properties of a type + // no else here! Is an additional switch ... + if (eOption == E_READ_UPDATE || eOption == E_READ_ALL) + impl_readPatchUINames(xItem, aItem); + } + break; + + + case E_FILTER : + { + assert(eOption >= 0 && eOption <= E_READ_ALL); + css::uno::Sequence< OUString > &rNames = m_aStandardProps[eOption]; + + // read standard properties of a filter + if (rNames.hasElements()) + { + css::uno::Reference< css::beans::XMultiPropertySet > + xPropSet( xItem, css::uno::UNO_QUERY_THROW); + css::uno::Sequence< css::uno::Any > aValues = xPropSet->getPropertyValues(rNames); + + for (sal_Int32 i = 0; i < rNames.getLength(); i++) + { + const OUString &rPropName = rNames[i]; + if (i != rNames.getLength() - 1 || rPropName != PROPNAME_FLAGS) + aItem[rPropName] = aValues[i]; + else + { + assert(rPropName == PROPNAME_FLAGS); + // special handling for flags! Convert it from a list of names to its + // int representation ... + css::uno::Sequence< OUString > lFlagNames; + if (aValues[i] >>= lFlagNames) + aItem[rPropName] <<= static_cast(FilterCache::impl_convertFlagNames2FlagField(lFlagNames)); + } + } + } +//TODO remove it if moving of filter uinames to type uinames +// will be finished really +#ifdef AS_ENABLE_FILTER_UINAMES + if (eOption == E_READ_UPDATE || eOption == E_READ_ALL) + impl_readPatchUINames(xItem, aItem); +#endif // AS_ENABLE_FILTER_UINAMES + } + break; + + case E_FRAMELOADER : + case E_CONTENTHANDLER : + aItem[PROPNAME_TYPES] = xItem->getByName(PROPNAME_TYPES); + break; + default: break; + } + + return aItem; +} + +CacheItemList::iterator FilterCache::impl_loadItemOnDemand( EItemType eType, + const OUString& sItem) +{ + CacheItemList* pList = nullptr; + css::uno::Reference< css::uno::XInterface > xConfig ; + OUString sSet ; + + switch(eType) + { + case E_TYPE : + { + pList = &m_lTypes; + xConfig = impl_openConfig(E_PROVIDER_TYPES); + sSet = CFGSET_TYPES; + } + break; + + case E_FILTER : + { + pList = &m_lFilters; + xConfig = impl_openConfig(E_PROVIDER_FILTERS); + sSet = CFGSET_FILTERS; + } + break; + + case E_FRAMELOADER : + { + pList = &m_lFrameLoaders; + xConfig = impl_openConfig(E_PROVIDER_OTHERS); + sSet = CFGSET_FRAMELOADERS; + } + break; + + case E_CONTENTHANDLER : + { + pList = &m_lContentHandlers; + xConfig = impl_openConfig(E_PROVIDER_OTHERS); + sSet = CFGSET_CONTENTHANDLERS; + } + break; + } + + if (!pList) + throw css::container::NoSuchElementException(); + + css::uno::Reference< css::container::XNameAccess > xRoot(xConfig, css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::container::XNameAccess > xSet ; + xRoot->getByName(sSet) >>= xSet; + + CacheItemList::iterator pItemInCache = pList->find(sItem); + bool bItemInConfig = xSet->hasByName(sItem); + + if (bItemInConfig) + { + (*pList)[sItem] = impl_loadItem(xSet, eType, sItem, E_READ_ALL); + } + else + { + if (pItemInCache != pList->end()) + pList->erase(pItemInCache); + // OK - this item does not exists inside configuration. + // And we already updated our internal cache. + // But the outside code needs this NoSuchElementException + // to know, that this item does notexists. + // Nobody checks the iterator! + throw css::container::NoSuchElementException(); + } + + return pList->find(sItem); +} + +void FilterCache::impl_saveItem(const css::uno::Reference< css::container::XNameReplace >& xItem, + EItemType eType, + const CacheItem & aItem) +{ + // This function changes the properties of aItem one-by-one; but it also + // listens to the configuration changes and reloads the whole item from the + // configuration on change, so use a copy of aItem throughout: + CacheItem copiedItem(aItem); + + CacheItem::const_iterator pIt; + switch(eType) + { + + case E_TYPE : + { + pIt = copiedItem.find(PROPNAME_PREFERREDFILTER); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_PREFERREDFILTER, pIt->second); + pIt = copiedItem.find(PROPNAME_DETECTSERVICE); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_DETECTSERVICE, pIt->second); + pIt = copiedItem.find(PROPNAME_URLPATTERN); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_URLPATTERN, pIt->second); + pIt = copiedItem.find(PROPNAME_EXTENSIONS); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_EXTENSIONS, pIt->second); + pIt = copiedItem.find(PROPNAME_PREFERRED); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_PREFERRED, pIt->second); + pIt = copiedItem.find(PROPNAME_MEDIATYPE); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_MEDIATYPE, pIt->second); + pIt = copiedItem.find(PROPNAME_CLIPBOARDFORMAT); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_CLIPBOARDFORMAT, pIt->second); + + css::uno::Reference< css::container::XNameReplace > xUIName; + xItem->getByName(PROPNAME_UINAME) >>= xUIName; + impl_savePatchUINames(xUIName, copiedItem); + } + break; + + + case E_FILTER : + { + pIt = copiedItem.find(PROPNAME_TYPE); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_TYPE, pIt->second); + pIt = copiedItem.find(PROPNAME_FILEFORMATVERSION); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_FILEFORMATVERSION, pIt->second); + pIt = copiedItem.find(PROPNAME_UICOMPONENT); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_UICOMPONENT, pIt->second); + pIt = copiedItem.find(PROPNAME_FILTERSERVICE); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_FILTERSERVICE, pIt->second); + pIt = copiedItem.find(PROPNAME_DOCUMENTSERVICE); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_DOCUMENTSERVICE, pIt->second); + pIt = copiedItem.find(PROPNAME_USERDATA); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_USERDATA, pIt->second); + pIt = copiedItem.find(PROPNAME_TEMPLATENAME); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_TEMPLATENAME, pIt->second); + + // special handling for flags! Convert it from an integer flag field back + // to a list of names ... + pIt = copiedItem.find(PROPNAME_FLAGS); + if (pIt != copiedItem.end()) + { + sal_Int32 nFlags = 0; + pIt->second >>= nFlags; + css::uno::Any aFlagNameList; + aFlagNameList <<= FilterCache::impl_convertFlagField2FlagNames(static_cast(nFlags)); + xItem->replaceByName(PROPNAME_FLAGS, aFlagNameList); + } + +//TODO remove it if moving of filter uinames to type uinames +// will be finished really +#ifdef AS_ENABLE_FILTER_UINAMES + css::uno::Reference< css::container::XNameReplace > xUIName; + xItem->getByName(PROPNAME_UINAME) >>= xUIName; + impl_savePatchUINames(xUIName, copiedItem); +#endif // AS_ENABLE_FILTER_UINAMES + } + break; + + + case E_FRAMELOADER : + case E_CONTENTHANDLER : + { + pIt = copiedItem.find(PROPNAME_TYPES); + if (pIt != copiedItem.end()) + xItem->replaceByName(PROPNAME_TYPES, pIt->second); + } + break; + default: break; + } +} + +/*----------------------------------------------- + static! => no locks necessary +-----------------------------------------------*/ +css::uno::Sequence< OUString > FilterCache::impl_convertFlagField2FlagNames(SfxFilterFlags nFlags) +{ + std::vector lFlagNames; + + if (nFlags & SfxFilterFlags::STARONEFILTER ) lFlagNames.emplace_back(FLAGNAME_3RDPARTYFILTER ); + if (nFlags & SfxFilterFlags::ALIEN ) lFlagNames.emplace_back(FLAGNAME_ALIEN ); + if (nFlags & SfxFilterFlags::CONSULTSERVICE ) lFlagNames.emplace_back(FLAGNAME_CONSULTSERVICE ); + if (nFlags & SfxFilterFlags::DEFAULT ) lFlagNames.emplace_back(FLAGNAME_DEFAULT ); + if (nFlags & SfxFilterFlags::ENCRYPTION ) lFlagNames.emplace_back(FLAGNAME_ENCRYPTION ); + if (nFlags & SfxFilterFlags::EXPORT ) lFlagNames.emplace_back(FLAGNAME_EXPORT ); + if (nFlags & SfxFilterFlags::IMPORT ) lFlagNames.emplace_back(FLAGNAME_IMPORT ); + if (nFlags & SfxFilterFlags::INTERNAL ) lFlagNames.emplace_back(FLAGNAME_INTERNAL ); + if (nFlags & SfxFilterFlags::NOTINFILEDLG ) lFlagNames.emplace_back(FLAGNAME_NOTINFILEDIALOG ); + if (nFlags & SfxFilterFlags::MUSTINSTALL ) lFlagNames.emplace_back(FLAGNAME_NOTINSTALLED ); + if (nFlags & SfxFilterFlags::OWN ) lFlagNames.emplace_back(FLAGNAME_OWN ); + if (nFlags & SfxFilterFlags::PACKED ) lFlagNames.emplace_back(FLAGNAME_PACKED ); + if (nFlags & SfxFilterFlags::PASSWORDTOMODIFY ) lFlagNames.emplace_back(FLAGNAME_PASSWORDTOMODIFY ); + if (nFlags & SfxFilterFlags::PREFERED ) lFlagNames.emplace_back(FLAGNAME_PREFERRED ); + if (nFlags & SfxFilterFlags::STARTPRESENTATION) lFlagNames.emplace_back(FLAGNAME_STARTPRESENTATION); + if (nFlags & SfxFilterFlags::OPENREADONLY ) lFlagNames.emplace_back(FLAGNAME_READONLY ); + if (nFlags & SfxFilterFlags::SUPPORTSSELECTION) lFlagNames.emplace_back(FLAGNAME_SUPPORTSSELECTION); + if (nFlags & SfxFilterFlags::TEMPLATE ) lFlagNames.emplace_back(FLAGNAME_TEMPLATE ); + if (nFlags & SfxFilterFlags::TEMPLATEPATH ) lFlagNames.emplace_back(FLAGNAME_TEMPLATEPATH ); + if (nFlags & SfxFilterFlags::COMBINED ) lFlagNames.emplace_back(FLAGNAME_COMBINED ); + if (nFlags & SfxFilterFlags::SUPPORTSSIGNING) lFlagNames.emplace_back(FLAGNAME_SUPPORTSSIGNING); + if (nFlags & SfxFilterFlags::GPGENCRYPTION) lFlagNames.emplace_back(FLAGNAME_GPGENCRYPTION); + if (nFlags & SfxFilterFlags::EXOTIC) lFlagNames.emplace_back(FLAGNAME_EXOTIC); + + return comphelper::containerToSequence(lFlagNames); +} + +/*----------------------------------------------- + static! => no locks necessary +-----------------------------------------------*/ +SfxFilterFlags FilterCache::impl_convertFlagNames2FlagField(const css::uno::Sequence< OUString >& lNames) +{ + SfxFilterFlags nField = SfxFilterFlags::NONE; + + const OUString* pNames = lNames.getConstArray(); + sal_Int32 c = lNames.getLength(); + for (sal_Int32 i=0; i 0) + { + SAL_WARN( "filter.config", "FilterCache::impl_interpretDataVal4Filter()\nCan not move Order value from filter to type on demand!"); + } + } + break; + // Type + case 1: rItem[PROPNAME_TYPE] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8); + break; + // DocumentService + case 2: rItem[PROPNAME_DOCUMENTSERVICE] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8); + break; + // FilterService + case 3: rItem[PROPNAME_FILTERSERVICE] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8); + break; + // Flags + case 4: rItem[PROPNAME_FLAGS] <<= sValue.toInt32(); + break; + // UserData + case 5: rItem[PROPNAME_USERDATA] <<= comphelper::containerToSequence(impl_tokenizeString(sValue, ';')); + break; + // FileFormatVersion + case 6: rItem[PROPNAME_FILEFORMATVERSION] <<= sValue.toInt32(); + break; + // TemplateName + case 7: rItem[PROPNAME_TEMPLATENAME] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8); + break; + // [optional!] UIComponent + case 8: rItem[PROPNAME_UICOMPONENT] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8); + break; + } +} + +/*----------------------------------------------- + TODO work on a cache copy first, which can be flushed afterwards + That would be useful to guarantee a consistent cache. +-----------------------------------------------*/ +void FilterCache::impl_readOldFormat() +{ + // Attention: Opening/Reading of this old configuration format has to be handled gracefully. + // It's optional and should not disturb our normal work! + // E.g. we must check, if the package exists... + try + { + css::uno::Reference< css::uno::XInterface > xInt = impl_openConfig(E_PROVIDER_OLD); + css::uno::Reference< css::container::XNameAccess > xCfg(xInt, css::uno::UNO_QUERY_THROW); + + OUString TYPES_SET("Types"); + + // May be there is no type set ... + if (xCfg->hasByName(TYPES_SET)) + { + css::uno::Reference< css::container::XNameAccess > xSet; + xCfg->getByName(TYPES_SET) >>= xSet; + const css::uno::Sequence< OUString > lItems = xSet->getElementNames(); + for (const OUString& rName : lItems) + m_lTypes[rName] = impl_readOldItem(xSet, E_TYPE, rName); + } + + OUString FILTER_SET("Filters"); + // May be there is no filter set ... + if (xCfg->hasByName(FILTER_SET)) + { + css::uno::Reference< css::container::XNameAccess > xSet; + xCfg->getByName(FILTER_SET) >>= xSet; + const css::uno::Sequence< OUString > lItems = xSet->getElementNames(); + for (const OUString& rName : lItems) + m_lFilters[rName] = impl_readOldItem(xSet, E_FILTER, rName); + } + } + /* corrupt filter addon? Because it's external (optional) code... we can ignore it. Addon won't work then... + but that seems to be acceptable. + see #139088# for further information + */ + catch(const css::uno::Exception&) + { + } +} + +CacheItem FilterCache::impl_readOldItem(const css::uno::Reference< css::container::XNameAccess >& xSet , + EItemType eType, + const OUString& sItem) +{ + css::uno::Reference< css::container::XNameAccess > xItem; + xSet->getByName(sItem) >>= xItem; + if (!xItem.is()) + throw css::uno::Exception("Can not read old item.", css::uno::Reference< css::uno::XInterface >()); + + CacheItem aItem; + aItem[PROPNAME_NAME] <<= sItem; + + // Installed flag ... + // Isn't used any longer! + + // UIName + impl_readPatchUINames(xItem, aItem); + + // Data + OUString sData; + std::vector lData; + xItem->getByName( "Data" ) >>= sData; + lData = impl_tokenizeString(sData, ','); + if ( + (sData.isEmpty()) || + (lData.empty() ) + ) + { + throw css::uno::Exception( "Can not read old item property DATA.", css::uno::Reference< css::uno::XInterface >()); + } + + sal_Int32 nProp = 0; + for (auto const& prop : lData) + { + switch(eType) + { + case E_TYPE : + impl_interpretDataVal4Type(prop, nProp, aItem); + break; + + case E_FILTER : + impl_interpretDataVal4Filter(prop, nProp, aItem); + break; + default: break; + } + ++nProp; + } + + return aItem; +} + + +std::vector FilterCache::impl_tokenizeString(std::u16string_view sData , + sal_Unicode cSeparator) +{ + std::vector lData ; + sal_Int32 nToken = 0; + do + { + OUString sToken( o3tl::getToken(sData, 0, cSeparator, nToken) ); + lData.push_back(sToken); + } + while(nToken >= 0); + return lData; +} + +#if OSL_DEBUG_LEVEL > 0 + + +OUString FilterCache::impl_searchFrameLoaderForType(const OUString& sType) const +{ + for (auto const& frameLoader : m_lFrameLoaders) + { + const OUString& sItem = frameLoader.first; + ::comphelper::SequenceAsHashMap lProps(frameLoader.second); + const css::uno::Sequence lTypes = + lProps[PROPNAME_TYPES].get >(); + + if (::std::find(lTypes.begin(), lTypes.end(), sType) != lTypes.end()) + return sItem; + } + + return OUString(); +} + + +OUString FilterCache::impl_searchContentHandlerForType(const OUString& sType) const +{ + for (auto const& contentHandler : m_lContentHandlers) + { + const OUString& sItem = contentHandler.first; + ::comphelper::SequenceAsHashMap lProps(contentHandler.second); + const css::uno::Sequence lTypes = + lProps[PROPNAME_TYPES].get >(); + if (::std::find(lTypes.begin(), lTypes.end(), sType) != lTypes.end()) + return sItem; + } + + return OUString(); +} +#endif + + +bool FilterCache::impl_isModuleInstalled(const OUString& sModule) +{ + css::uno::Reference< css::container::XNameAccess > xCfg; + + // SAFE -> + { + osl::MutexGuard aLock(m_aMutex); + if (!m_xModuleCfg.is()) + { + m_xModuleCfg = officecfg::Setup::Office::Factories::get(); + } + + xCfg = m_xModuleCfg; + } + // <- SAFE + + if (xCfg.is()) + return xCfg->hasByName(sModule); + + return false; +} + +} // namespace filter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/filtercache.hxx b/filter/source/config/cache/filtercache.hxx new file mode 100644 index 000000000..2f647c33e --- /dev/null +++ b/filter/source/config/cache/filtercache.hxx @@ -0,0 +1,939 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include "cacheitem.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace filter::config { + +class CacheUpdateListener; + + +/** @short implements a cache, which contains all + elements of our filter and type detection + configuration. + + @descr The cache itself is threadsafe implemented. + Because it should be used as a singleton only. + To do so please use reference mechanism as wrapper + around this FilterCache class. + + @attention Because we use a trick to get a full initialized + mutex lock during initialization time (means during + the constructor runs), the base class FilterCacheLock + must be the first of all declared one! + Further we make it public. So any user of this class + can lock us from outside too. + */ +class FilterCache : public cppu::BaseMutex +{ + + // public types + + public: + + + /** @short identify the type of a container item. + + @descr Because the cache interface is a generic one + every group of container items must be specified. + */ + enum EItemType + { + E_TYPE , + E_FILTER , + E_FRAMELOADER , + E_CONTENTHANDLER + }; + + + /** @short indicates, which items already exists inside this cache + and which not. + + @descr This cache supports a 2-step load mechanism. + First only types (and only some special properties of every type!) + but no filters/frame loaders/content handlers will be read. + That should be enough to work with this cache e.g. for loading + the first document. After this first document was loaded successfully, + a special "load-on-demand-thread" will be started to fill this cache + with ALL other information, which was not read before. + That's the second step. All operations on top of this cache will be + blocked then. + */ + enum EFillState + { + E_CONTAINS_NOTHING = 0, + E_CONTAINS_STANDARD = 1, + E_CONTAINS_TYPES = 2, + E_CONTAINS_FILTERS = 4, + E_CONTAINS_FRAMELOADERS = 8, + E_CONTAINS_CONTENTHANDLERS = 16 + }; + + + // private types + + private: + + + /** @short regulate, which properties of a configured item + will be read. + + @descr To perform reading of all configuration items, + only standard properties will be handled. At a second + step all optional properties will be read and added to + our internal structures. Of course the combination of + both options can be used too, to get all properties + at the same time. + */ + enum EReadOption + { + E_READ_STANDARD = 1, + E_READ_UPDATE = 2, + E_READ_ALL = 3 + }; + + + /** @short indicates the state of a configuration set item. + + @descr Inside method flush we check: +

    +
  • if the item exists inside config layer but not inside our cache => REMOVED
  • +
  • if the item exists inside config layer and inside our cache => CHANGED
  • +
  • if the item does not exists inside config layer but inside our cache => ADDED.
  • +
+ */ + enum EItemFlushState + { + /// indicates an unchanged item (can occur e.g. if an item was added and(!) removed before it was flushed ... + E_ITEM_UNCHANGED = 0, + /// indicates an item, which exists inside config layer but not inside our own cache + E_ITEM_REMOVED = 1, + /// indicates an item, which exists inside config layer and inside our own cache + E_ITEM_CHANGED = 2, + /// indicates an item, which does not exists inside config layer but inside our own cache + E_ITEM_ADDED = 3 + }; + + + /** TODO document me */ + enum EConfigProvider + { + E_PROVIDER_TYPES = 0, + E_PROVIDER_FILTERS = 1, + E_PROVIDER_OTHERS = 2, + E_PROVIDER_OLD = 3 + }; + + + // member + + private: + + + /** @short holds the used configuration provider alive, which + provides access to the list of types. */ + mutable css::uno::Reference< css::uno::XInterface > m_xConfigTypes; + + + /** @short holds the used configuration provider alive, which + provides access to the list of filters. */ + mutable css::uno::Reference< css::uno::XInterface > m_xConfigFilters; + + + /** @short holds the used configuration provider alive, which + provides access to the list of other values needed + by our type detection framework. */ + mutable css::uno::Reference< css::uno::XInterface > m_xConfigOthers; + + + /** @short contains all loaded types with its properties. */ + mutable CacheItemList m_lTypes; + + + /** @short contains all loaded filters with its properties. */ + mutable CacheItemList m_lFilters; + + + /** @short contains all loaded frame loader with its properties. */ + mutable CacheItemList m_lFrameLoaders; + + + /** @short contains all loaded content handler with its properties. */ + mutable CacheItemList m_lContentHandlers; + + + /** @short optimize mapping of URL extensions to a type representation, + by using extensions as key and a list of internal + type names as value. */ + mutable CacheItemRegistration m_lExtensions2Types; + + + /** @short optimize mapping of URL pattern to a type representation, + by using patterns as key and a list of internal + type names as value. */ + mutable CacheItemRegistration m_lURLPattern2Types; + + + /** @short contains the current locale of the office and will be + used to work with localized configuration values. */ + OUString m_sActLocale; + + + /** @short contains status, which cache items/properties + was already loaded from the underlying configuration. + + @descr This information can be used to detect missing + information and load it on demand. + + @see EFillState + @see load() + */ + EFillState m_eFillState; + + + /** TODO document me ... */ + std::vector m_lChangedTypes; + std::vector m_lChangedFilters; + std::vector m_lChangedFrameLoaders; + std::vector m_lChangedContentHandlers; + + /// standard property names for filter config keyed by EReadOption + css::uno::Sequence< OUString > m_aStandardProps[4]; + + /// type property names for filter config keyed by EReadOption + css::uno::Sequence< OUString > m_aTypeProps[4]; + + /// readonly access to the module configuration of OOo + css::uno::Reference< css::container::XNameAccess > m_xModuleCfg; + + rtl::Reference< CacheUpdateListener > m_xTypesChglisteners; + rtl::Reference< CacheUpdateListener > m_xFiltersChgListener; + + + // interface + + public: + + + // ctor/dtor + + /** @short standard ctor + + @descr It's not allowed to do anything here... + especially is forbidden to start operations, + which needs a FilterCache instance too! + Why? Because this FilterCache instance will be + used as a singleton! And if during this ctor any + action related to this FilterCache singleton is + started... a race will be the result. + + The first method after construction of a new + singleton reference should be "load()". There + a special fill state of this cache can be forced. + */ + FilterCache(); + + + /** @short standard dtor. + */ + ~FilterCache(); + + + /** @short creates a copy of this container. + + @descr Such copy can be used then to modify items (add/change/remove) + without the risk to damage the original container. + After its changed data was flushed to the configuration it can be + removed. + + The original container will get these new data automatically + because it listen for changes on the internal used configuration layer. + If the new data are needed immediately inside the original container, + the method takeOver() can be used to copy all changes back. + The may be following notifications of the configuration will be superfluous then. + But they can't be stopped... + + All internal structures will be copied here. But the internal used + configuration (update) access won't be copied. The cloned instance contains + a different one. + */ + std::unique_ptr clone() const; + + + /** @short copy the cache content or rClone back to this instance. + */ + void takeOver(const FilterCache& rClone); + + + /** @short force special fill state of this cache. + + @descr This method checks, if all requested items/properties already + exist. Only missing information will be read. + Otherwise this method does nothing! + + This method must be called from every user of this cache + every time it needs a filled cache. Normally we load + only standard information into this cache on startup. + + @throw An exception if the cache could not be filled really + or seems to be invalid afterwards. But there is no reaction + at all if this method does nothing inside, because the cache + is already fully filled! + */ + void load(EFillState eRequired); + + + /** @short return the current fill state of this cache. + + @descr This information can be used e.g. to start + a search on top of this cache with a minimum on + information ... and do it again, if some other + cache items seems to be available after calling of "loadAll()" + on this cache and first search does not had any valid results. + + @return sal_True if the required fill state exists for this cache; FALSE + otherwise. + + @throws css::uno::Exception + */ + bool isFillState(EFillState eRequired) const; + + + /** @short return a list of key names for items, which match + the specified criteria. + + @descr The returned key names can be used at another method "getItem()" + of this cache to get further information about this item. + + @attention Please note: because this cache can be used inside multithreaded + environments, such returned key name can point to an already removed + item! Please be aware of some "NoSuchElementExceptions" if you try to + call any other method of this cache in relation to this key name. + + @param eType + specify the sub container of this cache, which should be used for + searching. see also EItemType. + + @param lIProps + specify the property set, which must exist at the searched items + as minimum. + + @param lEProps + specify the property set, which must not(!) exist at the searched items + as minimum. + + @return [std::vector] + a list of key names, which identify items of the queried sub container. + May be an empty list. + + @throw [css::uno::Exception] + if some input parameter are wrong or the cache itself is not valid + any longer, because any operation before damage it. + */ + std::vector getMatchingItemsByProps( EItemType eType, + o3tl::span< const css::beans::NamedValue > lIProps, + o3tl::span< const css::beans::NamedValue > lEProps = {}) const; + + + /** @short indicates if the requested sub container + contains some items. + + @descr We don't provide any information about the count + of such items. Because we don't implement any index + based interface! The information "we have items or not" + must be enough for the outside code ... till somewhere + give us a good reason. :-) + + @param eType + specify the sub container of this cache, which should be used. + see also EItemType. + + @return [sal_Bool] + True, if the requested sub container contains some items; + False otherwise. + + @throw [css::uno::Exception] + if some input parameter are wrong or the cache itself is not valid + any longer, because any operation before damage it. + */ + bool hasItems(EItemType eType) const; + + + /** @short return a list of all key names, which represent + an item inside the specified sub container. + + @attention Please note: because this cache can be used inside multithreaded + environments, such returned key names can point to some already removed + items! Please be aware of some "NoSuchElementExceptions" if you try to + call any other method of this cache in relation to this key names. + + @param eType + specify the sub container of this cache, which should be used for + searching. see also EItemType. + + @return [std::vector] + a list of key names, which can be used to access the item properties + using some other methods of this cache. + + @throw [css::uno::Exception] + if some input parameter are wrong or the cache itself is not valid + any longer, because any operation before damage it. + */ + std::vector getItemNames(EItemType eType) const; + + + /** @short check if the required item exist inside this container. + + @attention This method exists to supports some UNO container interfaces + only. (e.g. XNameAccess.hasByName()). But inside multithreaded + environments there is no guarantee, that this item still exists, if + it's really requested e.g. by calling getItem()! + Be aware of some NoSuchElementExistExceptions ... + + @param eType + specify the sub container of this cache, which should be used. + see also EItemType. + + @param sItem + the key name of the requested item inside the specified sub container. + + @throw [css::uno::Exception] + if some input parameter are wrong or the cache itself is not valid + any longer, because any operation before damage it. + */ + bool hasItem( EItemType eType, + const OUString& sItem); + + + /** @short return an item, which match the specified type and name. + + @descr Because this cache can be used inside multithreaded environments + the caller must be aware of some exceptions - especially a "NoSuchElementExcepotion". + May another thread already removed the required item before ... + + @param eType + specify the sub container of this cache, which should be used for + searching. see also EItemType. + + @param sItem + specify the requested item by its key name. + + @return [CacheItem] + the required item if it could be located ... + But we throw an exception if the required item does not exist! + + @throw [css::container::NoSuchElementException] + if the required item does not still exist. + + @throw [css::uno::Exception] + if some input parameter are wrong or the cache itself is not valid + any longer, because any operation before damage it. + */ + CacheItem getItem( EItemType eType, + const OUString& sItem); + + + /** TODO document me ... + + @throws css::uno::Exception + */ + void removeItem( EItemType eType, + const OUString& sItem); + + + /** TODO document me ... + + @throws css::uno::Exception + */ + void setItem( EItemType eType , + const OUString& sItem , + const CacheItem& aValue); + + + /** TODO document me ... + + @throws css::uno::Exception + */ + void refreshItem( EItemType eType, + const OUString& sItem); + + + /** @short add some implicit properties to the given + cache item reference. + + @descr Such properties can e.g. finalized or mandatory. + They are not persistent and not really part of e.g. a + filter not. But they are attributes of a configuration + entry and can influence our container interface. + + @attention These properties are not part of the normal CacheItem + returned by the method getItem(). Because getItem() is + used internally too but these specialized properties + are needed at our container services only. So these + function sets are different to allow different handling. + + @param eType + specify the sub container of this cache, which should be used for + searching. see also EItemType. + + @param sItem + specify the requested item by its key name. + + @param rItem + contains already the normal properties of this item, + and will be used as out parameter to add the implicit + attributes there. + + @throw [css::uno::Exception] + if an internal error occurred. + Note: if the item is missing inside the underlying configuration + no exception will be thrown. In such case the item is marked as + finalized/mandatory automatically + Reason: maybe the item comes from the old configuration package and + was not migrated to the new one. So we can't provide write access + to such items... + */ + css::uno::Any getItemWithStateProps( EItemType eType, + const OUString& sItem); + + /** TODO document me + + @throws css::uno::Exception + */ + static void removeStatePropsFromItem(CacheItem& aValue); + + + /** @short force writing of all changes (which was made after + last flush was called) back to the configuration. + + @descr TODO + + @throw [css::uno::Exception] + if the cache itself is not valid + any longer, because any operation before damage it. + */ + void flush(); + + + /** @short supports a flat type detection for given URL. + + @descr Because such detection works on our optimized internal + structures (e.g. mapping from extensions/pattern to type names), + it should be made inside this cache. + + @param aURL + URL of the content, which type should be detected. + It's already parsed and split into its different parts, + like e.g.: main, jump marks etcpp. + + @param rFlatTypes + used as [out] parameter to add all types, which match to the given + URL. Further an information is added for every type. It indicates, how + this type is related to the specified URL (means e.g. if it matches + by extension or URLPattern...). + + @attention Please note: because this cache can be used inside multithreaded + environments, such returned key names can point to some already removed + items! Please be aware of some "NoSuchElementExceptions" if you try to + call any other method of this cache in relation to this key names. + + @throw [css::uno::Exception] + if the cache itself is not valid + any longer, because any operation before damage it. + */ + void detectFlatForURL(const css::util::URL& aURL , + FlatDetection& rFlatTypes) const; + + + // private helper + + private: + + + /** @short return a reference to one of our internal + sub container, which contains items of the + requested type. + + @param eType + specify, which sub container is needed outside. + + @return [CacheItemList&] + a reference(!) to the right sub container member. + + @throw [css::uno::Exception] + if the required list does not exist. + */ + const CacheItemList& impl_getItemList(EItemType eType) const; + + CacheItemList& impl_getItemList(EItemType eType); + + CacheItem& impl_getItem( EItemType eType, const OUString& sItem); + + /** @short return a valid configuration update access + to the underlying configuration package, which + is fix for this cache. + + @descr It checks first, if the internal member m_xConfig already + points to an open update access. If not - it opens a new one. + Doing so this method can be called every time a configuration + access is needed. + + @param eProvider + specify the needed configuration provider. + see EConfigProvider for further information ... + + @throws css::uno::Exception + + @attention If a configuration access was opened successfully + all necessary listener connections will be established + too. So this cache will be informed about outside updates. + */ + css::uno::Reference< css::uno::XInterface > impl_openConfig(EConfigProvider eProvide); + + + /** @short tries to open the requested configuration root + using the specified modi. + + @param sRoot + specify the configuration root, which should be opened. + + @param bReadOnly + enable/disable write access on the returned configuration + object. + + @param bLocalesMode + enable/disable special handling of localized configuration + items by the returned configuration object. + + @return A valid reference, if the configuration access could be opened + and initialized within the requested modes successfully; + a NULL reference otherwise. + */ + css::uno::Reference< css::uno::XInterface > impl_createConfigAccess(const OUString& sRoot , + bool bReadOnly , + bool bLocalesMode); + + + /** @short reads the specified configuration key + and return its value. + + @descr The specified key must be an absolute configuration path, + which can be split into its package and relative path tokens. + + @attention Because this function might opens a new configuration + read access for reading one key value only, it should + be used in rare cases only. It's an easy way... but an + expensive one. + + @param sDirectKey + the absolute configuration path, which should be read. + + @return [css::uno::Any] + the value of the requested key. + Can be empty if an internal error occurred or if the requested + key does not exists! + */ + css::uno::Any impl_getDirectCFGValue(const OUString& sDirectKey); + + + /** @short load the underlying configuration into this cache. + + @descr Which items should be read can be regulate by the + parameter eRequiredState. That provides the possibility + to load standard values on startup only and update this + cache later on demand with all available information. + + @param eRequiredState + indicates, which fill state this cache should have afterwards. + + @throws css::uno::Exception + */ + void impl_load(EFillState eRequiredState); + + + /** @short validate the whole cache and create + structures for optimized items access. + + @descr Wrong cache items will be removed automatically. + Wrong dependencies will be corrected automatically. + If something could not be repaired - an exception + is thrown. + Further some optimized structures will be created. + E.g.: a hash to map extensions to her types. + + @attention There is no exception, if the cache could be repaired + but contained wrong elements before! + + @throw [css::uno::Exception] + if cache is invalid and could not be repaired. + */ + void impl_validateAndOptimize(); + + private: + + + /** @short read the specified config set into the cache. + + @descr This method provides the following mechanism for reading: + a) read only standard properties of set items + b) read anything + c) read only optional properties and update already existing + items of the specified cache + + @param xConfig + API which provides access to the required configuration set. + + @param eType + specify the type of config item, which must be interpreted. + Of course this information can be used to locate the right set + at the given xConfig API object. + + @param eOption + regulate reading of standard/optional or all properties. + + @param pCache + points to the cache member, which should be filled or updated. + + @throw [css::uno::Exception] + if an unrecoverable error occurs inside this operation. + */ + void impl_loadSet(const css::uno::Reference< css::container::XNameAccess >& xConfig, + EItemType eType , + EReadOption eOption, + CacheItemList* pCache ); + + + /** @short read the specified container item from the given configuration set. + + @descr It's not added to any internal structures here. That must be done + outside this method. + + @param xSet + provides access to the configuration set, which includes all items. + + @param eType + specify, which container item type must be read. + + @param sItem + means the internal name, which can be used to address the item + properties relative to the given configuration set. + + @param eOption + regulate, which properties of the requested item should be read. + See definition of EReadOption for further information. + + @throw [css::uno::Exception] + if an unrecoverable error occurs inside this operation. + */ + CacheItem impl_loadItem(const css::uno::Reference< css::container::XNameAccess >& xSet , + EItemType eType , + const OUString& sItem , + EReadOption eOption); + + + /** @short try to load the requested item on demand from the underlying configuration + layer. + + @descr The outside code has to be sure, that the item does not already exists + inside this cache. Otherwise it will be loaded twice. This method + doesn't check such constellations! + + @param eType + specify the type of config item, which must be interpreted. + Of course this information can be used to locate the right set + at the given xConfig API object. + + @param sItem + the set node name of the requested item. + + @return An iterator, which points directly to the new cached item. + Is a valid iterator if no exception occurred here! + But to improve robustness - it should be checked :-) + + @throw [css::container::NoSuchElementException] + if the item does not exists inside the configuration layer too! + + @throw [css::uno::Exception] + if an unrecoverable error occurs inside this operation. + */ + CacheItemList::iterator impl_loadItemOnDemand( EItemType eType, + const OUString& sItem); + + + /** TODO + + @throws css::uno::Exception + */ + static void impl_saveItem(const css::uno::Reference< css::container::XNameReplace >& xSet , + EItemType eType , + const CacheItem & aValue); + + + /** TODO + + @throws css::uno::Exception + */ + void impl_addItem2FlushList( EItemType eType, + const OUString& sItem); + + + /** TODO + + @throws css::uno::Exception + */ + static void impl_flushByList(const css::uno::Reference< css::container::XNameAccess >& xSet , + EItemType eType , + const CacheItemList& rCache, + const std::vector& lItems); + + + /** @short specify, which save operation is necessary for the specified item. + + @desrc If an item of this cache will be added/removed or modified it will + be changed inside memory only first. But we save its name inside a special + list of changed items. If at least the method flush() is called, we use + this list to check if the item was changed/added or removed. This method + checks the exist state of the requested item inside our own cache + and inside the underlying configuration layer to find out, if the item + must be removed/added or modified inside the configuration layer. + + @param xSet + points directly to the configuration set, where the item should resist + (if it exists!). + + @param rList + points to our internal cache list, where the item should resist + (if it exists!). + + @param sItem + the internal name of the item, which should be checked. + + @return An enum value of type EItemFlushState, which indicates the needed + API operation for updating the underlying configuration layer. + + @throws An exception if anything failed inside this operation. + e.g. the given configuration set was not open. + */ + static EItemFlushState impl_specifyFlushOperation(const css::uno::Reference< css::container::XNameAccess >& xSet , + const CacheItemList& rList, + const OUString& sItem); + + + /** TODO + + @throws css::uno::Exception + */ + void impl_readPatchUINames(const css::uno::Reference< css::container::XNameAccess >& xNode, + CacheItem& rItem); + + + /** TODO + + @throws css::uno::Exception + */ + static void impl_savePatchUINames(const css::uno::Reference< css::container::XNameReplace >& xNode, + const CacheItem& rItem); + + /** TODO */ + void impl_readOldFormat(); + + /** TODO + + @throws css::uno::Exception + */ + CacheItem impl_readOldItem(const css::uno::Reference< css::container::XNameAccess >& xSet , + EItemType eType, + const OUString& sItem); + + + /** TODO */ + static void impl_interpretDataVal4Type(const OUString& sValue, + sal_Int32 nProp , + CacheItem& rItem ); + + + /** TODO */ + static void impl_interpretDataVal4Filter(const OUString& sValue, + sal_Int32 nProp , + CacheItem& rItem ); + + + /** TODO */ + static std::vector impl_tokenizeString(std::u16string_view sData , + sal_Unicode cSeparator); + + +#if OSL_DEBUG_LEVEL > 0 + /** TODO */ + OUString impl_searchFrameLoaderForType(const OUString& sType) const; + OUString impl_searchContentHandlerForType(const OUString& sType) const; +#endif + + + /** @short check if the specified OOo module is installed. + + @param sModule + the long name of the module (e.g. "com.sun.star.text.TextDocument"). + + @return sal_True if the requested module is installed; sal_False otherwise. + */ + bool impl_isModuleInstalled(const OUString& sModule); + + + /** @short convert a list of flag names to its int representation. + + @param lNames + the list of flag names. + + @return the converted flag field. + */ + static SfxFilterFlags impl_convertFlagNames2FlagField(const css::uno::Sequence< OUString >& lNames); + + + /** @short convert a flag field value to its list representation of flag names. + + @param nFlags + the flag field value + + @return [seq< string >] + the converted flag name list. + */ + static css::uno::Sequence< OUString > impl_convertFlagField2FlagNames(SfxFilterFlags nFlags); +}; + +FilterCache& GetTheFilterCache(); + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/filterconfig1.component b/filter/source/config/cache/filterconfig1.component new file mode 100644 index 000000000..711c0e38f --- /dev/null +++ b/filter/source/config/cache/filterconfig1.component @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/filter/source/config/cache/filterfactory.cxx b/filter/source/config/cache/filterfactory.cxx new file mode 100644 index 000000000..e083614c0 --- /dev/null +++ b/filter/source/config/cache/filterfactory.cxx @@ -0,0 +1,498 @@ +/* -*- 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 "filterfactory.hxx" +#include "constant.hxx" + +#include +#include +#include +#include +#include + + +namespace filter::config{ + +FilterCache& GetTheFilterCache() +{ + static FilterCache CACHE; + return CACHE; +} + +/** @short define all possible parts of a filter query. + + @descr syntax: "[:[=]]" + e.g.: "_query_writer:default_first:use_order:sort_prop=uiname" + + argument description default + ----------------------------------------------------------------------------------------------- + iflags= include filters by given mask 0 + eflags= exclude filters by given mask 0 + sort_prop=<[name,uiname]> sort by internal name or uiname name + descending sort descending false + use_order use order flag of filters for sorting false + default_first set default filter on top of return list false + case_sensitive compare "sort_prop" case sensitive false + */ + +FilterFactory::FilterFactory(const css::uno::Reference< css::uno::XComponentContext >& rxContext) + : m_xContext(rxContext) +{ + static const css::uno::Sequence sServiceNames { "com.sun.star.document.FilterFactory" }; + BaseContainer::init("com.sun.star.comp.filter.config.FilterFactory" , + sServiceNames, + FilterCache::E_FILTER ); +} + + +FilterFactory::~FilterFactory() +{ +} + + +css::uno::Reference< css::uno::XInterface > SAL_CALL FilterFactory::createInstance(const OUString& sFilter) +{ + return createInstanceWithArguments(sFilter, css::uno::Sequence< css::uno::Any >()); +} + + +css::uno::Reference< css::uno::XInterface > SAL_CALL FilterFactory::createInstanceWithArguments(const OUString& sFilter , + const css::uno::Sequence< css::uno::Any >& lArguments) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + auto & cache = GetTheFilterCache(); + + // search filter on cache + CacheItem aFilter = cache.getItem(FilterCache::E_FILTER, sFilter); + OUString sFilterService; + aFilter[PROPNAME_FILTERSERVICE] >>= sFilterService; + + // create service instance + css::uno::Reference< css::uno::XInterface > xFilter; + if (!sFilterService.isEmpty()) + xFilter = m_xContext->getServiceManager()->createInstanceWithContext(sFilterService, m_xContext); + + // initialize filter + css::uno::Reference< css::lang::XInitialization > xInit(xFilter, css::uno::UNO_QUERY); + if (xInit.is()) + { + // format: lInitData[0] = seq, which contains all configuration properties of this filter + // lInitData[1] = lArguments[0] + // ... + // lInitData[n] = lArguments[n-1] + css::uno::Sequence< css::beans::PropertyValue > lConfig; + aFilter >> lConfig; + + ::std::vector< css::uno::Any > stlArguments(comphelper::sequenceToContainer< ::std::vector< css::uno::Any > >(lArguments)); + stlArguments.insert(stlArguments.begin(), css::uno::Any(lConfig)); + + xInit->initialize(comphelper::containerToSequence(stlArguments)); + } + + return xFilter; + // <- SAFE +} + + +css::uno::Sequence< OUString > SAL_CALL FilterFactory::getAvailableServiceNames() +{ + /* Attention: Instead of getElementNames() this method have to return only filter names, + which can be created as UNO Services really. That's why we search for filters, + which don't have a valid value for the property "FilterService". + Of course we can't check for corrupted service names here. We can check + for empty strings only... + */ + css::beans::NamedValue lEProps[] { + { PROPNAME_FILTERSERVICE, css::uno::Any(OUString()) } }; + + std::vector lUNOFilters; + try + { + lUNOFilters = GetTheFilterCache().getMatchingItemsByProps(FilterCache::E_FILTER, {}, lEProps); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { lUNOFilters.clear(); } + + return comphelper::containerToSequence(lUNOFilters); +} + + +css::uno::Reference< css::container::XEnumeration > SAL_CALL FilterFactory::createSubSetEnumerationByQuery(const OUString& sQuery) +{ + // reject old deprecated queries ... + if (sQuery.startsWith("_filterquery_")) + throw css::uno::RuntimeException( + "Use of deprecated and now unsupported query!", + static_cast< css::container::XContainerQuery* >(this)); + + // convert "_query_xxx:..." to "getByDocService=xxx:..." + OUString sNewQuery(sQuery); + sal_Int32 pos = sNewQuery.indexOf("_query_"); + if (pos != -1) + { + OSL_FAIL("DEPRECATED!\nPlease use new query format: 'matchByDocumentService=...'"); + OUString sPatchedQuery(OUString::Concat("matchByDocumentService=") + sNewQuery.subView(7)); + sNewQuery = sPatchedQuery; + } + + // analyze query and split it into its tokens + QueryTokenizer lTokens(sNewQuery); + std::vector lEnumSet; + + // start query + // (see attention comment below!) + if (lTokens.valid()) + { + // SAFE -> ---------------------- + { + osl::MutexGuard aLock(m_aMutex); + // May be not all filters was loaded ... + // But we need it now! + impl_loadOnDemand(); + } + // <- SAFE ---------------------- + + if (lTokens.find(QUERY_IDENTIFIER_GETPREFERREDFILTERFORTYPE) != lTokens.end()) + OSL_FAIL("DEPRECATED!\nPlease use prop search at the TypeDetection container!"); + else + if (lTokens.find(QUERY_IDENTIFIER_MATCHBYDOCUMENTSERVICE) != lTokens.end()) + lEnumSet = impl_queryMatchByDocumentService(lTokens); + else + if (lTokens.find(QUERY_IDENTIFIER_GET_SORTED_FILTERLIST) != lTokens.end()) + lEnumSet = impl_getSortedFilterList(lTokens); + } + + // pack list of item names as an enum list + // Attention: Do not return empty reference for empty list! + // The outside check "hasMoreElements()" should be enough, to detect this state :-) + return new ::comphelper::OEnumerationByName(this, std::move(lEnumSet)); +} + + +std::vector FilterFactory::impl_queryMatchByDocumentService(const QueryTokenizer& lTokens) const +{ + // analyze query + QueryTokenizer::const_iterator pIt; + + OUString sDocumentService; + sal_Int32 nIFlags = 0; + sal_Int32 nEFlags = 0; + + pIt = lTokens.find(QUERY_IDENTIFIER_MATCHBYDOCUMENTSERVICE); + if (pIt != lTokens.end()) + sDocumentService = pIt->second; + +#define COMP_HACK +#ifdef COMP_HACK + if ( sDocumentService == "writer" ) + { + OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!"); + sDocumentService = "com.sun.star.text.TextDocument"; + } + else if ( sDocumentService == "web" ) + { + OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!"); + sDocumentService = "com.sun.star.text.WebDocument"; + } + else if ( sDocumentService == "global" ) + { + OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!"); + sDocumentService = "com.sun.star.text.GlobalDocument"; + } + else if ( sDocumentService == "calc" ) + { + OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!"); + sDocumentService = "com.sun.star.sheet.SpreadsheetDocument"; + } + else if ( sDocumentService == "draw" ) + { + OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!"); + sDocumentService = "com.sun.star.drawing.DrawingDocument"; + } + else if ( sDocumentService == "impress" ) + { + OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!"); + sDocumentService = "com.sun.star.presentation.PresentationDocument"; + } + else if ( sDocumentService == "math" ) + { + OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!"); + sDocumentService = "com.sun.star.formula.FormulaProperties"; + } +#endif + + pIt = lTokens.find(QUERY_PARAM_IFLAGS); + if (pIt != lTokens.end()) + nIFlags = pIt->second.toInt32(); + + pIt = lTokens.find(QUERY_PARAM_EFLAGS); + if (pIt != lTokens.end()) + nEFlags = pIt->second.toInt32(); + + // SAFE -> ---------------------- + osl::ClearableMutexGuard aLock(m_aMutex); + + // search suitable filters + FilterCache* pCache = impl_getWorkingCache(); + std::vector lFilterNames = pCache->getItemNames(FilterCache::E_FILTER); + std::vector lResult ; + + for (auto const& filterName : lFilterNames) + { + try + { + const CacheItem aFilter = pCache->getItem(FilterCache::E_FILTER, filterName); + + // "matchByDocumentService=" => any filter will be addressed here + // "matchByDocumentService=all" => any filter will be addressed here + // "matchByDocumentService=com.sun.star..." => only filter matching this document service will be addressed + OUString sCheckValue = aFilter.getUnpackedValueOrDefault(PROPNAME_DOCUMENTSERVICE, OUString()); + if ( + (!sDocumentService.isEmpty() ) && + (sDocumentService != QUERY_CONSTVALUE_ALL ) && + (sCheckValue != sDocumentService ) + ) + { + continue; // ignore filter -> try next one! + } + + // "iflags=" => not allowed + // "iflags=-1" => not allowed + // "iflags=0" => not useful + // "iflags=283648" => only filter, which has set these flag field will be addressed + sal_Int32 nCheckValue = aFilter.getUnpackedValueOrDefault(PROPNAME_FLAGS, sal_Int32(0)); + if ( + (nIFlags > 0 ) && + ((nCheckValue & nIFlags) != nIFlags) + ) + { + continue; // ignore filter -> try next one! + } + + // "eflags=" => not allowed + // "eflags=-1" => not allowed + // "eflags=0" => not useful + // "eflags=283648" => only filter, which has not set these flag field will be addressed + if ( + (nEFlags > 0 ) && + ((nCheckValue & nEFlags) == nEFlags) + ) + { + continue; // ignore filter -> try next one! + } + + // OK - this filter passed all checks. + // It match the query ... + lResult.push_back(filterName); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { continue; } + } + + aLock.clear(); + // <- SAFE ---------------------- + + return lResult; +} + +namespace { + +class stlcomp_removeIfMatchFlags +{ + private: + FilterCache* m_pCache ; + sal_Int32 m_nFlags ; + bool m_bIFlags; + + public: + stlcomp_removeIfMatchFlags(FilterCache* pCache , + sal_Int32 nFlags , + bool bIFlags) + : m_pCache (pCache ) + , m_nFlags (nFlags ) + , m_bIFlags(bIFlags) + {} + + bool operator() (const OUString& sFilter) const + { + try + { + const CacheItem aFilter = m_pCache->getItem(FilterCache::E_FILTER, sFilter); + sal_Int32 nFlags = aFilter.getUnpackedValueOrDefault(PROPNAME_FLAGS, (sal_Int32(0))); + + bool bMatch = false; + if (m_bIFlags) + // IFlags are interpreted as ALL_FLAGS_MUST_MATCH ! + bMatch = ((nFlags & m_nFlags) == m_nFlags); + else + // EFlags are interpreted as AT_LEAST_ONE_FLAG_MUST_MATCH ! + bMatch = !(nFlags & m_nFlags); + // We are asked for bRemove ! And bMatch = !bRemove => so bRemove = !bMatch .-) + return !bMatch; + } + catch(const css::container::NoSuchElementException &) + { + return true; + } + } +}; + +} + +std::vector FilterFactory::impl_getSortedFilterList(const QueryTokenizer& lTokens) const +{ + // analyze the given query parameter + QueryTokenizer::const_iterator pIt1; + + OUString sModule; + sal_Int32 nIFlags = -1; + sal_Int32 nEFlags = -1; + + pIt1 = lTokens.find(QUERY_PARAM_MODULE); + if (pIt1 != lTokens.end()) + sModule = pIt1->second; + pIt1 = lTokens.find(QUERY_PARAM_IFLAGS); + if (pIt1 != lTokens.end()) + nIFlags = pIt1->second.toInt32(); + pIt1 = lTokens.find(QUERY_PARAM_EFLAGS); + if (pIt1 != lTokens.end()) + nEFlags = pIt1->second.toInt32(); + + // simple search for filters of one specific module. + std::vector lFilterList; + if (!sModule.isEmpty()) + lFilterList = impl_getSortedFilterListForModule(sModule, nIFlags, nEFlags); + else + { + // more complex search for all filters + // We check first, which office modules are installed... + const css::uno::Sequence lModules = impl_getListOfInstalledModules(); + for (auto const& module : lModules) + { + std::vector lFilters4Module = impl_getSortedFilterListForModule(module, nIFlags, nEFlags); + for (auto const& filter4Module : lFilters4Module) + { + lFilterList.push_back(filter4Module); + } + } + } + + return lFilterList; +} + + +css::uno::Sequence FilterFactory::impl_getListOfInstalledModules() +{ + css::uno::Reference< css::container::XNameAccess > xModuleConfig = officecfg::Setup::Office::Factories::get(); + return xModuleConfig->getElementNames(); +} + + +std::vector FilterFactory::impl_getSortedFilterListForModule(const OUString& sModule, + sal_Int32 nIFlags, + sal_Int32 nEFlags) const +{ + std::vector lSortedFilters = impl_readSortedFilterListFromConfig(sModule); + + // get all filters for the requested module + css::beans::NamedValue lIProps[] { { PROPNAME_DOCUMENTSERVICE, css::uno::Any(sModule) } }; + + // SAFE -> ---------------------- + osl::ClearableMutexGuard aLock(m_aMutex); + FilterCache* pCache = impl_getWorkingCache(); + std::vector lOtherFilters = pCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps); + aLock.clear(); + // <- SAFE ---------------------- + + // bring "other" filters in an alphabetical order + // It's needed below. + ::std::sort(lOtherFilters.begin(), lOtherFilters.end()); + + // merge both lists together + std::vector lMergedFilters = lSortedFilters; + const auto itlSortedFiltersEnd = lSortedFilters.cend(); + for (auto const& otherFilter : lOtherFilters) + { + if (::std::find(lSortedFilters.cbegin(), lSortedFilters.cend(), otherFilter) == itlSortedFiltersEnd) + lMergedFilters.push_back(otherFilter); + } + + // remove all filters from this merged list, which does not fit the flag specification + if (nIFlags != -1) + { + auto pItToErase = ::std::remove_if(lMergedFilters.begin(), lMergedFilters.end(), stlcomp_removeIfMatchFlags(pCache, nIFlags, true)); + lMergedFilters.erase(pItToErase, lMergedFilters.end()); + } + if (nEFlags != -1) + { + auto pItToErase = ::std::remove_if(lMergedFilters.begin(), lMergedFilters.end(), stlcomp_removeIfMatchFlags(pCache, nEFlags, false)); + lMergedFilters.erase(pItToErase, lMergedFilters.end()); + } + + // sort the default filter to the front of this list + // TODO + + return lMergedFilters; +} + + +std::vector FilterFactory::impl_readSortedFilterListFromConfig(const OUString& sModule) +{ + try + { + css::uno::Reference< css::container::XNameAccess > xUISortConfig = officecfg::TypeDetection::UISort::ModuleDependendFilterOrder::get(); + // don't check the module name here. If it does not exists, an exception is thrown and caught below. + // We return an empty list as result then. + css::uno::Reference< css::container::XNameAccess > xModule; + xUISortConfig->getByName(sModule) >>= xModule; + if (xModule.is()) // only to be on the safe side of life if the exception was not thrown .-) + { + // Note: conversion of the returned Any to std::vector throws + // an IllegalArgumentException if the type does not match ... + // but it resets the std::vector to a length of 0 if the Any is empty! + std::vector lSortedFilters( + comphelper::sequenceToContainer< std::vector >(xModule->getByName(PROPNAME_SORTEDFILTERLIST).get >())); + return lSortedFilters; + } + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + {} + + return std::vector(); +} + +} // namespace filter + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_FilterFactory_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new filter::config::FilterFactory(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/filterfactory.hxx b/filter/source/config/cache/filterfactory.hxx new file mode 100644 index 000000000..9be370f4d --- /dev/null +++ b/filter/source/config/cache/filterfactory.hxx @@ -0,0 +1,135 @@ +/* -*- 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 . + */ + +#pragma once + +#include "basecontainer.hxx" +#include "querytokenizer.hxx" +#include +#include + + +namespace filter::config { + + +/** @short implements the service FilterFactory. + */ +class FilterFactory : public ::cppu::ImplInheritanceHelper< BaseContainer , + css::lang::XMultiServiceFactory > +{ + + // native interface + + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + public: + + + // ctor/dtor + + /** @short standard ctor to connect this interface wrapper to + the global filter cache instance ... + + @param rxContext + reference to the uno service manager, which created this service instance. + */ + explicit FilterFactory(const css::uno::Reference< css::uno::XComponentContext >& rxContext); + + + /** @short standard dtor. + */ + virtual ~FilterFactory() override; + + + // uno interface + + public: + + + // XMultiServiceFactory + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance(const OUString& sFilter) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments(const OUString& sFilter , + const css::uno::Sequence< css::uno::Any >& lArguments) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + + + // XContainerQuery + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByQuery(const OUString& sQuery) override; + + + // internal helper! + + private: + + + /** @short implement the container string query: "matchByDocumentService=:iflags=:eflags=:..." + + @param lTokens + the list of query tokens and its values. + + @return A string list of internal filter names, including + all filters, which match this query. + */ + std::vector impl_queryMatchByDocumentService(const QueryTokenizer& lTokens) const; + + + /** TODO document me + */ + static css::uno::Sequence impl_getListOfInstalledModules(); + + + /** @short implement the container string query: + "getSortedFilterList()[:module=]:[iflags=][:eflags=]" + + @param lTokens + the list of query tokens and its values. + + @return A string list of internal filter names, including + all filters, which match this query. + */ + std::vector impl_getSortedFilterList(const QueryTokenizer& lTokens) const; + + + /** TODO document me + */ + std::vector impl_getSortedFilterListForModule(const OUString& sModule, + sal_Int32 nIFlags, + sal_Int32 nEFlags) const; + + + /** @short read a specialized and sorted list of filter names from + the configuration (matching the specified module) + + @param sModule + the module for which the sorted list should be retrieved for. + + @return A string list of internal filter names. + Can be empty. + */ + static std::vector impl_readSortedFilterListFromConfig(const OUString& sModule); + +}; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/frameloaderfactory.cxx b/filter/source/config/cache/frameloaderfactory.cxx new file mode 100644 index 000000000..ebe482366 --- /dev/null +++ b/filter/source/config/cache/frameloaderfactory.cxx @@ -0,0 +1,102 @@ +/* -*- 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 "frameloaderfactory.hxx" + +#include +#include + + +namespace filter::config{ + +FrameLoaderFactory::FrameLoaderFactory(const css::uno::Reference< css::uno::XComponentContext >& rxContext) + : m_xContext(rxContext) +{ + BaseContainer::init("com.sun.star.comp.filter.config.FrameLoaderFactory" , + { "com.sun.star.frame.FrameLoaderFactory" }, + FilterCache::E_FRAMELOADER ); +} + + +FrameLoaderFactory::~FrameLoaderFactory() +{ +} + + +css::uno::Reference< css::uno::XInterface > SAL_CALL FrameLoaderFactory::createInstance(const OUString& sLoader) +{ + return createInstanceWithArguments(sLoader, css::uno::Sequence< css::uno::Any >()); +} + + +css::uno::Reference< css::uno::XInterface > SAL_CALL FrameLoaderFactory::createInstanceWithArguments(const OUString& sLoader , + const css::uno::Sequence< css::uno::Any >& lArguments) +{ + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + auto & cache = GetTheFilterCache(); + + // search loader on cache + CacheItem aLoader = cache.getItem(m_eType, sLoader); + + // create service instance + css::uno::Reference< css::uno::XInterface > xLoader = m_xContext->getServiceManager()->createInstanceWithContext(sLoader, m_xContext); + + // initialize filter + css::uno::Reference< css::lang::XInitialization > xInit(xLoader, css::uno::UNO_QUERY); + if (xInit.is()) + { + // format: lInitData[0] = seq, which contains all configuration properties of this loader + // lInitData[1] = lArguments[0] + // ... + // lInitData[n] = lArguments[n-1] + css::uno::Sequence< css::beans::PropertyValue > lConfig; + aLoader >> lConfig; + + ::std::vector< css::uno::Any > stlArguments(comphelper::sequenceToContainer< ::std::vector >(lArguments)); + stlArguments.insert(stlArguments.begin(), css::uno::Any(lConfig)); + + xInit->initialize(comphelper::containerToSequence(stlArguments)); + } + + return xLoader; + // <- SAFE +} + + +css::uno::Sequence< OUString > SAL_CALL FrameLoaderFactory::getAvailableServiceNames() +{ + // must be the same list as ((XNameAccess*)this)->getElementNames() return! + return BaseContainer::getElementNames(); +} + +} // namespace filter::config + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_FrameLoaderFactory_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new filter::config::FrameLoaderFactory(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/frameloaderfactory.hxx b/filter/source/config/cache/frameloaderfactory.hxx new file mode 100644 index 000000000..2b9098b1a --- /dev/null +++ b/filter/source/config/cache/frameloaderfactory.hxx @@ -0,0 +1,98 @@ +/* -*- 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 . + */ + +#pragma once + +#include "basecontainer.hxx" +#include +#include + + +namespace filter::config { + + +/** @short implements the service FrameLoaderFactory. + */ +class FrameLoaderFactory : public ::cppu::ImplInheritanceHelper< BaseContainer , + css::frame::XLoaderFactory > +{ + + // native interface + + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + public: + + + // ctor/dtor + + /** @short standard ctor to connect this interface wrapper to + the global filter cache instance ... + + @param rxContext + reference to the uno service manager, which created this service instance. + */ + explicit FrameLoaderFactory(const css::uno::Reference< css::uno::XComponentContext >& rxContext); + + + /** @short standard dtor. + */ + virtual ~FrameLoaderFactory() override; + + + // uno interface + + public: + + + // XMultiServiceFactory + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance(const OUString& sLoader) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments(const OUString& sLoader , + const css::uno::Sequence< css::uno::Any >& lArguments) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + + + public: + + // Overrides to resolve ambiguity + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override + { return BaseContainer::getByName(aName); } + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override + { return BaseContainer::getElementNames(); } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { return BaseContainer::hasByName(aName); } + + virtual css::uno::Type SAL_CALL getElementType() override + { return BaseContainer::getElementType(); } + virtual sal_Bool SAL_CALL hasElements() override + { return BaseContainer::hasElements(); } + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByQuery( const OUString& Query ) override + { return BaseContainer::createSubSetEnumerationByQuery(Query); } + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByProperties( const css::uno::Sequence< css::beans::NamedValue >& Properties ) override + { return BaseContainer::createSubSetEnumerationByProperties(Properties); } + +}; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/querytokenizer.cxx b/filter/source/config/cache/querytokenizer.cxx new file mode 100644 index 000000000..f5b021f53 --- /dev/null +++ b/filter/source/config/cache/querytokenizer.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 "querytokenizer.hxx" + +#include +#include + + +namespace filter::config{ + + +QueryTokenizer::QueryTokenizer(std::u16string_view sQuery) + : m_bValid(true) +{ + sal_Int32 token = 0; + while(token != -1) + { + std::u16string_view sToken = o3tl::getToken(sQuery,0, ':', token); + if (!sToken.empty()) + { + sal_Int32 nIdx{ 0 }; + const OUString sKey{ o3tl::getToken(sToken, 0, '=', nIdx) }; + const OUString sVal{ o3tl::getToken(sToken, 0, ':', nIdx) }; + + if (sKey.isEmpty()) + m_bValid = false; + OSL_ENSURE(m_bValid, "QueryTokenizer::QueryTokenizer() Found non boolean query parameter ... but its key is empty. Will be ignored!"); + + if (find(sKey) != end()) + m_bValid = false; + OSL_ENSURE(m_bValid, "QueryTokenizer::QueryTokenizer() Query contains same param more than once. Last one wins :-)"); + + (*this)[sKey] = sVal; + } + } +} + + +QueryTokenizer::~QueryTokenizer() +{ + /*TODO*/ +} + + +bool QueryTokenizer::valid() const +{ + return m_bValid; +} + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/querytokenizer.hxx b/filter/source/config/cache/querytokenizer.hxx new file mode 100644 index 000000000..0c7e79b3d --- /dev/null +++ b/filter/source/config/cache/querytokenizer.hxx @@ -0,0 +1,92 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + + +namespace filter::config { + + +/** @short It can be used to split any query string (which can be used at the + related interface XContainerQuery) + into its different tokens using a fix schema. + + @descr All queries implemented of the services +
    +
  • TypeDetection
  • +
  • FilterFactory
  • +
  • ExtendedTypeDetectionFactory
  • +
  • FrameLoaderFactory
  • +
  • ContentHandlerFactory
  • +
+ uses this schema. + + @attention This class is not threadsafe implemented. Because it's not necessary. + But you have to make sure that it's not used as such :-) + */ +class QueryTokenizer : public std::unordered_map< OUString, OUString > +{ + + // member + + private: + + /** @short Because the given query can contain errors, + it should be checked outside. + + TODO May it's a good idea to describe the real problem + more detailed ... + */ + bool m_bValid; + + + // interface + + public: + + /** @short create a new tokenizer instance with a + a new query. + + @descr The given query is immediately analyzed + and separated into its token, which can + be access by some specialized method later. + + @param sQuery + the query string. + */ + explicit QueryTokenizer(std::u16string_view sQuery); + + + /** @short destruct an instance of this class. + */ + virtual ~QueryTokenizer(); + + + /** @short can be used to check if analyzing of given query + was successful or not. + */ + bool valid() const; +}; + +} // namespace filter::config + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/typedetection.cxx b/filter/source/config/cache/typedetection.cxx new file mode 100644 index 000000000..ae8c194fa --- /dev/null +++ b/filter/source/config/cache/typedetection.cxx @@ -0,0 +1,1204 @@ +/* -*- 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 "typedetection.hxx" +#include "constant.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_TYPE_DETECTION 0 + +#if DEBUG_TYPE_DETECTION +#include +using std::cout; +using std::endl; +#endif + +using namespace com::sun::star; + +namespace filter::config{ + +TypeDetection::TypeDetection(const css::uno::Reference< css::uno::XComponentContext >& rxContext) + : m_xContext(rxContext) + , m_xTerminateListener(new TerminateDetection(this)) + , m_bCancel(false) +{ + css::frame::Desktop::create(m_xContext)->addTerminateListener(m_xTerminateListener); + BaseContainer::init("com.sun.star.comp.filter.config.TypeDetection" , + { "com.sun.star.document.TypeDetection" }, + FilterCache::E_TYPE ); +} + + +TypeDetection::~TypeDetection() +{ + css::frame::Desktop::create(m_xContext)->removeTerminateListener(m_xTerminateListener); +} + + +OUString SAL_CALL TypeDetection::queryTypeByURL(const OUString& sURL) +{ + OUString sType; + + // SAFE -> + osl::MutexGuard aLock(m_aMutex); + + css::util::URL aURL; + aURL.Complete = sURL; + css::uno::Reference< css::util::XURLTransformer > xParser( css::util::URLTransformer::create(m_xContext) ); + xParser->parseStrict(aURL); + + // set std types as minimum requirement first! + // Only in case no type was found for given URL, + // use optional types too ... + auto & cache = GetTheFilterCache(); + FlatDetection lFlatTypes; + cache.detectFlatForURL(aURL, lFlatTypes); + + if ( + (lFlatTypes.empty() ) && + (!cache.isFillState(FilterCache::E_CONTAINS_TYPES)) + ) + { + cache.load(FilterCache::E_CONTAINS_TYPES); + cache.detectFlatForURL(aURL, lFlatTypes); + } + + // first item is guaranteed as "preferred" one! + if (!lFlatTypes.empty()) + { + const FlatDetectionInfo& aMatch = *(lFlatTypes.begin()); + sType = aMatch.sType; + } + + return sType; + // <- SAFE +} + +namespace { + +/** + * Rank format types in order of complexity. More complex formats are + * ranked higher so that they get tested sooner over simpler formats. + * + * Guidelines to determine how complex a format is (subject to change): + * + * 1) compressed text (XML, HTML, etc) + * 2) binary + * 3) non-compressed text + * 3.1) structured text + * 3.1.1) dialect of a structured text (e.g. docbook XML) + * 3.1.2) generic structured text (e.g. generic XML) + * 3.2) non-structured text + * + * In each category, rank them from strictly-structured to + * loosely-structured. + */ +int getFlatTypeRank(std::u16string_view rType) +{ + // List formats from more complex to less complex. + // TODO: Add more. + static const char* ranks[] = { + + // Compressed XML (ODF XML zip formats) + "writer8_template", + "writer8", + "calc8_template", + "calc8", + "impress8_template", + "impress8", + "draw8_template", + "draw8", + "chart8", + "math8", + "writerglobal8_template", + "writerglobal8", + "writerweb8_writer_template", + "StarBase", + + // Compressed XML (OOXML) + "writer_OOXML_Text_Template", + "writer_OOXML", + "writer_MS_Word_2007_Template", + "writer_MS_Word_2007", + "Office Open XML Spreadsheet Template", + "Office Open XML Spreadsheet", + "MS Excel 2007 XML Template", + "MS Excel 2007 XML", + "MS PowerPoint 2007 XML Template", + "MS PowerPoint 2007 XML AutoPlay", + "MS PowerPoint 2007 XML", + + // Compressed XML (Uniform/Unified Office Format) + "Unified_Office_Format_text", + "Unified_Office_Format_spreadsheet", + "Unified_Office_Format_presentation", + + // Compressed XML (StarOffice XML zip formats) + "calc_StarOffice_XML_Calc", + "calc_StarOffice_XML_Calc_Template", + "chart_StarOffice_XML_Chart", + "draw_StarOffice_XML_Draw", + "draw_StarOffice_XML_Draw_Template", + "impress_StarOffice_XML_Impress", + "impress_StarOffice_XML_Impress_Template", + "math_StarOffice_XML_Math", + "writer_StarOffice_XML_Writer", + "writer_StarOffice_XML_Writer_Template", + "writer_globaldocument_StarOffice_XML_Writer_GlobalDocument", + "writer_web_StarOffice_XML_Writer_Web_Template", + + // Compressed text + "pdf_Portable_Document_Format", + + // Binary + "writer_T602_Document", + "writer_WordPerfect_Document", + "writer_MS_Works_Document", + "writer_MS_Word_97_Vorlage", + "writer_MS_Word_97", + "writer_MS_Word_95_Vorlage", + "writer_MS_Word_95", + "writer_MS_WinWord_60", + "writer_MS_WinWord_5", + "MS Excel 2007 Binary", + "calc_MS_Excel_97_VorlageTemplate", + "calc_MS_Excel_97", + "calc_MS_Excel_95_VorlageTemplate", + "calc_MS_Excel_95", + "calc_MS_Excel_5095_VorlageTemplate", + "calc_MS_Excel_5095", + "calc_MS_Excel_40_VorlageTemplate", + "calc_MS_Excel_40", + "calc_Pocket_Excel_File", + "impress_MS_PowerPoint_97_Vorlage", + "impress_MS_PowerPoint_97_AutoPlay", + "impress_MS_PowerPoint_97", + "calc_Lotus", + "calc_QPro", + "calc_SYLK", + "calc_DIF", + "calc_dBase", + + // Binary (raster and vector image files) + "emf_MS_Windows_Metafile", + "wmf_MS_Windows_Metafile", + "met_OS2_Metafile", + "svm_StarView_Metafile", + "sgv_StarDraw_20", + "tif_Tag_Image_File", + "tga_Truevision_TARGA", + "sgf_StarOffice_Writer_SGF", + "ras_Sun_Rasterfile", + "psd_Adobe_Photoshop", + "png_Portable_Network_Graphic", + "jpg_JPEG", + "mov_MOV", + "gif_Graphics_Interchange", + "bmp_MS_Windows", + "pcx_Zsoft_Paintbrush", + "pct_Mac_Pict", + "pcd_Photo_CD_Base", + "pcd_Photo_CD_Base4", + "pcd_Photo_CD_Base16", + "webp_WebP", + "impress_CGM_Computer_Graphics_Metafile", // There is binary and ascii variants ? + "draw_WordPerfect_Graphics", + "draw_Visio_Document", + "draw_Publisher_Document", + "draw_Corel_Presentation_Exchange", + "draw_CorelDraw_Document", + "writer_LotusWordPro_Document", + "writer_MIZI_Hwp_97", // Hanword (Hancom Office) + + // Non-compressed XML + "writer_ODT_FlatXML", + "calc_ODS_FlatXML", + "impress_ODP_FlatXML", + "draw_ODG_FlatXML", + "calc_ADO_rowset_XML", + "calc_MS_Excel_2003_XML", + "writer_MS_Word_2003_XML", + "writer_DocBook_File", + "XHTML_File", + "svg_Scalable_Vector_Graphics", + "math_MathML_XML_Math", + + // Non-compressed text + "dxf_AutoCAD_Interchange", + "eps_Encapsulated_PostScript", + "pbm_Portable_Bitmap", // There is 'raw' and 'ascii' variants. + "ppm_Portable_Pixelmap", // There is 'raw' and 'ascii' variants. + "pgm_Portable_Graymap", // There is 'raw' and 'ascii' variants. + "xpm_XPM", + "xbm_X_Consortium", + "writer_Rich_Text_Format", + "writer_web_HTML_help", + "generic_HTML", + + "generic_Text", // Plain text (catch all) + + // Anything ranked lower than generic_Text will never be used during + // type detection (since generic_Text catches all). + + // Export only + "writer_layout_dump_xml", + "writer_indexing_export", + "graphic_HTML", + + // Internal use only + "StarBaseReportChart", + "StarBaseReport", + "math_MathType_3x", // MathType equation embedded in Word doc. + }; + + size_t n = SAL_N_ELEMENTS(ranks); + + for (size_t i = 0; i < n; ++i) + { + if (o3tl::equalsAscii(rType, ranks[i])) + return n - i - 1; + } + + // Not ranked. Treat them equally. Unranked formats have higher priority + // than the ranked internal ones since they may be defined externally. + return n; +} + +/** + * Types with matching pattern first, then extension, then custom ranks by + * types, then types that are supported by the document service come next. + * Lastly, sort them alphabetically. + */ +struct SortByPriority +{ + bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const + { + if (r1.bMatchByPattern != r2.bMatchByPattern) + return r1.bMatchByPattern; + + if (r1.bMatchByExtension != r2.bMatchByExtension) + return r1.bMatchByExtension; + + int rank1 = getFlatTypeRank(r1.sType); + int rank2 = getFlatTypeRank(r2.sType); + + if (rank1 != rank2) + return rank1 > rank2; + + if (r1.bPreselectedByDocumentService != r2.bPreselectedByDocumentService) + return r1.bPreselectedByDocumentService; + + // All things being equal, sort them alphabetically. + return r1.sType > r2.sType; + } +}; + +struct SortByType +{ + bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const + { + return r1.sType > r2.sType; + } +}; + +struct EqualByType +{ + bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const + { + return r1.sType == r2.sType; + } +}; + +class FindByType +{ + OUString maType; +public: + explicit FindByType(OUString aType) : maType(std::move(aType)) {} + bool operator() (const FlatDetectionInfo& rInfo) const + { + return rInfo.sType == maType; + } +}; + +#if DEBUG_TYPE_DETECTION +void printFlatDetectionList(const char* caption, const FlatDetection& types) +{ + cout << "-- " << caption << " (size=" << types.size() << ")" << endl; + for (auto const& item : types) + { + cout << " type='" << item.sType << "'; match by extension (" << item.bMatchByExtension + << "); match by pattern (" << item.bMatchByPattern << "); pre-selected by doc service (" + << item.bPreselectedByDocumentService << ")" << endl; + } + cout << "--" << endl; +} +#endif + +} + +OUString SAL_CALL TypeDetection::queryTypeByDescriptor(css::uno::Sequence< css::beans::PropertyValue >& lDescriptor, + sal_Bool bAllowDeep ) +{ + // make the descriptor more usable :-) + utl::MediaDescriptor stlDescriptor(lDescriptor); + OUString sType, sURL; + + try + { + // SAFE -> ---------------------------------- + osl::ClearableMutexGuard aLock(m_aMutex); + + // parse given URL to split it into e.g. main and jump marks ... + sURL = stlDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL, OUString()); + +#if OSL_DEBUG_LEVEL > 0 + if (stlDescriptor.find( "FileName" ) != stlDescriptor.end()) + OSL_FAIL("Detect using of deprecated and already unsupported MediaDescriptor property \"FileName\"!"); +#endif + + css::util::URL aURL; + aURL.Complete = sURL; + css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext)); + xParser->parseStrict(aURL); + + OUString aSelectedFilter = stlDescriptor.getUnpackedValueOrDefault( + utl::MediaDescriptor::PROP_FILTERNAME, OUString()); + if (!aSelectedFilter.isEmpty()) + { + // Caller specified the filter type. Honor it. Just get the default + // type for that filter, and bail out. + if (impl_validateAndSetFilterOnDescriptor(stlDescriptor, aSelectedFilter)) + return stlDescriptor[utl::MediaDescriptor::PROP_TYPENAME].get(); + } + + FlatDetection lFlatTypes; + impl_getAllFormatTypes(aURL, stlDescriptor, lFlatTypes); + + aLock.clear(); + // <- SAFE ---------------------------------- + + // Properly prioritize all candidate types. + std::stable_sort(lFlatTypes.begin(), lFlatTypes.end(), SortByPriority()); + auto last = std::unique(lFlatTypes.begin(), lFlatTypes.end(), EqualByType()); + lFlatTypes.erase(last, lFlatTypes.end()); + + OUString sLastChance; + + // verify every flat detected (or preselected!) type + // by calling its registered deep detection service. + // But break this loop if a type match to the given descriptor + // by a URL pattern(!) or if deep detection isn't allowed from + // outside (bAllowDeep=sal_False) or break the whole detection by + // throwing an exception if creation of the might needed input + // stream failed by e.g. an IO exception ... + if (!lFlatTypes.empty()) + sType = impl_detectTypeFlatAndDeep(stlDescriptor, lFlatTypes, bAllowDeep, sLastChance); + + // flat detection failed + // pure deep detection failed + // => ask might existing InteractionHandler + // means: ask user for its decision + if (sType.isEmpty() && !m_bCancel) + sType = impl_askUserForTypeAndFilterIfAllowed(stlDescriptor); + + + // no real detected type - but a might valid one. + // update descriptor and set last chance for return. + if (sType.isEmpty() && !sLastChance.isEmpty() && !m_bCancel) + { + OSL_FAIL("set first flat detected type without a registered deep detection service as \"last chance\" ... nevertheless some other deep detections said \"NO\". I TRY IT!"); + sType = sLastChance; + } + } + catch(const css::uno::RuntimeException&) + { + throw; + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("filter.config", "caught exception while querying type of " << sURL); + sType.clear(); + } + + // adapt media descriptor, so it contains the right values + // for type/filter name/document service/ etcpp. + impl_checkResultsAndAddBestFilter(stlDescriptor, sType); // Attention: sType is used as IN/OUT param here and will might be changed inside this method !!! + impl_validateAndSetTypeOnDescriptor(stlDescriptor, sType); + + stlDescriptor >> lDescriptor; + return sType; +} + + +void TypeDetection::impl_checkResultsAndAddBestFilter(utl::MediaDescriptor& rDescriptor, + OUString& sType ) +{ + // a) + // Don't overwrite a might preselected filter! + OUString sFilter = rDescriptor.getUnpackedValueOrDefault( + utl::MediaDescriptor::PROP_FILTERNAME, + OUString()); + if (!sFilter.isEmpty()) + return; + + auto & cache = GetTheFilterCache(); + + // b) + // check a preselected document service too. + // Then we have to search a suitable filter within this module. + OUString sDocumentService = rDescriptor.getUnpackedValueOrDefault( + utl::MediaDescriptor::PROP_DOCUMENTSERVICE, + OUString()); + if (!sDocumentService.isEmpty()) + { + try + { + OUString sRealType = sType; + + // SAFE -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + // Attention: For executing next lines of code, We must be sure that + // all filters already loaded :-( + // That can disturb our "load on demand feature". But we have no other chance! + cache.load(FilterCache::E_CONTAINS_FILTERS); + + css::beans::NamedValue lIProps[] { + { PROPNAME_DOCUMENTSERVICE, uno::Any(sDocumentService) }, + { PROPNAME_TYPE, uno::Any(sRealType) } }; + std::vector lFilters = cache.getMatchingItemsByProps(FilterCache::E_FILTER, lIProps); + + aLock.clear(); + // <- SAFE + + for (auto const& filter : lFilters) + { + // SAFE -> + aLock.reset(); + try + { + CacheItem aFilter = cache.getItem(FilterCache::E_FILTER, filter); + sal_Int32 nFlags = 0; + aFilter[PROPNAME_FLAGS] >>= nFlags; + + if (static_cast(nFlags) & SfxFilterFlags::IMPORT) + sFilter = filter; + if (static_cast(nFlags) & SfxFilterFlags::PREFERED) + break; + } + catch(const css::uno::Exception&) {} + aLock.clear(); + // <- SAFE + } + + if (!sFilter.isEmpty()) + { + rDescriptor[utl::MediaDescriptor::PROP_TYPENAME ] <<= sRealType; + rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter; + sType = sRealType; + return; + } + } + catch(const css::uno::Exception&) + {} + } + + // c) + // We can use the preferred filter for the specified type. + // Such preferred filter points: + // - to the default filter of the preferred application + // - or to any other filter if no preferred filter was set. + // Note: It's an optimization only! + // It's not guaranteed, that such preferred filter exists. + sFilter.clear(); + try + { + // SAFE -> + osl::ClearableMutexGuard aLock(m_aMutex); + + CacheItem aType = cache.getItem(FilterCache::E_TYPE, sType); + aType[PROPNAME_PREFERREDFILTER] >>= sFilter; + cache.getItem(FilterCache::E_FILTER, sFilter); + + aLock.clear(); + // <- SAFE + + // no exception => found valid type and filter => set it on the given descriptor + rDescriptor[utl::MediaDescriptor::PROP_TYPENAME ] <<= sType ; + rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter; + return; + } + catch(const css::uno::Exception&) + {} + + // d) + // Search for any import(!) filter, which is registered for this type. + sFilter.clear(); + try + { + // SAFE -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + + // Attention: For executing next lines of code, We must be sure that + // all filters already loaded :-( + // That can disturb our "load on demand feature". But we have no other chance! + cache.load(FilterCache::E_CONTAINS_FILTERS); + + css::beans::NamedValue lIProps[] { + { PROPNAME_TYPE, uno::Any(sType) } }; + std::vector lFilters = cache.getMatchingItemsByProps(FilterCache::E_FILTER, lIProps); + + aLock.clear(); + // <- SAFE + + for (auto const& filter : lFilters) + { + sFilter = filter; + + // SAFE -> + aLock.reset(); + try + { + CacheItem aFilter = cache.getItem(FilterCache::E_FILTER, sFilter); + sal_Int32 nFlags = 0; + aFilter[PROPNAME_FLAGS] >>= nFlags; + + if (static_cast(nFlags) & SfxFilterFlags::IMPORT) + break; + } + catch(const css::uno::Exception&) + { continue; } + aLock.clear(); + // <- SAFE + + sFilter.clear(); + } + + if (!sFilter.isEmpty()) + { + rDescriptor[utl::MediaDescriptor::PROP_TYPENAME ] <<= sType ; + rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter; + return; + } + } + catch(const css::uno::Exception&) + {} +} + + +bool TypeDetection::impl_getPreselectionForType( + const OUString& sPreSelType, const util::URL& aParsedURL, FlatDetection& rFlatTypes, bool bDocService) +{ + // Can be used to suppress execution of some parts of this method + // if it's already clear that detected type is valid or not. + // It's necessary to use shared code at the end, which update + // all return parameters consistency! + bool bBreakDetection = false; + + // Further we must know if it matches by pattern + // Every flat detected type by pattern won't be detected deep! + bool bMatchByPattern = false; + + // And we must know if a preselection must be preferred, because + // it matches by its extension too. + bool bMatchByExtension = false; + + // validate type + OUString sType(sPreSelType); + CacheItem aType; + try + { + // SAFE -> -------------------------- + osl::MutexGuard aLock(m_aMutex); + aType = GetTheFilterCache().getItem(FilterCache::E_TYPE, sType); + // <- SAFE -------------------------- + } + catch(const css::container::NoSuchElementException&) + { + sType.clear(); + bBreakDetection = true; + } + + if (!bBreakDetection) + { + // We can't check a preselected type for a given stream! + // So we must believe, that it can work ... + if ( aParsedURL.Complete == "private:stream" ) + bBreakDetection = true; + } + + if (!bBreakDetection) + { + // extract extension from URL .. to check it case-insensitive ! + INetURLObject aParser (aParsedURL.Main); + OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT , + true , + INetURLObject::DecodeMechanism::WithCharset); + sExtension = sExtension.toAsciiLowerCase(); + + // otherwise we must know, if it matches to the given URL really. + // especially if it matches by its extension or pattern registration. + const css::uno::Sequence lExtensions = aType[PROPNAME_EXTENSIONS].get >(); + const css::uno::Sequence lURLPattern = aType[PROPNAME_URLPATTERN].get >(); + + for (auto const& extension : lExtensions) + { + OUString sCheckExtension(extension.toAsciiLowerCase()); + if (sCheckExtension == sExtension) + { + bBreakDetection = true; + bMatchByExtension = true; + break; + } + } + + if (!bBreakDetection) + { + for (auto const& elem : lURLPattern) + { + WildCard aCheck(elem); + if (aCheck.Matches(aParsedURL.Main)) + { + bMatchByPattern = true; + break; + } + } + } + } + + // if it's a valid type - set it on all return values! + if (!sType.isEmpty()) + { + FlatDetection::iterator it = std::find_if(rFlatTypes.begin(), rFlatTypes.end(), FindByType(sType)); + if (it != rFlatTypes.end()) + { + if (bMatchByExtension) + it->bMatchByExtension = true; + if (bMatchByPattern) + it->bMatchByPattern = true; + if (bDocService) + it->bPreselectedByDocumentService = true; + } + + return true; + } + + // not valid! + return false; +} + +void TypeDetection::impl_getPreselectionForDocumentService( + const OUString& sPreSelDocumentService, const util::URL& aParsedURL, FlatDetection& rFlatTypes) +{ + // get all filters, which match to this doc service + std::vector lFilters; + try + { + // SAFE -> -------------------------- + osl::MutexGuard aLock(m_aMutex); + + // Attention: For executing next lines of code, We must be sure that + // all filters already loaded :-( + // That can disturb our "load on demand feature". But we have no other chance! + auto & cache = GetTheFilterCache(); + cache.load(FilterCache::E_CONTAINS_FILTERS); + + css::beans::NamedValue lIProps[] { + { PROPNAME_DOCUMENTSERVICE, css::uno::Any(sPreSelDocumentService) } }; + lFilters = cache.getMatchingItemsByProps(FilterCache::E_FILTER, lIProps); + // <- SAFE -------------------------- + } + catch (const css::container::NoSuchElementException&) + { + lFilters.clear(); + } + + // step over all filters, and check if its registered type + // match the given URL. + // But use temp. list of "preselected types" instead of incoming rFlatTypes list! + // The reason behind: we must filter the obtained results. And copying stl entries + // is an easier job than removing them .-) + for (auto const& filter : lFilters) + { + OUString aType = impl_getTypeFromFilter(filter); + if (aType.isEmpty()) + continue; + + impl_getPreselectionForType(aType, aParsedURL, rFlatTypes, true); + } +} + +OUString TypeDetection::impl_getTypeFromFilter(const OUString& rFilterName) +{ + CacheItem aFilter; + try + { + osl::MutexGuard aLock(m_aMutex); + aFilter = GetTheFilterCache().getItem(FilterCache::E_FILTER, rFilterName); + } + catch (const container::NoSuchElementException&) + { + return OUString(); + } + + OUString aType; + aFilter[PROPNAME_TYPE] >>= aType; + return aType; +} + +void TypeDetection::impl_getAllFormatTypes( + const util::URL& aParsedURL, utl::MediaDescriptor const & rDescriptor, FlatDetection& rFlatTypes) +{ + rFlatTypes.clear(); + + // Get all filters that we have. + std::vector aFilterNames; + try + { + osl::MutexGuard aLock(m_aMutex); + auto & cache = GetTheFilterCache(); + cache.load(FilterCache::E_CONTAINS_FILTERS); + aFilterNames = cache.getItemNames(FilterCache::E_FILTER); + } + catch (const container::NoSuchElementException&) + { + return; + } + + // Retrieve the default type for each of these filters, and store them. + for (auto const& filterName : aFilterNames) + { + OUString aType = impl_getTypeFromFilter(filterName); + + if (aType.isEmpty()) + continue; + + FlatDetectionInfo aInfo; // all flags set to false by default. + aInfo.sType = aType; + rFlatTypes.push_back(aInfo); + } + + { + // Get all types that match the URL alone. + FlatDetection aFlatByURL; + GetTheFilterCache().detectFlatForURL(aParsedURL, aFlatByURL); + for (auto const& elem : aFlatByURL) + { + FlatDetection::iterator itPos = std::find_if(rFlatTypes.begin(), rFlatTypes.end(), FindByType(elem.sType)); + if (itPos == rFlatTypes.end()) + // Not in the list yet. + rFlatTypes.push_back(elem); + else + { + // Already in the list. Update the flags. + FlatDetectionInfo& rInfo = *itPos; + const FlatDetectionInfo& rThisInfo = elem; + if (rThisInfo.bMatchByExtension) + rInfo.bMatchByExtension = true; + if (rThisInfo.bMatchByPattern) + rInfo.bMatchByPattern = true; + if (rThisInfo.bPreselectedByDocumentService) + rInfo.bPreselectedByDocumentService = true; + } + } + } + + // Remove duplicates. + std::stable_sort(rFlatTypes.begin(), rFlatTypes.end(), SortByType()); + auto last = std::unique(rFlatTypes.begin(), rFlatTypes.end(), EqualByType()); + rFlatTypes.erase(last, rFlatTypes.end()); + + // Mark pre-selected type (if any) to have it prioritized. + OUString sSelectedType = rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME, OUString()); + if (!sSelectedType.isEmpty()) + impl_getPreselectionForType(sSelectedType, aParsedURL, rFlatTypes, false); + + // Mark all types preferred by the current document service, to have it prioritized. + OUString sSelectedDoc = rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, OUString()); + if (!sSelectedDoc.isEmpty()) + impl_getPreselectionForDocumentService(sSelectedDoc, aParsedURL, rFlatTypes); +} + + +OUString TypeDetection::impl_detectTypeFlatAndDeep( utl::MediaDescriptor& rDescriptor , + const FlatDetection& lFlatTypes , + bool bAllowDeep , + OUString& rLastChance ) +{ + // reset it everytimes, so the outside code can distinguish between + // a set and a not set value. + rLastChance.clear(); + + // step over all possible types for this URL. + // solutions: + // a) no types => no detection + // b) deep detection not allowed => return first valid type of list (because it's the preferred or the first valid one) + // or(!) match by URLPattern => in such case a deep detection will be suppressed! + // c) type has no detect service => safe the first occurred type without a detect service + // as "last chance"(!). It will be used outside of this method + // if no further type could be detected. + // It must be the first one, because it can be a preferred type. + // Our types list was sorted by such criteria! + // d) detect service return a valid result => return its decision + // e) detect service return an invalid result + // or any needed information could not be + // obtained from the cache => ignore it, and continue with search + + for (auto const& flatTypeInfo : lFlatTypes) + { + if (m_bCancel) + break; + OUString sFlatType = flatTypeInfo.sType; + + if (!impl_validateAndSetTypeOnDescriptor(rDescriptor, sFlatType)) + continue; + + // b) + if ( + (!bAllowDeep ) || + (flatTypeInfo.bMatchByPattern) + ) + { + return sFlatType; + } + + try + { + // SAFE -> ---------------------------------- + osl::ClearableMutexGuard aLock(m_aMutex); + CacheItem aType = GetTheFilterCache().getItem(FilterCache::E_TYPE, sFlatType); + aLock.clear(); + + OUString sDetectService; + aType[PROPNAME_DETECTSERVICE] >>= sDetectService; + + // c) + if (sDetectService.isEmpty()) + { + // flat detected types without any registered deep detection service and not + // preselected by the user can be used as LAST CHANCE in case no other type could + // be detected. Of course only the first type without deep detector can be used. + // Further ones has to be ignored. + if (rLastChance.isEmpty()) + rLastChance = sFlatType; + + continue; + } + + OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor); + + // d) + if (!sDeepType.isEmpty()) + return sDeepType; + } + catch(const css::container::NoSuchElementException&) + {} + // e) + } + + return OUString(); + // <- SAFE ---------------------------------- +} + +void TypeDetection::impl_seekStreamToZero(utl::MediaDescriptor const & rDescriptor) +{ + // try to seek to 0 ... + // But because XSeekable is an optional interface ... try it only .-) + css::uno::Reference< css::io::XInputStream > xStream = rDescriptor.getUnpackedValueOrDefault( + utl::MediaDescriptor::PROP_INPUTSTREAM, + css::uno::Reference< css::io::XInputStream >()); + css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY); + if (!xSeek.is()) + return; + + try + { + xSeek->seek(0); + } + catch(const css::uno::RuntimeException&) + { + throw; + } + catch(const css::uno::Exception&) + { + } +} + +OUString TypeDetection::impl_askDetectService(const OUString& sDetectService, + utl::MediaDescriptor& rDescriptor ) +{ + // Open the stream and add it to the media descriptor if this method is called for the first time. + // All following requests to this method will detect, that there already exists a stream .-) + // Attention: This method throws an exception if the stream could not be opened. + // It's important to break any further detection in such case. + // Catch it on the highest detection level only !!! + impl_openStream(rDescriptor); + + // seek to 0 is an optional feature to be more robust against + // "simple implemented detect services" .-) + impl_seekStreamToZero(rDescriptor); + + css::uno::Reference< css::document::XExtendedFilterDetection > xDetector; + css::uno::Reference< css::uno::XComponentContext > xContext; + + // SAFE -> + { + osl::MutexGuard aLock(m_aMutex); + xContext = m_xContext; + } + // <- SAFE + + try + { + // Attention! If e.g. an office module was not installed sometimes we + // find a registered detect service, which is referred inside the + // configuration ... but not really installed. On the other side we use + // third party components here, which can make trouble anyway. So we + // should handle errors during creation of such services more + // gracefully .-) + xDetector.set( + xContext->getServiceManager()->createInstanceWithContext(sDetectService, xContext), + css::uno::UNO_QUERY_THROW); + } + catch (...) + { + } + + if ( ! xDetector.is()) + return OUString(); + + OUString sDeepType; + try + { + // start deep detection + // Don't forget to convert stl descriptor to its uno representation. + + /* Attention! + You have to use an explicit instance of this uno sequence... + Because it's used as an in out parameter. And in case of a temp. used object + we will run into memory corruptions! + */ + css::uno::Sequence< css::beans::PropertyValue > lDescriptor; + rDescriptor >> lDescriptor; + sDeepType = xDetector->detect(lDescriptor); + rDescriptor << lDescriptor; + } + catch (...) + { + // We should ignore errors here. + // Thrown exceptions mostly will end in crash recovery... + // But might be we find another deep detection service which can detect the same + // document without a problem .-) + sDeepType.clear(); + } + + // seek to 0 is an optional feature to be more robust against + // "simple implemented detect services" .-) + impl_seekStreamToZero(rDescriptor); + + // analyze the results + // a) detect service returns "" => return "" too and remove TYPE/FILTER prop from descriptor + // b) returned type is unknown => return "" too and remove TYPE/FILTER prop from descriptor + // c) returned type is valid => check TYPE/FILTER props inside descriptor and return the type + + // this special helper checks for a valid type + // and set right values on the descriptor! + bool bValidType = impl_validateAndSetTypeOnDescriptor(rDescriptor, sDeepType); + if (bValidType) + return sDeepType; + + return OUString(); +} + + +OUString TypeDetection::impl_askUserForTypeAndFilterIfAllowed(utl::MediaDescriptor& rDescriptor) +{ + css::uno::Reference< css::task::XInteractionHandler > xInteraction = + rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_INTERACTIONHANDLER, + css::uno::Reference< css::task::XInteractionHandler >()); + + if (!xInteraction.is()) + return OUString(); + + OUString sURL = + rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL, + OUString()); + + css::uno::Reference< css::io::XInputStream > xStream = + rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_INPUTSTREAM, + css::uno::Reference< css::io::XInputStream >()); + + // Don't disturb the user for "non existing files - means empty URLs" or + // if we were forced to detect a stream. + // Reason behind: we must be sure to ask user for "unknown contents" only... + // and not for "missing files". Especially if detection is done by a stream only + // we can't check if the stream points to an "existing content"! + if ( + (sURL.isEmpty() ) || // "non existing file" ? + (!xStream.is() ) || // non existing file ! + (sURL.equalsIgnoreAsciiCase("private:stream")) // not a good idea .-) + ) + return OUString(); + + try + { + // create a new request to ask user for its decision about the usable filter + ::framework::RequestFilterSelect aRequest(sURL); + xInteraction->handle(aRequest.GetRequest()); + + // "Cancel" pressed? => return with error + if (aRequest.isAbort()) + return OUString(); + + // "OK" pressed => verify the selected filter, get its corresponding + // type and return it. (BTW: We must update the media descriptor here ...) + // The user selected explicitly a filter ... but normally we are interested on + // a type here only. But we must be sure, that the selected filter is used + // too and no ambiguous filter registration disturb us .-) + + OUString sFilter = aRequest.getFilter(); + if (!impl_validateAndSetFilterOnDescriptor(rDescriptor, sFilter)) + return OUString(); + + OUString sType; + rDescriptor[utl::MediaDescriptor::PROP_TYPENAME] >>= sType; + return sType; + } + catch(const css::uno::Exception&) + {} + + return OUString(); +} + + +void TypeDetection::impl_openStream(utl::MediaDescriptor& rDescriptor) +{ + bool bSuccess = false; + OUString sURL = rDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_URL, OUString() ); + bool bRequestedReadOnly = rDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_READONLY, false ); + if ( comphelper::isFileUrl( sURL ) ) + { + // OOo uses own file locking mechanics in case of local file + bSuccess = rDescriptor.addInputStreamOwnLock(); + } + else + bSuccess = rDescriptor.addInputStream(); + + if ( !bSuccess ) + throw css::uno::Exception( + "Could not open stream for <" + sURL + ">", + static_cast(this)); + + if ( !bRequestedReadOnly ) + { + // The MediaDescriptor implementation adds ReadOnly argument if the file can not be opened for writing + // this argument should be either removed or an additional argument should be added so that application + // can separate the case when the user explicitly requests readonly document. + // The current solution is to remove it here. + rDescriptor.erase( utl::MediaDescriptor::PROP_READONLY ); + } +} + + +void TypeDetection::impl_removeTypeFilterFromDescriptor(utl::MediaDescriptor& rDescriptor) +{ + utl::MediaDescriptor::iterator pItType = rDescriptor.find(utl::MediaDescriptor::PROP_TYPENAME ); + utl::MediaDescriptor::iterator pItFilter = rDescriptor.find(utl::MediaDescriptor::PROP_FILTERNAME); + if (pItType != rDescriptor.end()) + rDescriptor.erase(pItType); + if (pItFilter != rDescriptor.end()) + rDescriptor.erase(pItFilter); +} + + +bool TypeDetection::impl_validateAndSetTypeOnDescriptor( utl::MediaDescriptor& rDescriptor, + const OUString& sType ) +{ + // SAFE -> + { + osl::MutexGuard aLock(m_aMutex); + if (GetTheFilterCache().hasItem(FilterCache::E_TYPE, sType)) + { + rDescriptor[utl::MediaDescriptor::PROP_TYPENAME] <<= sType; + return true; + } + } + // <- SAFE + + // remove all related information from the descriptor + impl_removeTypeFilterFromDescriptor(rDescriptor); + return false; +} + + +bool TypeDetection::impl_validateAndSetFilterOnDescriptor( utl::MediaDescriptor& rDescriptor, + const OUString& sFilter ) +{ + try + { + // SAFE -> + osl::ClearableMutexGuard aLock(m_aMutex); + + auto & cache = GetTheFilterCache(); + CacheItem aFilter = cache.getItem(FilterCache::E_FILTER, sFilter); + OUString sType; + aFilter[PROPNAME_TYPE] >>= sType; + + aLock.clear(); + // <- SAFE + + // found valid type and filter => set it on the given descriptor + rDescriptor[utl::MediaDescriptor::PROP_TYPENAME ] <<= sType ; + rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter; + return true; + } + catch(const css::container::NoSuchElementException&){} + + // remove all related information from the descriptor + impl_removeTypeFilterFromDescriptor(rDescriptor); + return false; +} + +} // namespace filter + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_TypeDetection_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new filter::config::TypeDetection(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/cache/typedetection.hxx b/filter/source/config/cache/typedetection.hxx new file mode 100644 index 000000000..114410392 --- /dev/null +++ b/filter/source/config/cache/typedetection.hxx @@ -0,0 +1,350 @@ +/* -*- 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 . + */ +#pragma once + +#include "basecontainer.hxx" +#include +#include +#include +#include +#include +#include + +namespace filter::config { + +class TerminateDetection; + +/** @short implements the service TypeDetection. + */ +class TypeDetection : public ::cppu::ImplInheritanceHelper< BaseContainer , + css::document::XTypeDetection > +{ + +// native interface + + css::uno::Reference< css::uno::XComponentContext > m_xContext; + rtl::Reference m_xTerminateListener; + bool m_bCancel; + +public: + + + // ctor/dtor + + /** @short standard ctor to connect this interface wrapper to + the global filter cache instance ... + + @param rxContext + reference to the uno service manager, which created this service instance. + */ + explicit TypeDetection(const css::uno::Reference< css::uno::XComponentContext >& rxContext); + + void cancel() + { + m_bCancel = true; + } + + + /** @short standard dtor. + */ + virtual ~TypeDetection() override; + + +// private helper + +private: + + bool impl_getPreselectionForType( + const OUString& sPreSelType, const css::util::URL& aParsedURL, FlatDetection& rFlatTypes, bool bDocService); + + void impl_getPreselectionForDocumentService( + const OUString& sPreSelDocumentService, const css::util::URL& aParsedURL, FlatDetection& rFlatTypes); + + OUString impl_getTypeFromFilter(const OUString& rFilterName); + + /** + * Get all format types that we handle. + */ + void impl_getAllFormatTypes( + const css::util::URL& aParsedURL, utl::MediaDescriptor const & rDescriptor, + FlatDetection& rFlatTypes); + + + /** @short make a combined flat/deep type detection + + @descr It steps over all flat detected types (given by the parameter lFlatTypes), + try it and search for most suitable one. + The specified MediaDescriptor will be patched, so it contain + the right values every time. Using of any deep detection service + can be enabled/disabled. And last but not least: If the results + won't be really clear (because a flat detected type has no deep + detection service), a "suggested" type name will be returned as "rLastChance". + It can be used after e.g. all well known deep detection services + was used without getting any result. Then this "last-chance-type" + should be returned. Of course using of it can fail too ... but it's a try :-) + + @param rDescriptor + provides any easy-to-use stl interface to the MediaDescriptor. + Note : Its content will be adapted to returned result of this method. + Means: The type/filter entries of it will be actualized or removed from it. + + @param lFlatTypes + a list of all flat detected types, which should be checked here. + No other types are allowed here! + + @param rLastChance + the internal name of a "suggested type" ... (see before) + Note: it will be reset to an empty string every time. So + a set value of "rLastChance" can be detected outside very easy. + + @param bAllowDeep + enable/disable using of a might existing deep detection service. + + @return The internal name of a detected type. + An empty value if detection failed. ... but see rLastChance + for additional returns! + */ + OUString impl_detectTypeFlatAndDeep( utl::MediaDescriptor& rDescriptor , + const FlatDetection& lFlatTypes , + bool bAllowDeep , + OUString& rLastChance ); + + + /** @short seek a might existing stream to position 0. + + @descr This is an optional action to be more robust + in case any detect service doesn't make this seek... + Normally it's part of any called detect service or filter... + but sometimes it's not done there. + + @param rDescriptor + a stl representation of the MediaDescriptor as in/out parameter. + */ + static void impl_seekStreamToZero(utl::MediaDescriptor const & rDescriptor); + + + /** @short make deep type detection for a specified + detect service (threadsafe!). + + @descr It creates the right uno service, prepare the + needed MediaDescriptor, call the right interfaces, + and return the results. + + @attention The results (means type and corresponding filter) + are already part of the in/out parameter pDescriptor. + (in case they were valid). + + @param sDetectService + uno service name of the detect service. + + @param rDescriptor + a stl representation of the MediaDescriptor as in/out parameter. + */ + OUString impl_askDetectService(const OUString& sDetectService, + utl::MediaDescriptor& rDescriptor ); + + + /** @short try to find an interaction handler and + ask him to select a possible filter for + this unknown format. + + @descr If the user select a filter, it will be used as return value + without further checking against the given file content! + + @param rDescriptor + a stl representation of the MediaDescriptor as in/out parameter. + + @return [string] + a valid type name or an empty string if user canceled interaction. + */ + OUString impl_askUserForTypeAndFilterIfAllowed(utl::MediaDescriptor& rDescriptor); + + + /** @short check if an input stream is already part of the + given MediaDescriptor and creates a new one if necessary. + + @attention This method does further something special! +
    +
  • + If the given URL seem to be a streamable content, but creation of the stream + failed (might by an IOException), this method throws an exception. + (May be an existing interaction handler must be called here too ...) + The whole detection must be interrupted then and the interface method queryTypeByDescriptor() + must return an empty type name value. + + That prevent us against multiple handling of the same error more than ones + (e.g. if we ask all detect services as fallback ...). +
  • +
  • + In case the stream already exists inside the descriptor this method does nothing. +
  • +
  • + In case the stream does not exists but can be created successfully, the stream will + be added to the descriptor. +
  • +
+ + @param rDescriptor + provides any easy-to-use stl interface to the MediaDescriptor. + Note : Its content will be adapted to returned result of this method. + Means: The stream will be added to it. + + @throw Any suitable exception if stream should be opened but operation was not successful. + Note: If an interactionHandler is part of the given descriptor too, it was already used. + Means: let the exception pass through the top most interface method! + */ + void impl_openStream(utl::MediaDescriptor& rDescriptor); + + + /** @short validate the specified type and its relationships + and set all needed information related to this type + in the specified descriptor. + + @descr Related information are: - corresponding filter + - media type + - ... + + @param rDescriptor + provides access to the outside MediaDescriptor. + + @param sType + the name of the type, which should be set on the descriptor. + Can be empty to remove any related value from the descriptor! + + @return TRUE the specified type and its registrations was valid(!) and + could be set on the descriptor. + */ + bool impl_validateAndSetTypeOnDescriptor( utl::MediaDescriptor& rDescriptor, + const OUString& sType ); + + + /** @short validate the specified filter and its relationships + and set all needed information related to this filter + in the specified descriptor. + + @descr Related information are: - corresponding type + - ... + + @param rDescriptor + provides access to the outside MediaDescriptor. + + @param sFilter + the name of the filter, which should be set on the descriptor. + Can be empty to remove any related value from the descriptor! + + @return TRUE the specified type and its registrations was valid(!) and + could be set on the descriptor. + */ + bool impl_validateAndSetFilterOnDescriptor( utl::MediaDescriptor& rDescriptor, + const OUString& sFilter ); + + + /** @short remove anything related to a TYPE/FILTER entry from the + specified MediaDescriptor. + + @descr This method works together with impl_validateAndSetTypeOnDescriptor()/ + impl_validateAndSetFilterOnDescriptor(). All information, which can be + set by these two operations must be "removable" by this method. + + @param rDescriptor + reference to the MediaDescriptor (represented by an easy-to-use + stl interface!), which should be patched. + */ + static void impl_removeTypeFilterFromDescriptor(utl::MediaDescriptor& rDescriptor); + + + /** @short search the best suitable filter for the given type + and add it into the media descriptor. + + @descr Normally this is a type detection only ... + but for some special features we must overwrite our detection + because a file must be loaded into a special (means preselected) + application. + + E.g. CSV/TXT format are sometimes ugly to handle .-) + + Note: If the descriptor already include a filter + (may be selected by a FilterSelect interaction or preselected + by the user itself) ... we don't change that here ! + + @param rDescriptor + reference to the MediaDescriptor (represented by an easy-to-use + stl interface!), which should be patched. + + @param sType + the internal type name, where we search a filter for. + Used as IN/OUT parameter so we can overrule the detection result for + types too ! + + @note #i60158# + sometimes our text ascii and our csv filter can't work together. + Then we overwrite our detection hardly. + sType param is used as out parameter then too ... and + rDescriptor will be changed by selecting another filter. + (see code) + */ + void impl_checkResultsAndAddBestFilter(utl::MediaDescriptor& rDescriptor, + OUString& sType ); + + +// uno interface + +public: + + + // XTypeDetection + + virtual OUString SAL_CALL queryTypeByURL(const OUString& sURL) override; + + virtual OUString SAL_CALL queryTypeByDescriptor(css::uno::Sequence< css::beans::PropertyValue >& lDescriptor, + sal_Bool bAllowDeep ) override; + +}; + +class TerminateDetection : public comphelper::WeakComponentImplHelper +{ +private: + TypeDetection* m_pTypeDetection; + +public: + + using comphelper::WeakComponentImplHelperBase::disposing; + virtual void SAL_CALL disposing(const css::lang::EventObject&) override + { + } + + // XTerminateListener + virtual void SAL_CALL queryTermination(const css::lang::EventObject&) override + { + m_pTypeDetection->cancel(); + } + + virtual void SAL_CALL notifyTermination(const css::lang::EventObject&) override + { + } + + TerminateDetection(TypeDetection* pTypeDetection) + : m_pTypeDetection(pTypeDetection) + { + } +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_SoundHandler.xcu b/filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_SoundHandler.xcu new file mode 100644 index 000000000..f49e237d9 --- /dev/null +++ b/filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_SoundHandler.xcu @@ -0,0 +1,20 @@ + + + wav_Wave_Audio_File + diff --git a/filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_oxt_handler.xcu b/filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_oxt_handler.xcu new file mode 100644 index 000000000..2ae506aea --- /dev/null +++ b/filter/source/config/fragments/contenthandlers/com_sun_star_comp_framework_oxt_handler.xcu @@ -0,0 +1,20 @@ + + + oxt_OpenOffice_Extension + diff --git a/filter/source/config/fragments/filters/ADO_rowset_XML.xcu b/filter/source/config/fragments/filters/ADO_rowset_XML.xcu new file mode 100644 index 000000000..c31848ef8 --- /dev/null +++ b/filter/source/config/fragments/filters/ADO_rowset_XML.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Writer.XmlFilterAdaptor + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Calc.XMLOasisImporter,com.sun.star.comp.Calc.XMLOasisExporter,../$(share_subdir_name)/xslt/import/spreadsheetml/adorowset2ods.xsl, + 0 + calc_ADO_rowset_XML + + com.sun.star.sheet.SpreadsheetDocument + + ADO Rowset XML + + diff --git a/filter/source/config/fragments/filters/AbiWord.xcu b/filter/source/config/fragments/filters/AbiWord.xcu new file mode 100644 index 000000000..a309ac87d --- /dev/null +++ b/filter/source/config/fragments/filters/AbiWord.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER EXOTIC + + com.sun.star.comp.Writer.AbiWordImportFilter + ABW + + AbiWord Document + + 0 + writer_AbiWord_Document + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/AppleKeynote.xcu b/filter/source/config/fragments/filters/AppleKeynote.xcu new file mode 100644 index 000000000..48a99ba7c --- /dev/null +++ b/filter/source/config/fragments/filters/AppleKeynote.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Impress.KeynoteImportFilter + + + Apple Keynote + + + 0 + + + impress_AppleKeynote + + + com.sun.star.presentation.PresentationDocument + + diff --git a/filter/source/config/fragments/filters/AppleNumbers.xcu b/filter/source/config/fragments/filters/AppleNumbers.xcu new file mode 100644 index 000000000..2bfa87072 --- /dev/null +++ b/filter/source/config/fragments/filters/AppleNumbers.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Calc.NumbersImportFilter + + + Apple Numbers + + + 0 + + + calc_AppleNumbers + + + com.sun.star.sheet.SpreadsheetDocument + + diff --git a/filter/source/config/fragments/filters/ApplePages.xcu b/filter/source/config/fragments/filters/ApplePages.xcu new file mode 100644 index 000000000..25ca2f015 --- /dev/null +++ b/filter/source/config/fragments/filters/ApplePages.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Writer.PagesImportFilter + + + Apple Pages + + + 0 + + + writer_ApplePages + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/BMP___MS_Windows.xcu b/filter/source/config/fragments/filters/BMP___MS_Windows.xcu new file mode 100644 index 000000000..36ce6bfb4 --- /dev/null +++ b/filter/source/config/fragments/filters/BMP___MS_Windows.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + BMP - Windows Bitmap + + 0 + bmp_MS_Windows + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/BroadBand_eBook.xcu b/filter/source/config/fragments/filters/BroadBand_eBook.xcu new file mode 100644 index 000000000..3a54aed07 --- /dev/null +++ b/filter/source/config/fragments/filters/BroadBand_eBook.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Writer.EBookImportFilter + + + BroadBand eBook + + + 0 + + + writer_BroadBand_eBook + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/CGM___Computer_Graphics_Metafile.xcu b/filter/source/config/fragments/filters/CGM___Computer_Graphics_Metafile.xcu new file mode 100644 index 000000000..26fa9e638 --- /dev/null +++ b/filter/source/config/fragments/filters/CGM___Computer_Graphics_Metafile.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + CGM - Computer Graphics Metafile + + 0 + impress_CGM_Computer_Graphics_Metafile + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/ClarisWorks.xcu b/filter/source/config/fragments/filters/ClarisWorks.xcu new file mode 100644 index 000000000..8288c34ff --- /dev/null +++ b/filter/source/config/fragments/filters/ClarisWorks.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.MWAWImportFilter + + + ClarisWorks/AppleWorks Text Document + + 0 + writer_ClarisWorks + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/ClarisWorks_Calc.xcu b/filter/source/config/fragments/filters/ClarisWorks_Calc.xcu new file mode 100644 index 000000000..a6f817dc2 --- /dev/null +++ b/filter/source/config/fragments/filters/ClarisWorks_Calc.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + + ClarisWorks/AppleWorks Spreadsheet + + 0 + calc_ClarisWorks + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/ClarisWorks_Draw.xcu b/filter/source/config/fragments/filters/ClarisWorks_Draw.xcu new file mode 100644 index 000000000..e69354c3f --- /dev/null +++ b/filter/source/config/fragments/filters/ClarisWorks_Draw.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.MWAWDrawImportFilter + + + ClarisWorks/AppleWorks Drawing + + 0 + draw_ClarisWorks + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/ClarisWorks_Impress.xcu b/filter/source/config/fragments/filters/ClarisWorks_Impress.xcu new file mode 100644 index 000000000..9318c5d95 --- /dev/null +++ b/filter/source/config/fragments/filters/ClarisWorks_Impress.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Impress.MWAWPresentationImportFilter + + + ClarisWorks/AppleWorks Presentation + + 0 + impress_ClarisWorks + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/Claris_Resolve_Calc.xcu b/filter/source/config/fragments/filters/Claris_Resolve_Calc.xcu new file mode 100644 index 000000000..17b802422 --- /dev/null +++ b/filter/source/config/fragments/filters/Claris_Resolve_Calc.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + + ClarisResolve Document + + 0 + calc_Claris_Resolve + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/CorelDrawDocument.xcu b/filter/source/config/fragments/filters/CorelDrawDocument.xcu new file mode 100644 index 000000000..14b6e2806 --- /dev/null +++ b/filter/source/config/fragments/filters/CorelDrawDocument.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.CDRImportFilter + + + Corel Draw + + 0 + draw_CorelDraw_Document + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/CorelPresentationExchange.xcu b/filter/source/config/fragments/filters/CorelPresentationExchange.xcu new file mode 100644 index 000000000..0a402d2ea --- /dev/null +++ b/filter/source/config/fragments/filters/CorelPresentationExchange.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.CMXImportFilter + + + Corel Presentation Exchange + + 0 + draw_Corel_Presentation_Exchange + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/DIF.xcu b/filter/source/config/fragments/filters/DIF.xcu new file mode 100644 index 000000000..c075ff977 --- /dev/null +++ b/filter/source/config/fragments/filters/DIF.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN + com.sun.star.comp.Calc.FilterOptionsDialog + + + + Data Interchange Format + + 0 + calc_DIF + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/DXF___AutoCAD_Interchange.xcu b/filter/source/config/fragments/filters/DXF___AutoCAD_Interchange.xcu new file mode 100644 index 000000000..652ee10e2 --- /dev/null +++ b/filter/source/config/fragments/filters/DXF___AutoCAD_Interchange.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + DXF - AutoCAD Interchange Format + + 0 + dxf_AutoCAD_Interchange + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/DocBook_File.xcu b/filter/source/config/fragments/filters/DocBook_File.xcu new file mode 100644 index 000000000..da278f4c6 --- /dev/null +++ b/filter/source/config/fragments/filters/DocBook_File.xcu @@ -0,0 +1,30 @@ + + + 0 + writer_DocBook_File + com.sun.star.text.TextDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Writer.XMLImporter,com.sun.star.comp.Writer.XMLExporter,../$(share_subdir_name)/xslt/docbook/docbooktosoffheadings.xsl,../$(share_subdir_name)/xslt/docbook/sofftodocbookheadings.xsl + com.sun.star.comp.Writer.XmlFilterAdaptor + ../$(share_subdir_name)/xslt/docbook/DocBookTemplate.stw + + DocBook + + IMPORT EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/DosWord.xcu b/filter/source/config/fragments/filters/DosWord.xcu new file mode 100644 index 000000000..697032c91 --- /dev/null +++ b/filter/source/config/fragments/filters/DosWord.xcu @@ -0,0 +1,28 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER + + + com.sun.star.comp.Writer.MSWorksImportFilter + + + Microsoft Word for DOS + + + 0 + + + writer_DosWord + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/EMF___MS_Windows_Metafile.xcu b/filter/source/config/fragments/filters/EMF___MS_Windows_Metafile.xcu new file mode 100644 index 000000000..852cb1f8b --- /dev/null +++ b/filter/source/config/fragments/filters/EMF___MS_Windows_Metafile.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + EMF - Enhanced Metafile + + 0 + emf_MS_Windows_Metafile + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/EPS___Encapsulated_PostScript.xcu b/filter/source/config/fragments/filters/EPS___Encapsulated_PostScript.xcu new file mode 100644 index 000000000..195b6af84 --- /dev/null +++ b/filter/source/config/fragments/filters/EPS___Encapsulated_PostScript.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + EPS - Encapsulated PostScript + + 0 + eps_Encapsulated_PostScript + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/EPUB.xcu b/filter/source/config/fragments/filters/EPUB.xcu new file mode 100644 index 000000000..8ec0da9cd --- /dev/null +++ b/filter/source/config/fragments/filters/EPUB.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.Writer.EPUBExportUIComponent + com.sun.star.comp.Writer.EPUBExportFilter + EPUB + + EPUB Document + + 0 + writer_EPUB_Document + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/FictionBook_2.xcu b/filter/source/config/fragments/filters/FictionBook_2.xcu new file mode 100644 index 000000000..68e4c1c34 --- /dev/null +++ b/filter/source/config/fragments/filters/FictionBook_2.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Writer.EBookImportFilter + + + FictionBook 2.0 + + + 0 + + + writer_FictionBook_2 + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/FreehandDocument.xcu b/filter/source/config/fragments/filters/FreehandDocument.xcu new file mode 100644 index 000000000..4502ac0ce --- /dev/null +++ b/filter/source/config/fragments/filters/FreehandDocument.xcu @@ -0,0 +1,13 @@ + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.FreehandImportFilter + + + Adobe/Macromedia Freehand + + 0 + draw_Freehand_Document + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/GIF___Graphics_Interchange.xcu b/filter/source/config/fragments/filters/GIF___Graphics_Interchange.xcu new file mode 100644 index 000000000..a62d53fd0 --- /dev/null +++ b/filter/source/config/fragments/filters/GIF___Graphics_Interchange.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + GIF - Graphics Interchange Format + + 0 + gif_Graphics_Interchange + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/HTML.xcu b/filter/source/config/fragments/filters/HTML.xcu new file mode 100644 index 000000000..68a64cb01 --- /dev/null +++ b/filter/source/config/fragments/filters/HTML.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT PREFERRED + + + HTML + 0 + generic_HTML + + com.sun.star.text.WebDocument + + HTML Document + + diff --git a/filter/source/config/fragments/filters/HTML_MasterDoc.xcu b/filter/source/config/fragments/filters/HTML_MasterDoc.xcu new file mode 100644 index 000000000..1316b1d4f --- /dev/null +++ b/filter/source/config/fragments/filters/HTML_MasterDoc.xcu @@ -0,0 +1,30 @@ + + + 0 + generic_HTML + com.sun.star.text.GlobalDocument + + HTML + + + + HTML Document (Master Document) + + EXPORT INTERNAL NOTINFILEDIALOG + diff --git a/filter/source/config/fragments/filters/HTML__StarCalc_.xcu b/filter/source/config/fragments/filters/HTML__StarCalc_.xcu new file mode 100644 index 000000000..9e731b3bb --- /dev/null +++ b/filter/source/config/fragments/filters/HTML__StarCalc_.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN USEOPTIONS + com.sun.star.comp.Calc.FilterOptionsDialog + + + 0 + generic_HTML + + com.sun.star.sheet.SpreadsheetDocument + + HTML Document (Calc) + + diff --git a/filter/source/config/fragments/filters/HTML__StarWriter_.xcu b/filter/source/config/fragments/filters/HTML__StarWriter_.xcu new file mode 100644 index 000000000..3a9d68347 --- /dev/null +++ b/filter/source/config/fragments/filters/HTML__StarWriter_.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN + + + HTML + 0 + generic_HTML + + com.sun.star.text.TextDocument + + HTML Document (Writer) + + diff --git a/filter/source/config/fragments/filters/JPG___JPEG.xcu b/filter/source/config/fragments/filters/JPG___JPEG.xcu new file mode 100644 index 000000000..7e5794a38 --- /dev/null +++ b/filter/source/config/fragments/filters/JPG___JPEG.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + JPEG - Joint Photographic Experts Group + + 0 + jpg_JPEG + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/Lotus.xcu b/filter/source/config/fragments/filters/Lotus.xcu new file mode 100644 index 000000000..44bf3a89c --- /dev/null +++ b/filter/source/config/fragments/filters/Lotus.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN PREFERRED + com.sun.star.comp.Calc.FilterOptionsDialog + + + + Lotus 1-2-3 + + 0 + calc_Lotus + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/LotusWordPro.xcu b/filter/source/config/fragments/filters/LotusWordPro.xcu new file mode 100644 index 000000000..8b065b0c2 --- /dev/null +++ b/filter/source/config/fragments/filters/LotusWordPro.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.LotusWordProImportFilter + WPD + + Lotus WordPro Document + + 0 + writer_LotusWordPro_Document + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MET___OS_2_Metafile.xcu b/filter/source/config/fragments/filters/MET___OS_2_Metafile.xcu new file mode 100644 index 000000000..1c1059b74 --- /dev/null +++ b/filter/source/config/fragments/filters/MET___OS_2_Metafile.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + MET - OS/2 Metafile + + 0 + met_OS2_Metafile + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/MS_Excel_2003_XML.xcu b/filter/source/config/fragments/filters/MS_Excel_2003_XML.xcu new file mode 100644 index 000000000..a0fc95939 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_2003_XML.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Writer.XmlFilterAdaptor + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Calc.XMLOasisImporter,com.sun.star.comp.Calc.XMLOasisExporter,../$(share_subdir_name)/xslt/import/spreadsheetml/spreadsheetml2ooo.xsl,../$(share_subdir_name)/xslt/export/spreadsheetml/ooo2spreadsheetml.xsl + 0 + calc_MS_Excel_2003_XML + + com.sun.star.sheet.SpreadsheetDocument + + Microsoft Excel 2003 XML + + diff --git a/filter/source/config/fragments/filters/MS_Excel_2003_XML_Orcus.xcu b/filter/source/config/fragments/filters/MS_Excel_2003_XML_Orcus.xcu new file mode 100644 index 000000000..2206b0274 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_2003_XML_Orcus.xcu @@ -0,0 +1,19 @@ + + + IMPORT ALIEN PREFERRED + + + + calc_MS_Excel_2003_XML + + com.sun.star.sheet.SpreadsheetDocument + + Microsoft Excel 2003 XML + + diff --git a/filter/source/config/fragments/filters/MS_Excel_4_0.xcu b/filter/source/config/fragments/filters/MS_Excel_4_0.xcu new file mode 100644 index 000000000..99dbdb06b --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_4_0.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN PREFERRED + + + + + Microsoft Excel 4.0 + + 0 + calc_MS_Excel_40 + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/MS_Excel_4_0_Vorlage_Template.xcu b/filter/source/config/fragments/filters/MS_Excel_4_0_Vorlage_Template.xcu new file mode 100644 index 000000000..1e724cdcb --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_4_0_Vorlage_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN TEMPLATE TEMPLATEPATH + + + + 0 + calc_MS_Excel_40_VorlageTemplate + + com.sun.star.sheet.SpreadsheetDocument + + Microsoft Excel 4.0 Template + + diff --git a/filter/source/config/fragments/filters/MS_Excel_5_0_95.xcu b/filter/source/config/fragments/filters/MS_Excel_5_0_95.xcu new file mode 100644 index 000000000..56244a3e4 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_5_0_95.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN PREFERRED + + + + + Microsoft Excel 5.0 + + 0 + calc_MS_Excel_5095 + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/MS_Excel_5_0_95_Vorlage_Template.xcu b/filter/source/config/fragments/filters/MS_Excel_5_0_95_Vorlage_Template.xcu new file mode 100644 index 000000000..4b8ec72a3 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_5_0_95_Vorlage_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN TEMPLATE TEMPLATEPATH + + + + 0 + calc_MS_Excel_5095_VorlageTemplate + + com.sun.star.sheet.SpreadsheetDocument + + Microsoft Excel 5.0 Template + + diff --git a/filter/source/config/fragments/filters/MS_Excel_95.xcu b/filter/source/config/fragments/filters/MS_Excel_95.xcu new file mode 100644 index 000000000..a6f424fbc --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_95.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN PREFERRED + + + + + Microsoft Excel 95 + + 0 + calc_MS_Excel_95 + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/MS_Excel_95_Vorlage_Template.xcu b/filter/source/config/fragments/filters/MS_Excel_95_Vorlage_Template.xcu new file mode 100644 index 000000000..d4c39a3d2 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_95_Vorlage_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN TEMPLATE TEMPLATEPATH + + + + 0 + calc_MS_Excel_95_VorlageTemplate + + com.sun.star.sheet.SpreadsheetDocument + + Microsoft Excel 95 Template + + diff --git a/filter/source/config/fragments/filters/MS_Excel_97.xcu b/filter/source/config/fragments/filters/MS_Excel_97.xcu new file mode 100644 index 000000000..cd2dd38d8 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_97.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN PREFERRED ENCRYPTION PASSWORDTOMODIFY + + + + + Excel 97–2003 + + 0 + calc_MS_Excel_97 + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/MS_Excel_97_Vorlage_Template.xcu b/filter/source/config/fragments/filters/MS_Excel_97_Vorlage_Template.xcu new file mode 100644 index 000000000..2dc342b06 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Excel_97_Vorlage_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN TEMPLATE TEMPLATEPATH ENCRYPTION PASSWORDTOMODIFY + + + + 0 + calc_MS_Excel_97_VorlageTemplate + + com.sun.star.sheet.SpreadsheetDocument + + Excel 97–2003 Template + + diff --git a/filter/source/config/fragments/filters/MS_Multiplan.xcu b/filter/source/config/fragments/filters/MS_Multiplan.xcu new file mode 100644 index 000000000..780901d53 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Multiplan.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + + Microsoft Multiplan + + + 0 + + + calc_MS_Multiplan + + + com.sun.star.sheet.SpreadsheetDocument + + diff --git a/filter/source/config/fragments/filters/MS_PowerPoint_97.xcu b/filter/source/config/fragments/filters/MS_PowerPoint_97.xcu new file mode 100644 index 000000000..eab7c73e3 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_PowerPoint_97.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN + + + sdfilt + + PowerPoint 97–2003 + + 0 + impress_MS_PowerPoint_97 + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/MS_PowerPoint_97_AutoPlay.xcu b/filter/source/config/fragments/filters/MS_PowerPoint_97_AutoPlay.xcu new file mode 100644 index 000000000..24683ea1b --- /dev/null +++ b/filter/source/config/fragments/filters/MS_PowerPoint_97_AutoPlay.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN STARTPRESENTATION + + + sdfilt + + PowerPoint 97–2003 AutoPlay + + 0 + impress_MS_PowerPoint_97_AutoPlay + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/MS_PowerPoint_97_Vorlage.xcu b/filter/source/config/fragments/filters/MS_PowerPoint_97_Vorlage.xcu new file mode 100644 index 000000000..4de589b1d --- /dev/null +++ b/filter/source/config/fragments/filters/MS_PowerPoint_97_Vorlage.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH ALIEN + + + sdfilt + 0 + impress_MS_PowerPoint_97_Vorlage + + com.sun.star.presentation.PresentationDocument + + PowerPoint 97–2003 Template + + diff --git a/filter/source/config/fragments/filters/MS_WinWord_5.xcu b/filter/source/config/fragments/filters/MS_WinWord_5.xcu new file mode 100644 index 000000000..a8656eda4 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_WinWord_5.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + WW6 + + Microsoft WinWord 1/2/5 + + 0 + writer_MS_WinWord_5 + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_WinWord_6_0.xcu b/filter/source/config/fragments/filters/MS_WinWord_6_0.xcu new file mode 100644 index 000000000..cdc6a6a5e --- /dev/null +++ b/filter/source/config/fragments/filters/MS_WinWord_6_0.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + CWW6 + + Microsoft Word 6.0 + + 0 + writer_MS_WinWord_60 + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_Word_2003_XML.xcu b/filter/source/config/fragments/filters/MS_Word_2003_XML.xcu new file mode 100644 index 000000000..1db287f09 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_2003_XML.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Writer.XmlFilterAdaptor + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Writer.XMLOasisImporter,com.sun.star.comp.Writer.XMLOasisExporter,../$(share_subdir_name)/xslt/import/wordml/wordml2ooo.xsl,../$(share_subdir_name)/xslt/export/wordml/ooo2wordml.xsl + 0 + writer_MS_Word_2003_XML + + com.sun.star.text.TextDocument + + Word 2003 XML + + diff --git a/filter/source/config/fragments/filters/MS_Word_2007_XML.xcu b/filter/source/config/fragments/filters/MS_Word_2007_XML.xcu new file mode 100644 index 000000000..c4e6f828c --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_2007_XML.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER ENCRYPTION PASSWORDTOMODIFY SUPPORTSSIGNING + + com.sun.star.comp.Writer.WriterFilter + OXML + + Word 2007–365 + + 0 + writer_MS_Word_2007 + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_Word_2007_XML_Template.xcu b/filter/source/config/fragments/filters/MS_Word_2007_XML_Template.xcu new file mode 100644 index 000000000..cd81c9943 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_2007_XML_Template.xcu @@ -0,0 +1,28 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH + + com.sun.star.comp.Writer.WriterFilter + OXML + Word 2007–365 Template + 0 + writer_MS_Word_2007_Template + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_Word_2007_XML_VBA.xcu b/filter/source/config/fragments/filters/MS_Word_2007_XML_VBA.xcu new file mode 100644 index 000000000..0f1bdb723 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_2007_XML_VBA.xcu @@ -0,0 +1,18 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER ENCRYPTION PASSWORDTOMODIFY SUPPORTSSIGNING + + com.sun.star.comp.Writer.WriterFilter + OXML + Word 2007–365 VBA + 0 + writer_MS_Word_2007_VBA + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_Word_95.xcu b/filter/source/config/fragments/filters/MS_Word_95.xcu new file mode 100644 index 000000000..7db5ca087 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_95.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + CWW6 + + Microsoft Word 95 + + 0 + writer_MS_Word_95 + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_Word_95_Vorlage.xcu b/filter/source/config/fragments/filters/MS_Word_95_Vorlage.xcu new file mode 100644 index 000000000..3b2a105f8 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_95_Vorlage.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE TEMPLATEPATH ALIEN + + + CWW6 + 0 + writer_MS_Word_95_Vorlage + + com.sun.star.text.TextDocument + + Microsoft Word 95 Template + + diff --git a/filter/source/config/fragments/filters/MS_Word_97.xcu b/filter/source/config/fragments/filters/MS_Word_97.xcu new file mode 100644 index 000000000..5adec6272 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_97.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN PREFERRED ENCRYPTION PASSWORDTOMODIFY + + + CWW8 + + Word 97–2003 + + 0 + writer_MS_Word_97 + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_Word_97_Vorlage.xcu b/filter/source/config/fragments/filters/MS_Word_97_Vorlage.xcu new file mode 100644 index 000000000..2fc7a7b68 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Word_97_Vorlage.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH ALIEN ENCRYPTION PASSWORDTOMODIFY + + + CWW8 + 0 + writer_MS_Word_97_Vorlage + + com.sun.star.text.TextDocument + + Word 97–2003 Template + + diff --git a/filter/source/config/fragments/filters/MS_Works.xcu b/filter/source/config/fragments/filters/MS_Works.xcu new file mode 100644 index 000000000..7a6377b8c --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Works.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Writer.MSWorksImportFilter + WPS + + Microsoft Works Document + + 0 + writer_MS_Works_Document + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MS_Works_Calc.xcu b/filter/source/config/fragments/filters/MS_Works_Calc.xcu new file mode 100644 index 000000000..f563469a5 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Works_Calc.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + + Microsoft Works Document + + 0 + calc_MS_Works_Document + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/MS_Write.xcu b/filter/source/config/fragments/filters/MS_Write.xcu new file mode 100644 index 000000000..061613816 --- /dev/null +++ b/filter/source/config/fragments/filters/MS_Write.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Writer.MSWorksImportFilter + WRI + + Microsoft Write + + 0 + writer_MS_Write + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MWAW_Bitmap.xcu b/filter/source/config/fragments/filters/MWAW_Bitmap.xcu new file mode 100644 index 000000000..3e70cc62f --- /dev/null +++ b/filter/source/config/fragments/filters/MWAW_Bitmap.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED EXOTIC + + + com.sun.star.comp.Draw.MWAWDrawImportFilter + + + Legacy Mac Bitmap + + + 0 + + + MWAW_Bitmap + + + com.sun.star.drawing.DrawingDocument + + diff --git a/filter/source/config/fragments/filters/MWAW_Database.xcu b/filter/source/config/fragments/filters/MWAW_Database.xcu new file mode 100644 index 000000000..075f3ed9e --- /dev/null +++ b/filter/source/config/fragments/filters/MWAW_Database.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED EXOTIC + + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + + Legacy Mac Database + + + 0 + + + MWAW_Database + + + com.sun.star.sheet.SpreadsheetDocument + + diff --git a/filter/source/config/fragments/filters/MWAW_Drawing.xcu b/filter/source/config/fragments/filters/MWAW_Drawing.xcu new file mode 100644 index 000000000..1b9ec56d2 --- /dev/null +++ b/filter/source/config/fragments/filters/MWAW_Drawing.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED EXOTIC + + + com.sun.star.comp.Draw.MWAWDrawImportFilter + + + Legacy Mac Drawing + + + 0 + + + MWAW_Drawing + + + com.sun.star.drawing.DrawingDocument + + diff --git a/filter/source/config/fragments/filters/MWAW_Presentation.xcu b/filter/source/config/fragments/filters/MWAW_Presentation.xcu new file mode 100644 index 000000000..aae6598b2 --- /dev/null +++ b/filter/source/config/fragments/filters/MWAW_Presentation.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED EXOTIC + + + com.sun.star.comp.Impress.MWAWPresentationImportFilter + + + Legacy Mac Presentation + + + 0 + + + MWAW_Presentation + + + com.sun.star.presentation.PresentationDocument + + diff --git a/filter/source/config/fragments/filters/MWAW_Spreadsheet.xcu b/filter/source/config/fragments/filters/MWAW_Spreadsheet.xcu new file mode 100644 index 000000000..5461b7fe2 --- /dev/null +++ b/filter/source/config/fragments/filters/MWAW_Spreadsheet.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED EXOTIC + + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + + Legacy Mac Spreadsheet + + + 0 + + + MWAW_Spreadsheet + + + com.sun.star.sheet.SpreadsheetDocument + + diff --git a/filter/source/config/fragments/filters/MWAW_Text_Document.xcu b/filter/source/config/fragments/filters/MWAW_Text_Document.xcu new file mode 100644 index 000000000..cfbd5556f --- /dev/null +++ b/filter/source/config/fragments/filters/MWAW_Text_Document.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED EXOTIC + + + com.sun.star.comp.Writer.MWAWImportFilter + + + Legacy Mac Text Document + + + 0 + + + MWAW_Text_Document + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/MacWrite.xcu b/filter/source/config/fragments/filters/MacWrite.xcu new file mode 100644 index 000000000..79a297f33 --- /dev/null +++ b/filter/source/config/fragments/filters/MacWrite.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.MWAWImportFilter + + + MacWrite Document + + 0 + writer_MacWrite + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/Mac_Word.xcu b/filter/source/config/fragments/filters/Mac_Word.xcu new file mode 100644 index 000000000..64d2edb2b --- /dev/null +++ b/filter/source/config/fragments/filters/Mac_Word.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.MWAWImportFilter + + + Microsoft Word for Mac (v1 - v5) + + 0 + writer_Mac_Word + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/Mac_Works.xcu b/filter/source/config/fragments/filters/Mac_Works.xcu new file mode 100644 index 000000000..beb2eadea --- /dev/null +++ b/filter/source/config/fragments/filters/Mac_Works.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.MWAWImportFilter + + + Microsoft Works for Mac Text Document (v1 - v4) + + 0 + writer_Mac_Works + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/Mac_Works_Calc.xcu b/filter/source/config/fragments/filters/Mac_Works_Calc.xcu new file mode 100644 index 000000000..ec3b959d2 --- /dev/null +++ b/filter/source/config/fragments/filters/Mac_Works_Calc.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + + Microsoft Works for Mac Spreadsheet (v1 - v4) + + 0 + calc_Mac_Works + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/Mariner_Write.xcu b/filter/source/config/fragments/filters/Mariner_Write.xcu new file mode 100644 index 000000000..df6689ccc --- /dev/null +++ b/filter/source/config/fragments/filters/Mariner_Write.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.MWAWImportFilter + + + Mariner Write Mac Classic v1.6 - v3.5 + + 0 + writer_Mariner_Write + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/MathML_XML__Math_.xcu b/filter/source/config/fragments/filters/MathML_XML__Math_.xcu new file mode 100644 index 000000000..5a6e24adc --- /dev/null +++ b/filter/source/config/fragments/filters/MathML_XML__Math_.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE + + + + + MathML 2.0 + + 6200 + math_MathML_XML_Math + + com.sun.star.formula.FormulaProperties + diff --git a/filter/source/config/fragments/filters/MathType_3_x.xcu b/filter/source/config/fragments/filters/MathType_3_x.xcu new file mode 100644 index 000000000..b93bf39c4 --- /dev/null +++ b/filter/source/config/fragments/filters/MathType_3_x.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN NOTINFILEDIALOG + + + + + MathType3.x + + 0 + math_MathType_3x + + com.sun.star.formula.FormulaProperties + diff --git a/filter/source/config/fragments/filters/ODG_FlatXML.xcu b/filter/source/config/fragments/filters/ODG_FlatXML.xcu new file mode 100644 index 000000000..c246e0a47 --- /dev/null +++ b/filter/source/config/fragments/filters/ODG_FlatXML.xcu @@ -0,0 +1,30 @@ + + + 0 + draw_ODG_FlatXML + com.sun.star.drawing.DrawingDocument + + com.sun.star.comp.filter.OdfFlatXml,,com.sun.star.comp.Draw.XMLOasisImporter,com.sun.star.comp.Draw.XMLOasisExporter,,,true + com.sun.star.comp.Writer.XmlFilterAdaptor + + + Flat XML ODF Drawing + + IMPORT EXPORT OWN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/ODP_FlatXML.xcu b/filter/source/config/fragments/filters/ODP_FlatXML.xcu new file mode 100644 index 000000000..e5052aa14 --- /dev/null +++ b/filter/source/config/fragments/filters/ODP_FlatXML.xcu @@ -0,0 +1,30 @@ + + + 0 + impress_ODP_FlatXML + com.sun.star.presentation.PresentationDocument + + com.sun.star.comp.filter.OdfFlatXml,,com.sun.star.comp.Impress.XMLOasisImporter,com.sun.star.comp.Impress.XMLOasisExporter,,,true + com.sun.star.comp.Writer.XmlFilterAdaptor + + + Flat XML ODF Presentation + + IMPORT EXPORT OWN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/ODS_FlatXML.xcu b/filter/source/config/fragments/filters/ODS_FlatXML.xcu new file mode 100644 index 000000000..d18197bdd --- /dev/null +++ b/filter/source/config/fragments/filters/ODS_FlatXML.xcu @@ -0,0 +1,30 @@ + + + 0 + calc_ODS_FlatXML + com.sun.star.sheet.SpreadsheetDocument + + com.sun.star.comp.filter.OdfFlatXml,,com.sun.star.comp.Calc.XMLOasisImporter,com.sun.star.comp.Calc.XMLOasisExporter,,,true + com.sun.star.comp.Writer.XmlFilterAdaptor + + + Flat XML ODF Spreadsheet + + IMPORT EXPORT OWN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/ODT_FlatXML.xcu b/filter/source/config/fragments/filters/ODT_FlatXML.xcu new file mode 100644 index 000000000..e113d742c --- /dev/null +++ b/filter/source/config/fragments/filters/ODT_FlatXML.xcu @@ -0,0 +1,30 @@ + + + 0 + writer_ODT_FlatXML + com.sun.star.text.TextDocument + + com.sun.star.comp.filter.OdfFlatXml,,com.sun.star.comp.Writer.XMLOasisImporter,com.sun.star.comp.Writer.XMLOasisExporter,,,true + com.sun.star.comp.Writer.XmlFilterAdaptor + + + Flat XML ODF Text Document + + IMPORT EXPORT OWN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/OOXML_Text.xcu b/filter/source/config/fragments/filters/OOXML_Text.xcu new file mode 100644 index 000000000..ebaab6406 --- /dev/null +++ b/filter/source/config/fragments/filters/OOXML_Text.xcu @@ -0,0 +1,31 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER ENCRYPTION PASSWORDTOMODIFY + + com.sun.star.comp.Writer.WriterFilter + + + Office Open XML Text (Transitional) + + + 1 + writer_OOXML + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/OOXML_Text_Template.xcu b/filter/source/config/fragments/filters/OOXML_Text_Template.xcu new file mode 100644 index 000000000..88fbf7047 --- /dev/null +++ b/filter/source/config/fragments/filters/OOXML_Text_Template.xcu @@ -0,0 +1,31 @@ + + + IMPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH + + com.sun.star.comp.Writer.WriterFilter + + + Office Open XML Text Template (Transitional) + + + 1 + writer_OOXML_Text_Template + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/PBM___Portable_Bitmap.xcu b/filter/source/config/fragments/filters/PBM___Portable_Bitmap.xcu new file mode 100644 index 000000000..6d560bc44 --- /dev/null +++ b/filter/source/config/fragments/filters/PBM___Portable_Bitmap.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PBM - Portable Bitmap + + 0 + pbm_Portable_Bitmap + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PCT___Mac_Pict.xcu b/filter/source/config/fragments/filters/PCT___Mac_Pict.xcu new file mode 100644 index 000000000..92ae6cd23 --- /dev/null +++ b/filter/source/config/fragments/filters/PCT___Mac_Pict.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PCT - Mac Pict + + 0 + pct_Mac_Pict + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PCX___Zsoft_Paintbrush.xcu b/filter/source/config/fragments/filters/PCX___Zsoft_Paintbrush.xcu new file mode 100644 index 000000000..31122c365 --- /dev/null +++ b/filter/source/config/fragments/filters/PCX___Zsoft_Paintbrush.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PCX - Zsoft Paintbrush + + 0 + pcx_Zsoft_Paintbrush + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PGM___Portable_Graymap.xcu b/filter/source/config/fragments/filters/PGM___Portable_Graymap.xcu new file mode 100644 index 000000000..f930bc8c1 --- /dev/null +++ b/filter/source/config/fragments/filters/PGM___Portable_Graymap.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PGM - Portable Graymap + + 0 + pgm_Portable_Graymap + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PNG___Portable_Network_Graphic.xcu b/filter/source/config/fragments/filters/PNG___Portable_Network_Graphic.xcu new file mode 100644 index 000000000..b321ab6da --- /dev/null +++ b/filter/source/config/fragments/filters/PNG___Portable_Network_Graphic.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PNG - Portable Network Graphics + + 0 + png_Portable_Network_Graphic + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PPM___Portable_Pixelmap.xcu b/filter/source/config/fragments/filters/PPM___Portable_Pixelmap.xcu new file mode 100644 index 000000000..de35d2491 --- /dev/null +++ b/filter/source/config/fragments/filters/PPM___Portable_Pixelmap.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PPM - Portable Pixelmap + + 0 + ppm_Portable_Pixelmap + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PSD___Adobe_Photoshop.xcu b/filter/source/config/fragments/filters/PSD___Adobe_Photoshop.xcu new file mode 100644 index 000000000..ab2a457e9 --- /dev/null +++ b/filter/source/config/fragments/filters/PSD___Adobe_Photoshop.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PSD - Adobe Photoshop + + 0 + psd_Adobe_Photoshop + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PageMakerDocument.xcu b/filter/source/config/fragments/filters/PageMakerDocument.xcu new file mode 100644 index 000000000..ad45de75b --- /dev/null +++ b/filter/source/config/fragments/filters/PageMakerDocument.xcu @@ -0,0 +1,13 @@ + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + org.libreoffice.comp.Draw.PageMakerImportFilter + + + Adobe PageMaker + + 0 + draw_PageMaker_Document + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/PalmDoc.xcu b/filter/source/config/fragments/filters/PalmDoc.xcu new file mode 100644 index 000000000..8e612f693 --- /dev/null +++ b/filter/source/config/fragments/filters/PalmDoc.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Writer.EBookImportFilter + + + PalmDoc eBook + + + 0 + + + writer_PalmDoc + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/Palm_Text_Document.xcu b/filter/source/config/fragments/filters/Palm_Text_Document.xcu new file mode 100644 index 000000000..4747d3588 --- /dev/null +++ b/filter/source/config/fragments/filters/Palm_Text_Document.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Writer.EBookImportFilter + + + Palm Text Document + + + 0 + + + Palm_Text_Document + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/Plucker_eBook.xcu b/filter/source/config/fragments/filters/Plucker_eBook.xcu new file mode 100644 index 000000000..b5942780d --- /dev/null +++ b/filter/source/config/fragments/filters/Plucker_eBook.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Writer.EBookImportFilter + + + Plucker eBook + + + 0 + + + writer_Plucker_eBook + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/PocketWord_File.xcu b/filter/source/config/fragments/filters/PocketWord_File.xcu new file mode 100644 index 000000000..1ce83aa68 --- /dev/null +++ b/filter/source/config/fragments/filters/PocketWord_File.xcu @@ -0,0 +1,29 @@ + + + 0 + writer_PocketWord_File + com.sun.star.text.TextDocument + + com.sun.star.comp.Writer.MSWorksImportFilter + + + Pocket Word + + IMPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/PowerPoint3.xcu b/filter/source/config/fragments/filters/PowerPoint3.xcu new file mode 100644 index 000000000..d1d19e6d2 --- /dev/null +++ b/filter/source/config/fragments/filters/PowerPoint3.xcu @@ -0,0 +1,28 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER + + + com.sun.star.comp.Impress.MWAWPresentationImportFilter + + + Microsoft PowerPoint 1-4 and 95's + + + 0 + + + impress_PowerPoint3 + + + com.sun.star.presentation.PresentationDocument + + diff --git a/filter/source/config/fragments/filters/PublisherDocument.xcu b/filter/source/config/fragments/filters/PublisherDocument.xcu new file mode 100644 index 000000000..5dcc167e8 --- /dev/null +++ b/filter/source/config/fragments/filters/PublisherDocument.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.MSPUBImportFilter + + + Microsoft Publisher 98-2010 + + 0 + draw_Publisher_Document + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/QPro.xcu b/filter/source/config/fragments/filters/QPro.xcu new file mode 100644 index 000000000..e3242644b --- /dev/null +++ b/filter/source/config/fragments/filters/QPro.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN PREFERRED + + + + + Quattro Pro 6.0 + + 0 + calc_QPro + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/QXPDocument.xcu b/filter/source/config/fragments/filters/QXPDocument.xcu new file mode 100644 index 000000000..b0e645000 --- /dev/null +++ b/filter/source/config/fragments/filters/QXPDocument.xcu @@ -0,0 +1,13 @@ + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + org.libreoffice.comp.Draw.QXPImportFilter + + + QuarkXPress + + 0 + draw_QXP_Document + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/RAS___Sun_Rasterfile.xcu b/filter/source/config/fragments/filters/RAS___Sun_Rasterfile.xcu new file mode 100644 index 000000000..cd9f7b1d2 --- /dev/null +++ b/filter/source/config/fragments/filters/RAS___Sun_Rasterfile.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + RAS - Sun Raster Image + + 0 + ras_Sun_Rasterfile + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/Rich_Text_Format.xcu b/filter/source/config/fragments/filters/Rich_Text_Format.xcu new file mode 100644 index 000000000..239408310 --- /dev/null +++ b/filter/source/config/fragments/filters/Rich_Text_Format.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.RtfFilter + RTF + + Rich Text + + 0 + writer_Rich_Text_Format + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/Rich_Text_Format__StarCalc_.xcu b/filter/source/config/fragments/filters/Rich_Text_Format__StarCalc_.xcu new file mode 100644 index 000000000..c74c65857 --- /dev/null +++ b/filter/source/config/fragments/filters/Rich_Text_Format__StarCalc_.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + Rich Text Format (Calc) + + 0 + writer_Rich_Text_Format + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu b/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu new file mode 100644 index 000000000..c5cae01dd --- /dev/null +++ b/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.SVGFilter + + + SVG - Scalable Vector Graphics + + 0 + svg_Scalable_Vector_Graphics + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics_Draw.xcu b/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics_Draw.xcu new file mode 100644 index 000000000..eb98d7f94 --- /dev/null +++ b/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics_Draw.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.SVGFilter + + + SVG - Scalable Vector Graphics Draw + + 0 + svg_Scalable_Vector_Graphics_Draw + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/SVM___StarView_Metafile.xcu b/filter/source/config/fragments/filters/SVM___StarView_Metafile.xcu new file mode 100644 index 000000000..89c542533 --- /dev/null +++ b/filter/source/config/fragments/filters/SVM___StarView_Metafile.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + SVM - StarView Metafile + + 0 + svm_StarView_Metafile + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/SYLK.xcu b/filter/source/config/fragments/filters/SYLK.xcu new file mode 100644 index 000000000..9ebb83643 --- /dev/null +++ b/filter/source/config/fragments/filters/SYLK.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN + + + + + SYLK + + 0 + calc_SYLK + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/StarBaseReport.xcu b/filter/source/config/fragments/filters/StarBaseReport.xcu new file mode 100644 index 000000000..797d490f9 --- /dev/null +++ b/filter/source/config/fragments/filters/StarBaseReport.xcu @@ -0,0 +1,38 @@ + + + + IMPORT EXPORT OWN DEFAULT 3RDPARTYFILTER NOTINFILEDIALOG + + + + + + 6800 + + + StarBaseReport + + + + com.sun.star.report.ReportDefinition + + + ODF Database Report + + diff --git a/filter/source/config/fragments/filters/StarBaseReportChart.xcu b/filter/source/config/fragments/filters/StarBaseReportChart.xcu new file mode 100644 index 000000000..86233ac14 --- /dev/null +++ b/filter/source/config/fragments/filters/StarBaseReportChart.xcu @@ -0,0 +1,40 @@ + + + + IMPORT EXPORT OWN DEFAULT NOTINFILEDIALOG + + + + com.sun.star.comp.chart2.report.XMLFilter + + + + 6800 + + + StarBaseReportChart + + + + com.sun.star.chart2.ChartDocument + + + OpenOffice.org 1.0 Report Chart + + diff --git a/filter/source/config/fragments/filters/StarOffice_Drawing.xcu b/filter/source/config/fragments/filters/StarOffice_Drawing.xcu new file mode 100644 index 000000000..f820fe096 --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_Drawing.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Draw.StarOfficeDrawImportFilter + + + Legacy StarOffice Drawing + + + 0 + + + StarOffice_Drawing + + + com.sun.star.drawing.DrawingDocument + + diff --git a/filter/source/config/fragments/filters/StarOffice_Presentation.xcu b/filter/source/config/fragments/filters/StarOffice_Presentation.xcu new file mode 100644 index 000000000..7179379d7 --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_Presentation.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Impress.StarOfficePresentationImportFilter + + + Legacy StarOffice Presentation + + + 0 + + + StarOffice_Presentation + + + com.sun.star.presentation.PresentationDocument + + diff --git a/filter/source/config/fragments/filters/StarOffice_Spreadsheet.xcu b/filter/source/config/fragments/filters/StarOffice_Spreadsheet.xcu new file mode 100644 index 000000000..d6ac85576 --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_Spreadsheet.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Calc.StarOfficeCalcImportFilter + + + Legacy StarOffice Spreadsheet + + + 0 + + + StarOffice_Spreadsheet + + + com.sun.star.sheet.SpreadsheetDocument + + diff --git a/filter/source/config/fragments/filters/StarOffice_Writer.xcu b/filter/source/config/fragments/filters/StarOffice_Writer.xcu new file mode 100644 index 000000000..9522d73b0 --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_Writer.xcu @@ -0,0 +1,29 @@ + + + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + + org.libreoffice.comp.Writer.StarOfficeWriterImportFilter + + + Legacy StarOffice Text Document + + + 0 + + + StarOffice_Writer + + + com.sun.star.text.TextDocument + + diff --git a/filter/source/config/fragments/filters/StarOffice_XML__Base_.xcu b/filter/source/config/fragments/filters/StarOffice_XML__Base_.xcu new file mode 100644 index 000000000..344843043 --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_XML__Base_.xcu @@ -0,0 +1,30 @@ + + + IMPORT OWN DEFAULT 3RDPARTYFILTER ENCRYPTION EXOTIC + + + + 6200 + StarBase + + com.sun.star.sdb.OfficeDatabaseDocument + + ODF Database + + diff --git a/filter/source/config/fragments/filters/StarOffice_XML__Calc_.xcu b/filter/source/config/fragments/filters/StarOffice_XML__Calc_.xcu new file mode 100644 index 000000000..6f658cbdd --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_XML__Calc_.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE OWN ALIEN ENCRYPTION + + + + 6200 + calc_StarOffice_XML_Calc + + com.sun.star.sheet.SpreadsheetDocument + + OpenOffice.org 1.0 Spreadsheet + + diff --git a/filter/source/config/fragments/filters/StarOffice_XML__Chart_.xcu b/filter/source/config/fragments/filters/StarOffice_XML__Chart_.xcu new file mode 100644 index 000000000..3ad0cb8c0 --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_XML__Chart_.xcu @@ -0,0 +1,30 @@ + + + IMPORT OWN ALIEN NOTINFILEDIALOG ENCRYPTION + + com.sun.star.comp.chart2.XMLFilter + XML + 6200 + chart_StarOffice_XML_Chart + + com.sun.star.chart2.ChartDocument + + OpenOffice.org 1.0 Chart + + diff --git a/filter/source/config/fragments/filters/StarOffice_XML__Draw_.xcu b/filter/source/config/fragments/filters/StarOffice_XML__Draw_.xcu new file mode 100644 index 000000000..9fdd62b9a --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_XML__Draw_.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE OWN ALIEN PREFERRED ENCRYPTION + + + XML + 6200 + draw_StarOffice_XML_Draw + + com.sun.star.drawing.DrawingDocument + + OpenOffice.org 1.0 Drawing + + diff --git a/filter/source/config/fragments/filters/StarOffice_XML__Impress_.xcu b/filter/source/config/fragments/filters/StarOffice_XML__Impress_.xcu new file mode 100644 index 000000000..1a2c24d22 --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_XML__Impress_.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE OWN ALIEN PREFERRED ENCRYPTION + + + XML + 6200 + impress_StarOffice_XML_Impress + + com.sun.star.presentation.PresentationDocument + + OpenOffice.org 1.0 Presentation + + diff --git a/filter/source/config/fragments/filters/StarOffice_XML__Math_.xcu b/filter/source/config/fragments/filters/StarOffice_XML__Math_.xcu new file mode 100644 index 000000000..569eb570b --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_XML__Math_.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE OWN ALIEN ENCRYPTION + + + + 6200 + math_StarOffice_XML_Math + + com.sun.star.formula.FormulaProperties + + OpenOffice.org 1.0 Formula + + diff --git a/filter/source/config/fragments/filters/StarOffice_XML__Writer_.xcu b/filter/source/config/fragments/filters/StarOffice_XML__Writer_.xcu new file mode 100644 index 000000000..ba7db694d --- /dev/null +++ b/filter/source/config/fragments/filters/StarOffice_XML__Writer_.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE OWN ALIEN PREFERRED ENCRYPTION EXOTIC + + + CXML + 6200 + writer_StarOffice_XML_Writer + + com.sun.star.text.TextDocument + + OpenOffice.org 1.0 Text Document + + diff --git a/filter/source/config/fragments/filters/T602Document.xcu b/filter/source/config/fragments/filters/T602Document.xcu new file mode 100644 index 000000000..bf8a68fa6 --- /dev/null +++ b/filter/source/config/fragments/filters/T602Document.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED EXOTIC + + com.sun.star.comp.Writer.T602ImportFilter + 602 + + T602 Document + + 0 + writer_T602_Document + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/TGA___Truevision_TARGA.xcu b/filter/source/config/fragments/filters/TGA___Truevision_TARGA.xcu new file mode 100644 index 000000000..246c3f566 --- /dev/null +++ b/filter/source/config/fragments/filters/TGA___Truevision_TARGA.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + TGA - Truevision Targa + + 0 + tga_Truevision_TARGA + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/TIF___Tag_Image_File.xcu b/filter/source/config/fragments/filters/TIF___Tag_Image_File.xcu new file mode 100644 index 000000000..367159fb4 --- /dev/null +++ b/filter/source/config/fragments/filters/TIF___Tag_Image_File.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + TIFF - Tagged Image File Format + + 0 + tif_Tag_Image_File + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/Text.xcu b/filter/source/config/fragments/filters/Text.xcu new file mode 100644 index 000000000..7ce06bcd1 --- /dev/null +++ b/filter/source/config/fragments/filters/Text.xcu @@ -0,0 +1,31 @@ + + + IMPORT EXPORT ALIEN PREFERRED + + + TEXT + 0 + txt + generic_Text + + com.sun.star.text.TextDocument + + Text + + diff --git a/filter/source/config/fragments/filters/Text__StarWriter_Web_.xcu b/filter/source/config/fragments/filters/Text__StarWriter_Web_.xcu new file mode 100644 index 000000000..e3d1658fb --- /dev/null +++ b/filter/source/config/fragments/filters/Text__StarWriter_Web_.xcu @@ -0,0 +1,31 @@ + + + IMPORT EXPORT ALIEN + + + TEXT + 0 + txt + generic_Text + + com.sun.star.text.WebDocument + + Text (Writer/Web) + + diff --git a/filter/source/config/fragments/filters/Text___txt___csv__StarCalc_.xcu b/filter/source/config/fragments/filters/Text___txt___csv__StarCalc_.xcu new file mode 100644 index 000000000..886552c7e --- /dev/null +++ b/filter/source/config/fragments/filters/Text___txt___csv__StarCalc_.xcu @@ -0,0 +1,31 @@ + + + IMPORT EXPORT ALIEN + com.sun.star.comp.Calc.FilterOptionsDialog + + + 0 + csv + generic_Text + + com.sun.star.sheet.SpreadsheetDocument + + Text CSV + + diff --git a/filter/source/config/fragments/filters/Text__encoded_.xcu b/filter/source/config/fragments/filters/Text__encoded_.xcu new file mode 100644 index 000000000..f4c6f0d30 --- /dev/null +++ b/filter/source/config/fragments/filters/Text__encoded_.xcu @@ -0,0 +1,31 @@ + + + IMPORT EXPORT ALIEN + com.sun.star.comp.Writer.FilterOptionsDialog + + TEXT_DLG + 0 + txt + generic_Text + + com.sun.star.text.TextDocument + + Text - Choose Encoding + + diff --git a/filter/source/config/fragments/filters/Text__encoded___StarWriter_GlobalDocument_.xcu b/filter/source/config/fragments/filters/Text__encoded___StarWriter_GlobalDocument_.xcu new file mode 100644 index 000000000..2b6a8b011 --- /dev/null +++ b/filter/source/config/fragments/filters/Text__encoded___StarWriter_GlobalDocument_.xcu @@ -0,0 +1,31 @@ + + + IMPORT EXPORT ALIEN + com.sun.star.comp.Writer.FilterOptionsDialog + + TEXT_DLG + 0 + txt + generic_Text + + com.sun.star.text.GlobalDocument + + Text - Choose Encoding (Master Document) + + diff --git a/filter/source/config/fragments/filters/Text__encoded___StarWriter_Web_.xcu b/filter/source/config/fragments/filters/Text__encoded___StarWriter_Web_.xcu new file mode 100644 index 000000000..4e2d92d89 --- /dev/null +++ b/filter/source/config/fragments/filters/Text__encoded___StarWriter_Web_.xcu @@ -0,0 +1,31 @@ + + + IMPORT EXPORT ALIEN + com.sun.star.comp.Writer.FilterOptionsDialog + + TEXT_DLG + 0 + txt + generic_Text + + com.sun.star.text.WebDocument + + Text - Choose Encoding (Writer/Web) + + diff --git a/filter/source/config/fragments/filters/UOF_presentation.xcu b/filter/source/config/fragments/filters/UOF_presentation.xcu new file mode 100644 index 000000000..1f8be437b --- /dev/null +++ b/filter/source/config/fragments/filters/UOF_presentation.xcu @@ -0,0 +1,30 @@ + + + 0 + Unified_Office_Format_presentation + com.sun.star.presentation.PresentationDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Impress.XMLOasisImporter,com.sun.star.comp.Impress.XMLOasisExporter,../$(share_subdir_name)/xslt/import/uof/uof2odf_presentation.xsl,../$(share_subdir_name)/xslt/export/uof/odf2uof_presentation.xsl + com.sun.star.comp.Writer.XmlFilterAdaptor + + + Unified Office Format presentation + + IMPORT EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/UOF_spreadsheet.xcu b/filter/source/config/fragments/filters/UOF_spreadsheet.xcu new file mode 100644 index 000000000..91f564307 --- /dev/null +++ b/filter/source/config/fragments/filters/UOF_spreadsheet.xcu @@ -0,0 +1,30 @@ + + + 0 + Unified_Office_Format_spreadsheet + com.sun.star.sheet.SpreadsheetDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Calc.XMLOasisImporter,com.sun.star.comp.Calc.XMLOasisExporter,../$(share_subdir_name)/xslt/import/uof/uof2odf_spreadsheet.xsl,../$(share_subdir_name)/xslt/export/uof/odf2uof_spreadsheet.xsl + com.sun.star.comp.Writer.XmlFilterAdaptor + + + Unified Office Format spreadsheet + + IMPORT EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/UOF_text.xcu b/filter/source/config/fragments/filters/UOF_text.xcu new file mode 100644 index 000000000..e4241f175 --- /dev/null +++ b/filter/source/config/fragments/filters/UOF_text.xcu @@ -0,0 +1,30 @@ + + + 0 + Unified_Office_Format_text + com.sun.star.text.TextDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Writer.XMLOasisImporter,com.sun.star.comp.Writer.XMLOasisExporter,../$(share_subdir_name)/xslt/import/uof/uof2odf_text.xsl,../$(share_subdir_name)/xslt/export/uof/odf2uof_text.xsl + com.sun.star.comp.Writer.XmlFilterAdaptor + + + Unified Office Format text + + IMPORT EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/VisioDocument.xcu b/filter/source/config/fragments/filters/VisioDocument.xcu new file mode 100644 index 000000000..3b43b24db --- /dev/null +++ b/filter/source/config/fragments/filters/VisioDocument.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.VisioImportFilter + + + Microsoft Visio 2000-2013 + + 0 + draw_Visio_Document + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/WEBP___WebP.xcu b/filter/source/config/fragments/filters/WEBP___WebP.xcu new file mode 100644 index 000000000..9c650e3de --- /dev/null +++ b/filter/source/config/fragments/filters/WEBP___WebP.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + WEBP - WebP Image + + 0 + webp_WebP + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/WMF___MS_Windows_Metafile.xcu b/filter/source/config/fragments/filters/WMF___MS_Windows_Metafile.xcu new file mode 100644 index 000000000..12c2034ae --- /dev/null +++ b/filter/source/config/fragments/filters/WMF___MS_Windows_Metafile.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + WMF - Windows Metafile + + 0 + wmf_MS_Windows_Metafile + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/WPS_Lotus_Calc.xcu b/filter/source/config/fragments/filters/WPS_Lotus_Calc.xcu new file mode 100644 index 000000000..1d141826c --- /dev/null +++ b/filter/source/config/fragments/filters/WPS_Lotus_Calc.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + + Lotus Document + + 0 + calc_WPS_Lotus_Document + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/WPS_QPro_Calc.xcu b/filter/source/config/fragments/filters/WPS_QPro_Calc.xcu new file mode 100644 index 000000000..f32b11820 --- /dev/null +++ b/filter/source/config/fragments/filters/WPS_QPro_Calc.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + + QuattroPro Document + + 0 + calc_WPS_QPro_Document + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/WordPerfect.xcu b/filter/source/config/fragments/filters/WordPerfect.xcu new file mode 100644 index 000000000..d26c30369 --- /dev/null +++ b/filter/source/config/fragments/filters/WordPerfect.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.WordPerfectImportFilter + WPD + + WordPerfect Document + + 0 + writer_WordPerfect_Document + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/WordPerfectGraphics.xcu b/filter/source/config/fragments/filters/WordPerfectGraphics.xcu new file mode 100644 index 000000000..54f4f43db --- /dev/null +++ b/filter/source/config/fragments/filters/WordPerfectGraphics.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Draw.WPGImportFilter + + + WordPerfect Graphics + + 0 + draw_WordPerfect_Graphics + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/WriteNow.xcu b/filter/source/config/fragments/filters/WriteNow.xcu new file mode 100644 index 000000000..600e5d617 --- /dev/null +++ b/filter/source/config/fragments/filters/WriteNow.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.Writer.MWAWImportFilter + + + WriteNow Document + + 0 + writer_WriteNow + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/XBM___X_Consortium.xcu b/filter/source/config/fragments/filters/XBM___X_Consortium.xcu new file mode 100644 index 000000000..56d3ff5a9 --- /dev/null +++ b/filter/source/config/fragments/filters/XBM___X_Consortium.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + XBM - X Bitmap + + 0 + xbm_X_Consortium + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/XHTML_Calc_File.xcu b/filter/source/config/fragments/filters/XHTML_Calc_File.xcu new file mode 100644 index 000000000..a13b05dc9 --- /dev/null +++ b/filter/source/config/fragments/filters/XHTML_Calc_File.xcu @@ -0,0 +1,30 @@ + + + 0 + XHTML_File + com.sun.star.sheet.SpreadsheetDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Calc.XMLOasisImporter,com.sun.star.comp.Calc.XMLOasisExporter,,../$(share_subdir_name)/xslt/export/xhtml/opendoc2xhtml.xsl + com.sun.star.comp.Writer.XmlFilterAdaptor + + + XHTML + + EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/XHTML_Draw_File.xcu b/filter/source/config/fragments/filters/XHTML_Draw_File.xcu new file mode 100644 index 000000000..c63283a4e --- /dev/null +++ b/filter/source/config/fragments/filters/XHTML_Draw_File.xcu @@ -0,0 +1,30 @@ + + + 0 + XHTML_File + com.sun.star.drawing.DrawingDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Draw.XMLOasisImporter,com.sun.star.comp.Draw.XMLOasisExporter,,../$(share_subdir_name)/xslt/export/xhtml/opendoc2xhtml.xsl + com.sun.star.comp.Writer.XmlFilterAdaptor + + + XHTML + + EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/XHTML_Impress_File.xcu b/filter/source/config/fragments/filters/XHTML_Impress_File.xcu new file mode 100644 index 000000000..f8431fe16 --- /dev/null +++ b/filter/source/config/fragments/filters/XHTML_Impress_File.xcu @@ -0,0 +1,30 @@ + + + 0 + XHTML_File + com.sun.star.presentation.PresentationDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Impress.XMLOasisImporter,com.sun.star.comp.Impress.XMLOasisExporter,,../$(share_subdir_name)/xslt/export/xhtml/opendoc2xhtml.xsl + com.sun.star.comp.Writer.XmlFilterAdaptor + + + XHTML + + EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/XHTML_Writer_File.xcu b/filter/source/config/fragments/filters/XHTML_Writer_File.xcu new file mode 100644 index 000000000..e50ec3077 --- /dev/null +++ b/filter/source/config/fragments/filters/XHTML_Writer_File.xcu @@ -0,0 +1,30 @@ + + + 0 + XHTML_File + com.sun.star.text.TextDocument + + com.sun.star.documentconversion.XSLTFilter,,com.sun.star.comp.Writer.XMLOasisImporter,com.sun.star.comp.Writer.XMLOasisExporter,,../$(share_subdir_name)/xslt/export/xhtml/opendoc2xhtml.xsl,,true + com.sun.star.comp.Writer.XmlFilterAdaptor + + + XHTML + + EXPORT ALIEN 3RDPARTYFILTER + diff --git a/filter/source/config/fragments/filters/XPM.xcu b/filter/source/config/fragments/filters/XPM.xcu new file mode 100644 index 000000000..8a67b710f --- /dev/null +++ b/filter/source/config/fragments/filters/XPM.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN EXOTIC + + + + + XPM - X PixMap + + 0 + xpm_XPM + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/ZMFDocument.xcu b/filter/source/config/fragments/filters/ZMFDocument.xcu new file mode 100644 index 000000000..b72449df3 --- /dev/null +++ b/filter/source/config/fragments/filters/ZMFDocument.xcu @@ -0,0 +1,13 @@ + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + org.libreoffice.comp.Draw.ZMFImportFilter + + + Zoner Callisto/Draw + + 0 + draw_ZMF_Document + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/calc8.xcu b/filter/source/config/fragments/filters/calc8.xcu new file mode 100644 index 000000000..e6f0d6251 --- /dev/null +++ b/filter/source/config/fragments/filters/calc8.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE OWN DEFAULT ENCRYPTION PASSWORDTOMODIFY GPGENCRYPTION + + + + 6800 + calc8 + + com.sun.star.sheet.SpreadsheetDocument + + ODF Spreadsheet + + diff --git a/filter/source/config/fragments/filters/calc8_template.xcu b/filter/source/config/fragments/filters/calc8_template.xcu new file mode 100644 index 000000000..4752a45f1 --- /dev/null +++ b/filter/source/config/fragments/filters/calc8_template.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH OWN ENCRYPTION PASSWORDTOMODIFY + + + + 6800 + calc8_template + + com.sun.star.sheet.SpreadsheetDocument + + ODF Spreadsheet Template + + diff --git a/filter/source/config/fragments/filters/calc_Gnumeric.xcu b/filter/source/config/fragments/filters/calc_Gnumeric.xcu new file mode 100644 index 000000000..cc350fd62 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_Gnumeric.xcu @@ -0,0 +1,29 @@ + + + IMPORT ALIEN PREFERRED + + + + Gnumeric XML + + com.sun.star.sheet.SpreadsheetDocument + + Gnumeric Spreadsheet + + diff --git a/filter/source/config/fragments/filters/calc_HTML_WebQuery.xcu b/filter/source/config/fragments/filters/calc_HTML_WebQuery.xcu new file mode 100644 index 000000000..c91d92880 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_HTML_WebQuery.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN USEOPTIONS PREFERRED + com.sun.star.comp.Calc.FilterOptionsDialog + + + 0 + generic_HTML + + com.sun.star.sheet.SpreadsheetDocument + + Web Page Query (Calc) + + diff --git a/filter/source/config/fragments/filters/calc_MS_Excel_2007_Binary.xcu b/filter/source/config/fragments/filters/calc_MS_Excel_2007_Binary.xcu new file mode 100644 index 000000000..24743cf86 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_MS_Excel_2007_Binary.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER PREFERRED + + com.sun.star.comp.oox.xls.ExcelFilter + + + MS Excel 2007 Binary + + com.sun.star.sheet.SpreadsheetDocument + + Microsoft Excel 2007 Binary + + diff --git a/filter/source/config/fragments/filters/calc_MS_Excel_2007_VBA_XML.xcu b/filter/source/config/fragments/filters/calc_MS_Excel_2007_VBA_XML.xcu new file mode 100644 index 000000000..ffeee2c63 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_MS_Excel_2007_VBA_XML.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY + + com.sun.star.comp.oox.xls.ExcelFilter + macro-enabled + + MS Excel 2007 VBA XML + + com.sun.star.sheet.SpreadsheetDocument + + Excel 2007–365 (macro-enabled) + + diff --git a/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML.xcu b/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML.xcu new file mode 100644 index 000000000..bc0ab95e2 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY SUPPORTSSIGNING + + com.sun.star.comp.oox.xls.ExcelFilter + + + MS Excel 2007 XML + + com.sun.star.sheet.SpreadsheetDocument + + Excel 2007–365 + + diff --git a/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu b/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu new file mode 100644 index 000000000..515b89152 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_MS_Excel_2007_XML_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH + + com.sun.star.comp.oox.xls.ExcelFilter + + + MS Excel 2007 XML Template + + com.sun.star.sheet.SpreadsheetDocument + + Excel 2007–365 Template + + diff --git a/filter/source/config/fragments/filters/calc_OOXML.xcu b/filter/source/config/fragments/filters/calc_OOXML.xcu new file mode 100644 index 000000000..2bc098129 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_OOXML.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY + + com.sun.star.comp.oox.xls.ExcelFilter + OOXML + 1 + Office Open XML Spreadsheet + + com.sun.star.sheet.SpreadsheetDocument + + Office Open XML Spreadsheet + + diff --git a/filter/source/config/fragments/filters/calc_OOXML_Template.xcu b/filter/source/config/fragments/filters/calc_OOXML_Template.xcu new file mode 100644 index 000000000..b65a75608 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_OOXML_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH + + com.sun.star.comp.oox.xls.ExcelFilter + OOXML + 1 + Office Open XML Spreadsheet Template + + com.sun.star.sheet.SpreadsheetDocument + + Office Open XML Spreadsheet Template + + diff --git a/filter/source/config/fragments/filters/calc_StarOffice_XML_Calc_Template.xcu b/filter/source/config/fragments/filters/calc_StarOffice_XML_Calc_Template.xcu new file mode 100644 index 000000000..3c05efa39 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_StarOffice_XML_Calc_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE TEMPLATEPATH OWN ALIEN ENCRYPTION + + + + 6200 + calc_StarOffice_XML_Calc_Template + + com.sun.star.sheet.SpreadsheetDocument + + OpenOffice.org 1.0 Spreadsheet Template + + diff --git a/filter/source/config/fragments/filters/calc_jpg_Export.xcu b/filter/source/config/fragments/filters/calc_jpg_Export.xcu new file mode 100644 index 000000000..80a72878f --- /dev/null +++ b/filter/source/config/fragments/filters/calc_jpg_Export.xcu @@ -0,0 +1,20 @@ + + + EXPORT ALIEN 3RDPARTYFILTER SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + JPEG - Joint Photographic Experts Group + + 0 + jpg_JPEG + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/calc_pdf_Export.xcu b/filter/source/config/fragments/filters/calc_pdf_Export.xcu new file mode 100644 index 000000000..897d6ddb7 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_pdf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.PDF.PDFDialog + com.sun.star.comp.PDF.PDFFilter + + + PDF - Portable Document Format + + 0 + pdf_Portable_Document_Format + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/calc_png_Export.xcu b/filter/source/config/fragments/filters/calc_png_Export.xcu new file mode 100644 index 000000000..bdc49e484 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_png_Export.xcu @@ -0,0 +1,20 @@ + + + EXPORT ALIEN 3RDPARTYFILTER SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + PNG - Portable Network Graphics + + 0 + png_Portable_Network_Graphic + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/calc_svg_Export.xcu b/filter/source/config/fragments/filters/calc_svg_Export.xcu new file mode 100644 index 000000000..703ce82e9 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_svg_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER INTERNAL NOTINFILEDIALOG + + com.sun.star.comp.Draw.SVGFilter + + + SVG - Scalable Vector Graphics + + 0 + svg_Scalable_Vector_Graphics + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/calc_webp_Export.xcu b/filter/source/config/fragments/filters/calc_webp_Export.xcu new file mode 100644 index 000000000..a6e5d18a3 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_webp_Export.xcu @@ -0,0 +1,20 @@ + + + EXPORT ALIEN 3RDPARTYFILTER SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + WEBP - WebP Image + + 0 + webp_WebP + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/chart8.xcu b/filter/source/config/fragments/filters/chart8.xcu new file mode 100644 index 000000000..6bcfbd88d --- /dev/null +++ b/filter/source/config/fragments/filters/chart8.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT OWN DEFAULT NOTINFILEDIALOG NOTINCHOOSER PREFERRED ENCRYPTION + + com.sun.star.comp.chart2.XMLFilter + XML + 6800 + chart8 + + com.sun.star.chart2.ChartDocument + + ODF Chart + + diff --git a/filter/source/config/fragments/filters/dBase.xcu b/filter/source/config/fragments/filters/dBase.xcu new file mode 100644 index 000000000..59aaf31a9 --- /dev/null +++ b/filter/source/config/fragments/filters/dBase.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN + com.sun.star.comp.Calc.FilterOptionsDialog + + + + dBASE + + 0 + calc_dBase + + com.sun.star.sheet.SpreadsheetDocument + diff --git a/filter/source/config/fragments/filters/draw8.xcu b/filter/source/config/fragments/filters/draw8.xcu new file mode 100644 index 000000000..3a9656ec4 --- /dev/null +++ b/filter/source/config/fragments/filters/draw8.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE OWN DEFAULT PREFERRED ENCRYPTION PASSWORDTOMODIFY GPGENCRYPTION + + + XML + 6800 + draw8 + + com.sun.star.drawing.DrawingDocument + + ODF Drawing + + diff --git a/filter/source/config/fragments/filters/draw8_template.xcu b/filter/source/config/fragments/filters/draw8_template.xcu new file mode 100644 index 000000000..ac4f262d5 --- /dev/null +++ b/filter/source/config/fragments/filters/draw8_template.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH OWN ENCRYPTION PASSWORDTOMODIFY + + + CXMLV + 6800 + draw8_template + + com.sun.star.drawing.DrawingDocument + + ODF Drawing Template + + diff --git a/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base.xcu b/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base.xcu new file mode 100644 index 000000000..a19508c37 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PCD - Kodak Photo CD (768x512) + + 0 + pcd_Photo_CD_Base + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base16.xcu b/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base16.xcu new file mode 100644 index 000000000..54fc3855d --- /dev/null +++ b/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base16.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PCD - Kodak Photo CD (192x128) + + 0 + pcd_Photo_CD_Base16 + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base4.xcu b/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base4.xcu new file mode 100644 index 000000000..1674a92c0 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_PCD_Photo_CD_Base4.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN + + + + + PCD - Kodak Photo CD (384x256) + + 0 + pcd_Photo_CD_Base4 + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_StarOffice_XML_Draw_Template.xcu b/filter/source/config/fragments/filters/draw_StarOffice_XML_Draw_Template.xcu new file mode 100644 index 000000000..783027713 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_StarOffice_XML_Draw_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE TEMPLATEPATH OWN ALIEN ENCRYPTION + + + CXMLV + 6200 + draw_StarOffice_XML_Draw_Template + + com.sun.star.drawing.DrawingDocument + + OpenOffice.org 1.0 Drawing Template + + diff --git a/filter/source/config/fragments/filters/draw_bmp_Export.xcu b/filter/source/config/fragments/filters/draw_bmp_Export.xcu new file mode 100644 index 000000000..66f790853 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_bmp_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + BMP - Windows Bitmap + + 0 + bmp_MS_Windows + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_emf_Export.xcu b/filter/source/config/fragments/filters/draw_emf_Export.xcu new file mode 100644 index 000000000..b8d95ca8d --- /dev/null +++ b/filter/source/config/fragments/filters/draw_emf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + EMF - Enhanced Metafile + + 0 + emf_MS_Windows_Metafile + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_eps_Export.xcu b/filter/source/config/fragments/filters/draw_eps_Export.xcu new file mode 100644 index 000000000..821271e8b --- /dev/null +++ b/filter/source/config/fragments/filters/draw_eps_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + EPS - Encapsulated PostScript + + 0 + eps_Encapsulated_PostScript + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_gif_Export.xcu b/filter/source/config/fragments/filters/draw_gif_Export.xcu new file mode 100644 index 000000000..b86f272e3 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_gif_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + GIF - Graphics Interchange Format + + 0 + gif_Graphics_Interchange + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_html_Export.xcu b/filter/source/config/fragments/filters/draw_html_Export.xcu new file mode 100644 index 000000000..179c7bb7e --- /dev/null +++ b/filter/source/config/fragments/filters/draw_html_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN + com.sun.star.comp.draw.SdHtmlOptionsDialog + + + 0 + graphic_HTML + + com.sun.star.drawing.DrawingDocument + + HTML Document (Draw) + + diff --git a/filter/source/config/fragments/filters/draw_jpg_Export.xcu b/filter/source/config/fragments/filters/draw_jpg_Export.xcu new file mode 100644 index 000000000..67b64bbf9 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_jpg_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + JPEG - Joint Photographic Experts Group + + 0 + jpg_JPEG + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_pdf_Export.xcu b/filter/source/config/fragments/filters/draw_pdf_Export.xcu new file mode 100644 index 000000000..89816e454 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_pdf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.PDF.PDFDialog + com.sun.star.comp.PDF.PDFFilter + + + PDF - Portable Document Format + + 0 + pdf_Portable_Document_Format + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_png_Export.xcu b/filter/source/config/fragments/filters/draw_png_Export.xcu new file mode 100644 index 000000000..5ba112cc5 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_png_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + PNG - Portable Network Graphics + + 0 + png_Portable_Network_Graphic + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_svg_Export.xcu b/filter/source/config/fragments/filters/draw_svg_Export.xcu new file mode 100644 index 000000000..c7816f3d7 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_svg_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Draw.SVGFilter + + + SVG - Scalable Vector Graphics + + 0 + svg_Scalable_Vector_Graphics + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_tif_Export.xcu b/filter/source/config/fragments/filters/draw_tif_Export.xcu new file mode 100644 index 000000000..43bae82fd --- /dev/null +++ b/filter/source/config/fragments/filters/draw_tif_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + + + + + TIFF - Tagged Image File Format + + 0 + tif_Tag_Image_File + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_webp_Export.xcu b/filter/source/config/fragments/filters/draw_webp_Export.xcu new file mode 100644 index 000000000..e6da69197 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_webp_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + WEBP - WebP Image + + 0 + webp_WebP + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/draw_wmf_Export.xcu b/filter/source/config/fragments/filters/draw_wmf_Export.xcu new file mode 100644 index 000000000..308cd9bee --- /dev/null +++ b/filter/source/config/fragments/filters/draw_wmf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + WMF - Windows Metafile + + 0 + wmf_MS_Windows_Metafile + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/impress8.xcu b/filter/source/config/fragments/filters/impress8.xcu new file mode 100644 index 000000000..527d83ed0 --- /dev/null +++ b/filter/source/config/fragments/filters/impress8.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE OWN DEFAULT PREFERRED ENCRYPTION PASSWORDTOMODIFY GPGENCRYPTION + + + XML + 6800 + impress8 + + com.sun.star.presentation.PresentationDocument + + ODF Presentation + + diff --git a/filter/source/config/fragments/filters/impress8_draw.xcu b/filter/source/config/fragments/filters/impress8_draw.xcu new file mode 100644 index 000000000..1f3e53c97 --- /dev/null +++ b/filter/source/config/fragments/filters/impress8_draw.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE OWN ENCRYPTION PASSWORDTOMODIFY + + + XML + 6800 + draw8 + + com.sun.star.presentation.PresentationDocument + + ODF Drawing (Impress) + + diff --git a/filter/source/config/fragments/filters/impress8_template.xcu b/filter/source/config/fragments/filters/impress8_template.xcu new file mode 100644 index 000000000..e2f4393d9 --- /dev/null +++ b/filter/source/config/fragments/filters/impress8_template.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH OWN ENCRYPTION PASSWORDTOMODIFY + + + CXMLV + 6800 + impress8_template + + com.sun.star.presentation.PresentationDocument + + ODF Presentation Template + + diff --git a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu new file mode 100644 index 000000000..446316310 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY SUPPORTSSIGNING + + com.sun.star.comp.oox.ppt.PowerPointImport + + + MS PowerPoint 2007 XML + + com.sun.star.presentation.PresentationDocument + + PowerPoint 2007–365 + + diff --git a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu new file mode 100644 index 000000000..c5e5e767f --- /dev/null +++ b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu @@ -0,0 +1,28 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED STARTPRESENTATION ENCRYPTION PASSWORDTOMODIFY + + com.sun.star.comp.oox.ppt.PowerPointImport + + PowerPoint 2007–365 AutoPlay + + MS PowerPoint 2007 XML AutoPlay + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_Template.xcu b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_Template.xcu new file mode 100644 index 000000000..cba3ea325 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_Template.xcu @@ -0,0 +1,28 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH PREFERRED + + com.sun.star.comp.oox.ppt.PowerPointImport + + PowerPoint 2007–365 Template + + MS PowerPoint 2007 XML Template + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_VBA.xcu b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_VBA.xcu new file mode 100644 index 000000000..de44648c5 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_VBA.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY SUPPORTSSIGNING + + com.sun.star.comp.oox.ppt.PowerPointImport + macro-enabled + + MS PowerPoint 2007 XML VBA + + com.sun.star.presentation.PresentationDocument + + PowerPoint 2007–365 VBA + + diff --git a/filter/source/config/fragments/filters/impress_OOXML.xcu b/filter/source/config/fragments/filters/impress_OOXML.xcu new file mode 100644 index 000000000..c585e4b26 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_OOXML.xcu @@ -0,0 +1,29 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY + + com.sun.star.comp.oox.ppt.PowerPointImport + OOXML + Office Open XML Presentation + + 1 + Office Open XML Presentation + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu b/filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu new file mode 100644 index 000000000..dbadb8bd2 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu @@ -0,0 +1,28 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED STARTPRESENTATION ENCRYPTION PASSWORDTOMODIFY + + com.sun.star.comp.oox.ppt.PowerPointImport + + Office Open XML Presentation AutoPlay + + Office Open XML Presentation AutoPlay + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_OOXML_Template.xcu b/filter/source/config/fragments/filters/impress_OOXML_Template.xcu new file mode 100644 index 000000000..b0ce4c8ef --- /dev/null +++ b/filter/source/config/fragments/filters/impress_OOXML_Template.xcu @@ -0,0 +1,29 @@ + + + IMPORT EXPORT ALIEN 3RDPARTYFILTER TEMPLATE TEMPLATEPATH PREFERRED + + com.sun.star.comp.oox.ppt.PowerPointImport + OOXML + Office Open XML Presentation Template + + 1 + Office Open XML Presentation Template + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_StarOffice_XML_Draw.xcu b/filter/source/config/fragments/filters/impress_StarOffice_XML_Draw.xcu new file mode 100644 index 000000000..65ac76df6 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_StarOffice_XML_Draw.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE OWN ALIEN ENCRYPTION + + + XML + 6200 + draw_StarOffice_XML_Draw + + com.sun.star.presentation.PresentationDocument + + OpenOffice.org 1.0 Drawing (Impress) + + diff --git a/filter/source/config/fragments/filters/impress_StarOffice_XML_Impress_Template.xcu b/filter/source/config/fragments/filters/impress_StarOffice_XML_Impress_Template.xcu new file mode 100644 index 000000000..02c142e66 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_StarOffice_XML_Impress_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE TEMPLATEPATH OWN ALIEN ENCRYPTION + + + CXMLV + 6200 + impress_StarOffice_XML_Impress_Template + + com.sun.star.presentation.PresentationDocument + + OpenOffice.org 1.0 Presentation Template + + diff --git a/filter/source/config/fragments/filters/impress_bmp_Export.xcu b/filter/source/config/fragments/filters/impress_bmp_Export.xcu new file mode 100644 index 000000000..2cb2aba76 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_bmp_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + BMP - Windows Bitmap + + 0 + bmp_MS_Windows + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_emf_Export.xcu b/filter/source/config/fragments/filters/impress_emf_Export.xcu new file mode 100644 index 000000000..d90db357a --- /dev/null +++ b/filter/source/config/fragments/filters/impress_emf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + EMF - Enhanced Metafile + + 0 + emf_MS_Windows_Metafile + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_eps_Export.xcu b/filter/source/config/fragments/filters/impress_eps_Export.xcu new file mode 100644 index 000000000..6256970d1 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_eps_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + EPS - Encapsulated PostScript + + 0 + eps_Encapsulated_PostScript + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_gif_Export.xcu b/filter/source/config/fragments/filters/impress_gif_Export.xcu new file mode 100644 index 000000000..874770a85 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_gif_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + GIF - Graphics Interchange Format + + 0 + gif_Graphics_Interchange + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_html_Export.xcu b/filter/source/config/fragments/filters/impress_html_Export.xcu new file mode 100644 index 000000000..65a5c5dad --- /dev/null +++ b/filter/source/config/fragments/filters/impress_html_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN + com.sun.star.comp.draw.SdHtmlOptionsDialog + + + 0 + graphic_HTML + + com.sun.star.presentation.PresentationDocument + + HTML Document (Impress) + + diff --git a/filter/source/config/fragments/filters/impress_jpg_Export.xcu b/filter/source/config/fragments/filters/impress_jpg_Export.xcu new file mode 100644 index 000000000..edbeee1b1 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_jpg_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + JPEG - Joint Photographic Experts Group + + 0 + jpg_JPEG + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_pdf_Export.xcu b/filter/source/config/fragments/filters/impress_pdf_Export.xcu new file mode 100644 index 000000000..b95554753 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_pdf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.PDF.PDFDialog + com.sun.star.comp.PDF.PDFFilter + + + PDF - Portable Document Format + + 0 + pdf_Portable_Document_Format + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_png_Export.xcu b/filter/source/config/fragments/filters/impress_png_Export.xcu new file mode 100644 index 000000000..f2de7528d --- /dev/null +++ b/filter/source/config/fragments/filters/impress_png_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + PNG - Portable Network Graphics + + 0 + png_Portable_Network_Graphic + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_svg_Export.xcu b/filter/source/config/fragments/filters/impress_svg_Export.xcu new file mode 100644 index 000000000..21cb8aec2 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_svg_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Draw.SVGFilter + + + SVG - Scalable Vector Graphics + + 0 + svg_Scalable_Vector_Graphics + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_tif_Export.xcu b/filter/source/config/fragments/filters/impress_tif_Export.xcu new file mode 100644 index 000000000..4951d6fcb --- /dev/null +++ b/filter/source/config/fragments/filters/impress_tif_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + + + + + TIFF - Tagged Image File Format + + 0 + tif_Tag_Image_File + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_webp_Export.xcu b/filter/source/config/fragments/filters/impress_webp_Export.xcu new file mode 100644 index 000000000..00284a272 --- /dev/null +++ b/filter/source/config/fragments/filters/impress_webp_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + WEBP - WebP Image + + 0 + webp_WebP + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/impress_wmf_Export.xcu b/filter/source/config/fragments/filters/impress_wmf_Export.xcu new file mode 100644 index 000000000..dbb65bdaf --- /dev/null +++ b/filter/source/config/fragments/filters/impress_wmf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN SUPPORTSSELECTION + com.sun.star.svtools.SvFilterOptionsDialog + + + + WMF - Windows Metafile + + 0 + wmf_MS_Windows_Metafile + + com.sun.star.presentation.PresentationDocument + diff --git a/filter/source/config/fragments/filters/math8.xcu b/filter/source/config/fragments/filters/math8.xcu new file mode 100644 index 000000000..0287f7ffa --- /dev/null +++ b/filter/source/config/fragments/filters/math8.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE OWN DEFAULT ENCRYPTION GPGENCRYPTION + + + + 6800 + math8 + + com.sun.star.formula.FormulaProperties + + ODF Formula + + diff --git a/filter/source/config/fragments/filters/math_pdf_Export.xcu b/filter/source/config/fragments/filters/math_pdf_Export.xcu new file mode 100644 index 000000000..dd81c453b --- /dev/null +++ b/filter/source/config/fragments/filters/math_pdf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.PDF.PDFDialog + com.sun.star.comp.PDF.PDFFilter + + + PDF - Portable Document Format + + 0 + pdf_Portable_Document_Format + + com.sun.star.formula.FormulaProperties + diff --git a/filter/source/config/fragments/filters/mov__MOV.xcu b/filter/source/config/fragments/filters/mov__MOV.xcu new file mode 100644 index 000000000..168188449 --- /dev/null +++ b/filter/source/config/fragments/filters/mov__MOV.xcu @@ -0,0 +1,21 @@ + + + IMPORT ALIEN + + + + + MOV - QuickTime File Format + + 0 + mov_MOV + + com.sun.star.drawing.DrawingDocument + diff --git a/filter/source/config/fragments/filters/writer8.xcu b/filter/source/config/fragments/filters/writer8.xcu new file mode 100644 index 000000000..def9d57d5 --- /dev/null +++ b/filter/source/config/fragments/filters/writer8.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE OWN DEFAULT PREFERRED ENCRYPTION PASSWORDTOMODIFY GPGENCRYPTION + + + CXML + 6800 + writer8 + + com.sun.star.text.TextDocument + + ODF Text Document + + diff --git a/filter/source/config/fragments/filters/writer8_template.xcu b/filter/source/config/fragments/filters/writer8_template.xcu new file mode 100644 index 000000000..286b907a7 --- /dev/null +++ b/filter/source/config/fragments/filters/writer8_template.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH OWN ENCRYPTION PASSWORDTOMODIFY + + + CXMLV + 6800 + writer8_template + + com.sun.star.text.TextDocument + + ODF Text Document Template + + diff --git a/filter/source/config/fragments/filters/writer_MIZI_Hwp_97.xcu b/filter/source/config/fragments/filters/writer_MIZI_Hwp_97.xcu new file mode 100644 index 000000000..2b717c8cb --- /dev/null +++ b/filter/source/config/fragments/filters/writer_MIZI_Hwp_97.xcu @@ -0,0 +1,30 @@ + + + IMPORT ALIEN 3RDPARTYFILTER EXOTIC + + com.sun.comp.hwpimport.HwpImportFilter + + + Hangul WP 97 + + 0 + writer_MIZI_Hwp_97 + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writer_StarOffice_XML_Writer_Template.xcu b/filter/source/config/fragments/filters/writer_StarOffice_XML_Writer_Template.xcu new file mode 100644 index 000000000..fc0066a4c --- /dev/null +++ b/filter/source/config/fragments/filters/writer_StarOffice_XML_Writer_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE TEMPLATEPATH OWN ALIEN ENCRYPTION + + + CXMLV + 6200 + writer_StarOffice_XML_Writer_Template + + com.sun.star.text.TextDocument + + OpenOffice.org 1.0 Text Document Template + + diff --git a/filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer.xcu b/filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer.xcu new file mode 100644 index 000000000..a01a61c5c --- /dev/null +++ b/filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer.xcu @@ -0,0 +1,30 @@ + + + TEMPLATE ALIEN ENCRYPTION + + + CXML + 6200 + writer_StarOffice_XML_Writer + + com.sun.star.text.GlobalDocument + + OpenOffice.org 1.0 Text Document + + diff --git a/filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu b/filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu new file mode 100644 index 000000000..015aefe17 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE OWN ALIEN PREFERRED ENCRYPTION + + + CXML + 6200 + writer_globaldocument_StarOffice_XML_Writer_GlobalDocument + + com.sun.star.text.GlobalDocument + + OpenOffice.org 1.0 Master Document + + diff --git a/filter/source/config/fragments/filters/writer_globaldocument_pdf_Export.xcu b/filter/source/config/fragments/filters/writer_globaldocument_pdf_Export.xcu new file mode 100644 index 000000000..93b9306e9 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_globaldocument_pdf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.PDF.PDFDialog + com.sun.star.comp.PDF.PDFFilter + + + PDF - Portable Document Format + + 0 + pdf_Portable_Document_Format + + com.sun.star.text.GlobalDocument + diff --git a/filter/source/config/fragments/filters/writer_indexing_export.xcu b/filter/source/config/fragments/filters/writer_indexing_export.xcu new file mode 100644 index 000000000..28cbe5b5b --- /dev/null +++ b/filter/source/config/fragments/filters/writer_indexing_export.xcu @@ -0,0 +1,22 @@ + + + + EXPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Writer.IndexingExportFilter + + + Writer Indexing Export XML + + 0 + writer_indexing_export_xml + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writer_jpg_Export.xcu b/filter/source/config/fragments/filters/writer_jpg_Export.xcu new file mode 100644 index 000000000..f3b1be924 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_jpg_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + JPEG - Joint Photographic Experts Group + + 0 + jpg_JPEG + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writer_layout_dump.xcu b/filter/source/config/fragments/filters/writer_layout_dump.xcu new file mode 100644 index 000000000..e7ae50bcf --- /dev/null +++ b/filter/source/config/fragments/filters/writer_layout_dump.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + + com.sun.star.comp.Writer.LayoutDump + + + Writer Layout XML + + 0 + writer_layout_dump_xml + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writer_pdf_Export.xcu b/filter/source/config/fragments/filters/writer_pdf_Export.xcu new file mode 100644 index 000000000..749c28504 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_pdf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.PDF.PDFDialog + com.sun.star.comp.PDF.PDFFilter + + + PDF - Portable Document Format + + 0 + pdf_Portable_Document_Format + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writer_png_Export.xcu b/filter/source/config/fragments/filters/writer_png_Export.xcu new file mode 100644 index 000000000..1ea189ee6 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_png_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + PNG - Portable Network Graphics + + 0 + png_Portable_Network_Graphic + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writer_svg_Export.xcu b/filter/source/config/fragments/filters/writer_svg_Export.xcu new file mode 100644 index 000000000..c08576cdd --- /dev/null +++ b/filter/source/config/fragments/filters/writer_svg_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER INTERNAL NOTINFILEDIALOG + + com.sun.star.comp.Draw.SVGFilter + + + SVG - Scalable Vector Graphics + + 0 + svg_Scalable_Vector_Graphics + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writer_web_HTML_help.xcu b/filter/source/config/fragments/filters/writer_web_HTML_help.xcu new file mode 100644 index 000000000..4e3cb6a6c --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_HTML_help.xcu @@ -0,0 +1,30 @@ + + + IMPORT INTERNAL NOTINFILEDIALOG READONLY + + + HTML_HELP + + Help content + + 0 + writer_web_HTML_help + + com.sun.star.text.WebDocument + diff --git a/filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer.xcu b/filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer.xcu new file mode 100644 index 000000000..5cfbfc891 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer.xcu @@ -0,0 +1,30 @@ + + + EXPORT TEMPLATE ALIEN ENCRYPTION + + + CXML + 6200 + writer_StarOffice_XML_Writer + + com.sun.star.text.WebDocument + + OpenOffice.org 1.0 Text Document (Writer/Web) + + diff --git a/filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer_Web_Template.xcu b/filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer_Web_Template.xcu new file mode 100644 index 000000000..70b6a8f59 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_StarOffice_XML_Writer_Web_Template.xcu @@ -0,0 +1,30 @@ + + + IMPORT TEMPLATE TEMPLATEPATH OWN ALIEN ENCRYPTION + + + CXMLVWEB + 6200 + writer_web_StarOffice_XML_Writer_Web_Template + + com.sun.star.text.WebDocument + + OpenOffice.org 1.0 HTML Template + + diff --git a/filter/source/config/fragments/filters/writer_web_jpg_Export.xcu b/filter/source/config/fragments/filters/writer_web_jpg_Export.xcu new file mode 100644 index 000000000..ddcc62b36 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_jpg_Export.xcu @@ -0,0 +1,21 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + JPEG - Joint Photographic Experts Group + + 0 + jpg_JPEG + + com.sun.star.text.WebDocument + diff --git a/filter/source/config/fragments/filters/writer_web_pdf_Export.xcu b/filter/source/config/fragments/filters/writer_web_pdf_Export.xcu new file mode 100644 index 000000000..00f86e544 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_pdf_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.comp.PDF.PDFDialog + com.sun.star.comp.PDF.PDFFilter + + + PDF - Portable Document Format + + 0 + pdf_Portable_Document_Format + + com.sun.star.text.WebDocument + diff --git a/filter/source/config/fragments/filters/writer_web_png_Export.xcu b/filter/source/config/fragments/filters/writer_web_png_Export.xcu new file mode 100644 index 000000000..4c44173bf --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_png_Export.xcu @@ -0,0 +1,21 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + PNG - Portable Network Graphics + + 0 + png_Portable_Network_Graphic + + com.sun.star.text.WebDocument + diff --git a/filter/source/config/fragments/filters/writer_web_webp_Export.xcu b/filter/source/config/fragments/filters/writer_web_webp_Export.xcu new file mode 100644 index 000000000..5273bb722 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_webp_Export.xcu @@ -0,0 +1,21 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + WEBP - WebP Image + + 0 + webp_WebP + + com.sun.star.text.WebDocument + diff --git a/filter/source/config/fragments/filters/writer_webp_Export.xcu b/filter/source/config/fragments/filters/writer_webp_Export.xcu new file mode 100644 index 000000000..ceb56a8c0 --- /dev/null +++ b/filter/source/config/fragments/filters/writer_webp_Export.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN 3RDPARTYFILTER + com.sun.star.svtools.SvFilterOptionsDialog + com.sun.star.comp.GraphicExportFilter + + + WEBP - WebP Image + + 0 + webp_WebP + + com.sun.star.text.TextDocument + diff --git a/filter/source/config/fragments/filters/writerglobal8.xcu b/filter/source/config/fragments/filters/writerglobal8.xcu new file mode 100644 index 000000000..ea2594d07 --- /dev/null +++ b/filter/source/config/fragments/filters/writerglobal8.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE OWN PREFERRED ENCRYPTION PASSWORDTOMODIFY + + + CXML + 6800 + writerglobal8 + + com.sun.star.text.GlobalDocument + + ODF Master Document + + diff --git a/filter/source/config/fragments/filters/writerglobal8_HTML.xcu b/filter/source/config/fragments/filters/writerglobal8_HTML.xcu new file mode 100644 index 000000000..1e8534a86 --- /dev/null +++ b/filter/source/config/fragments/filters/writerglobal8_HTML.xcu @@ -0,0 +1,30 @@ + + + EXPORT ALIEN + + + HTML + 0 + generic_HTML + + com.sun.star.text.GlobalDocument + + HTML (Writer/Global) + + diff --git a/filter/source/config/fragments/filters/writerglobal8_template.xcu b/filter/source/config/fragments/filters/writerglobal8_template.xcu new file mode 100644 index 000000000..699006015 --- /dev/null +++ b/filter/source/config/fragments/filters/writerglobal8_template.xcu @@ -0,0 +1,20 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH OWN ENCRYPTION PASSWORDTOMODIFY + + + CXMLV + 6800 + writerglobal8_template + + com.sun.star.text.GlobalDocument + + ODF Master Document Template + + diff --git a/filter/source/config/fragments/filters/writerglobal8_writer.xcu b/filter/source/config/fragments/filters/writerglobal8_writer.xcu new file mode 100644 index 000000000..24d06b212 --- /dev/null +++ b/filter/source/config/fragments/filters/writerglobal8_writer.xcu @@ -0,0 +1,30 @@ + + + EXPORT TEMPLATE DEFAULT ENCRYPTION PASSWORDTOMODIFY + + + CXML + 6800 + writer8 + + com.sun.star.text.GlobalDocument + + ODF Text Document + + diff --git a/filter/source/config/fragments/filters/writerweb8_writer.xcu b/filter/source/config/fragments/filters/writerweb8_writer.xcu new file mode 100644 index 000000000..7e18ba6d9 --- /dev/null +++ b/filter/source/config/fragments/filters/writerweb8_writer.xcu @@ -0,0 +1,30 @@ + + + EXPORT TEMPLATE ENCRYPTION PASSWORDTOMODIFY + + + CXML + 6800 + writer8 + + com.sun.star.text.WebDocument + + Text (Writer/Web) + + diff --git a/filter/source/config/fragments/filters/writerweb8_writer_template.xcu b/filter/source/config/fragments/filters/writerweb8_writer_template.xcu new file mode 100644 index 000000000..b6e9bbd3d --- /dev/null +++ b/filter/source/config/fragments/filters/writerweb8_writer_template.xcu @@ -0,0 +1,30 @@ + + + IMPORT EXPORT TEMPLATE TEMPLATEPATH OWN ENCRYPTION PASSWORDTOMODIFY + + + CXMLVWEB + 6800 + writerweb8_writer_template + + com.sun.star.text.WebDocument + + HTML Document Template + + diff --git a/filter/source/config/fragments/frameloaders/com_sun_star_comp_chart2_ChartFrameLoader.xcu b/filter/source/config/fragments/frameloaders/com_sun_star_comp_chart2_ChartFrameLoader.xcu new file mode 100644 index 000000000..0234d59ed --- /dev/null +++ b/filter/source/config/fragments/frameloaders/com_sun_star_comp_chart2_ChartFrameLoader.xcu @@ -0,0 +1,20 @@ + + + chart_StarOffice_XML_Chart chart8 chart_StarChart_50 chart_StarChart_40 chart_StarChart_30 + diff --git a/filter/source/config/fragments/frameloaders/com_sun_star_frame_Bibliography.xcu b/filter/source/config/fragments/frameloaders/com_sun_star_frame_Bibliography.xcu new file mode 100644 index 000000000..b7d53d62e --- /dev/null +++ b/filter/source/config/fragments/frameloaders/com_sun_star_frame_Bibliography.xcu @@ -0,0 +1,20 @@ + + + component_Bibliography + diff --git a/filter/source/config/fragments/frameloaders/com_sun_star_sdb_ContentLoader.xcu b/filter/source/config/fragments/frameloaders/com_sun_star_sdb_ContentLoader.xcu new file mode 100644 index 000000000..6d10acbad --- /dev/null +++ b/filter/source/config/fragments/frameloaders/com_sun_star_sdb_ContentLoader.xcu @@ -0,0 +1,20 @@ + + + component_DB + diff --git a/filter/source/config/fragments/frameloaders/org_openoffice_comp_dbflt_DBContentLoader2.xcu b/filter/source/config/fragments/frameloaders/org_openoffice_comp_dbflt_DBContentLoader2.xcu new file mode 100644 index 000000000..62b6a6eee --- /dev/null +++ b/filter/source/config/fragments/frameloaders/org_openoffice_comp_dbflt_DBContentLoader2.xcu @@ -0,0 +1,20 @@ + + + StarBase + diff --git a/filter/source/config/fragments/internalgraphicfilters/bmp_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/bmp_Export.xcu new file mode 100644 index 000000000..250504108 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/bmp_Export.xcu @@ -0,0 +1,27 @@ + + + bmp_MS_Windows + SVBMP + + com.sun.star.svtools.SvFilterOptionsDialog + + BMP - Windows Bitmap + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/bmp_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/bmp_Import.xcu new file mode 100644 index 000000000..7b5c54a64 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/bmp_Import.xcu @@ -0,0 +1,27 @@ + + + bmp_MS_Windows + SVBMP + BMP - MS Windows + + + BMP - Windows Bitmap + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/dxf_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/dxf_Import.xcu new file mode 100644 index 000000000..d4ce34e28 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/dxf_Import.xcu @@ -0,0 +1,28 @@ + + + + dxf_AutoCAD_Interchange + SVDXF + DXF - AutoCAD Interchange + + + DXF - AutoCAD Interchange Format + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/emf_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/emf_Export.xcu new file mode 100644 index 000000000..631f90a50 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/emf_Export.xcu @@ -0,0 +1,27 @@ + + + emf_MS_Windows_Metafile + SVEMF + + com.sun.star.svtools.SvFilterOptionsDialog + + EMF - Enhanced Metafile + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/emf_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/emf_Import.xcu new file mode 100644 index 000000000..e2d19bbf8 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/emf_Import.xcu @@ -0,0 +1,27 @@ + + + emf_MS_Windows_Metafile + SVEMF + EMF - MS Windows Metafile + + + EMF - Enhanced Metafile + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/eps_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/eps_Export.xcu new file mode 100644 index 000000000..b89453e45 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/eps_Export.xcu @@ -0,0 +1,28 @@ + + + + eps_Encapsulated_PostScript + SVEEPS + + com.sun.star.svtools.SvFilterOptionsDialog + + EPS - Encapsulated PostScript + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/eps_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/eps_Import.xcu new file mode 100644 index 000000000..327834368 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/eps_Import.xcu @@ -0,0 +1,28 @@ + + + + eps_Encapsulated_PostScript + SVIEPS + EPS - Encapsulated PostScript + + + EPS - Encapsulated PostScript + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/gif_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/gif_Export.xcu new file mode 100644 index 000000000..f55d1ba55 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/gif_Export.xcu @@ -0,0 +1,28 @@ + + + + gif_Graphics_Interchange + SVEGIF + + com.sun.star.svtools.SvFilterOptionsDialog + + GIF - Graphics Interchange Format + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/gif_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/gif_Import.xcu new file mode 100644 index 000000000..08bcff520 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/gif_Import.xcu @@ -0,0 +1,27 @@ + + + gif_Graphics_Interchange + SVIGIF + GIF - Graphics Interchange + + + GIF - Graphics Interchange Format + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/jpg_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/jpg_Export.xcu new file mode 100644 index 000000000..82bfd4ec9 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/jpg_Export.xcu @@ -0,0 +1,27 @@ + + + jpg_JPEG + SVEJPEG + + com.sun.star.svtools.SvFilterOptionsDialog + + JPEG - Joint Photographic Experts Group + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/jpg_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/jpg_Import.xcu new file mode 100644 index 000000000..0e3ac03fe --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/jpg_Import.xcu @@ -0,0 +1,27 @@ + + + jpg_JPEG + SVIJPEG + JPG - JPEG + + + JPEG - Joint Photographic Experts Group + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/met_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/met_Import.xcu new file mode 100644 index 000000000..8e6aa1b9e --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/met_Import.xcu @@ -0,0 +1,28 @@ + + + + met_OS2_Metafile + SVMET + MET - OS/2 Metafile + + + MET - OS/2 Metafile + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/mov_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/mov_Import.xcu new file mode 100644 index 000000000..3dd288603 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/mov_Import.xcu @@ -0,0 +1,18 @@ + + + mov_MOV + SVMOV + MOV - MOV + + + MOV - QuickTime File Format + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pbm_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/pbm_Import.xcu new file mode 100644 index 000000000..0e7f0b940 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pbm_Import.xcu @@ -0,0 +1,28 @@ + + + + pbm_Portable_Bitmap + SVPBM + PBM - Portable Bitmap + + + PBM - Portable Bitmap + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base.xcu b/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base.xcu new file mode 100644 index 000000000..29c7b846d --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base.xcu @@ -0,0 +1,28 @@ + + + + pcd_Photo_CD_Base + SVPCD + draw_PCD_Photo_CD_Base + + + PCD - Kodak Photo CD (768x512) + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base16.xcu b/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base16.xcu new file mode 100644 index 000000000..b61fde810 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base16.xcu @@ -0,0 +1,28 @@ + + + + pcd_Photo_CD_Base16 + SVPCD + draw_PCD_Photo_CD_Base16 + + + PCD - Kodak Photo CD (192x128) + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base4.xcu b/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base4.xcu new file mode 100644 index 000000000..15d51918a --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pcd_Import_Base4.xcu @@ -0,0 +1,28 @@ + + + + pcd_Photo_CD_Base4 + SVPCD + draw_PCD_Photo_CD_Base4 + + + PCD - Kodak Photo CD (384x256) + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pct_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/pct_Import.xcu new file mode 100644 index 000000000..974bb3300 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pct_Import.xcu @@ -0,0 +1,28 @@ + + + + pct_Mac_Pict + SVPICT + PCT - Mac Pict + + + PCT - Mac Pict + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pcx_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/pcx_Import.xcu new file mode 100644 index 000000000..da49344d4 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pcx_Import.xcu @@ -0,0 +1,28 @@ + + + + pcx_Zsoft_Paintbrush + SVPCX + PCX - Zsoft Paintbrush + + + PCX - Zsoft Paintbrush + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pdf_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/pdf_Export.xcu new file mode 100644 index 000000000..d82c771da --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pdf_Export.xcu @@ -0,0 +1,17 @@ + + + pdf_Portable_Document_Format + SVEPDF + + com.sun.star.svtools.SvFilterOptionsDialog + + PDF - Portable Document Format + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pdf_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/pdf_Import.xcu new file mode 100644 index 000000000..a1cc9ce59 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pdf_Import.xcu @@ -0,0 +1,17 @@ + + + pdf_Portable_Document_Format + SVIPDF + PDF - Portable Document Format + + + PDF - Portable Document Format + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/pgm_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/pgm_Import.xcu new file mode 100644 index 000000000..0356e6954 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/pgm_Import.xcu @@ -0,0 +1,28 @@ + + + + pgm_Portable_Graymap + SVPBM + PGM - Portable Graymap + + + PGM - Portable Graymap + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/png_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/png_Export.xcu new file mode 100644 index 000000000..95fc65272 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/png_Export.xcu @@ -0,0 +1,27 @@ + + + png_Portable_Network_Graphic + SVEPNG + + com.sun.star.svtools.SvFilterOptionsDialog + + PNG - Portable Network Graphics + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/png_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/png_Import.xcu new file mode 100644 index 000000000..cbc4c6507 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/png_Import.xcu @@ -0,0 +1,27 @@ + + + png_Portable_Network_Graphic + SVIPNG + PNG - Portable Network Graphic + + + PNG - Portable Network Graphics + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/ppm_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/ppm_Import.xcu new file mode 100644 index 000000000..03134558c --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/ppm_Import.xcu @@ -0,0 +1,28 @@ + + + + ppm_Portable_Pixelmap + SVPBM + PPM - Portable Pixelmap + + + PPM - Portable Pixelmap + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/psd_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/psd_Import.xcu new file mode 100644 index 000000000..f51b0fa59 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/psd_Import.xcu @@ -0,0 +1,28 @@ + + + + psd_Adobe_Photoshop + SVPSD + PSD - Adobe Photoshop + + + PSD - Adobe Photoshop + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/ras_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/ras_Import.xcu new file mode 100644 index 000000000..7e9a3b2bb --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/ras_Import.xcu @@ -0,0 +1,28 @@ + + + + ras_Sun_Rasterfile + SVRAS + RAS - Sun Rasterfile + + + RAS - Sun Raster Image + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/svg_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/svg_Export.xcu new file mode 100644 index 000000000..11e70d478 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/svg_Export.xcu @@ -0,0 +1,27 @@ + + + svg_Scalable_Vector_Graphics + SVESVG + + com.sun.star.svtools.SvFilterOptionsDialog + + SVG - Scalable Vector Graphics + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/svg_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/svg_Import.xcu new file mode 100644 index 000000000..3577bd98d --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/svg_Import.xcu @@ -0,0 +1,27 @@ + + + svg_Scalable_Vector_Graphics + SVISVG + SVG - Scalable Vector Graphics + + + SVG - Scalable Vector Graphics + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/svm_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/svm_Export.xcu new file mode 100644 index 000000000..eeaa34cc4 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/svm_Export.xcu @@ -0,0 +1,27 @@ + + + svm_StarView_Metafile + SVMETAFILE + + com.sun.star.svtools.SvFilterOptionsDialog + + SVM - StarView Metafile + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/svm_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/svm_Import.xcu new file mode 100644 index 000000000..74dd7ec30 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/svm_Import.xcu @@ -0,0 +1,27 @@ + + + svm_StarView_Metafile + SVMETAFILE + SVM - StarView Metafile + + + SVM - StarView Metafile + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/tga_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/tga_Import.xcu new file mode 100644 index 000000000..922cdefbf --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/tga_Import.xcu @@ -0,0 +1,28 @@ + + + + tga_Truevision_TARGA + SVTGA + TGA - Truevision TARGA + + + TGA - Truevision Targa + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/tif_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/tif_Export.xcu new file mode 100644 index 000000000..6fc07ec72 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/tif_Export.xcu @@ -0,0 +1,27 @@ + + + tif_Tag_Image_File + SVTIFF + + com.sun.star.svtools.SvFilterOptionsDialog + + TIFF - Tagged Image File Format + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/tif_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/tif_Import.xcu new file mode 100644 index 000000000..b77e6e6d6 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/tif_Import.xcu @@ -0,0 +1,27 @@ + + + tif_Tag_Image_File + SVTIFF + TIF - Tag Image File + + + TIFF - Tagged Image File Format + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/webp_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/webp_Export.xcu new file mode 100644 index 000000000..70ff15429 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/webp_Export.xcu @@ -0,0 +1,27 @@ + + + webp_WebP + SVEWEBP + + com.sun.star.svtools.SvFilterOptionsDialog + + WEBP - WebP Image + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/webp_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/webp_Import.xcu new file mode 100644 index 000000000..cdce5c9e4 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/webp_Import.xcu @@ -0,0 +1,27 @@ + + + webp_WebP + SVIWEBP + WEBP - WebP + + + WEBP - WebP Image + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/wmf_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/wmf_Export.xcu new file mode 100644 index 000000000..a389687be --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/wmf_Export.xcu @@ -0,0 +1,27 @@ + + + wmf_MS_Windows_Metafile + SVWMF + + com.sun.star.svtools.SvFilterOptionsDialog + + WMF - Windows Metafile + + EXPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/wmf_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/wmf_Import.xcu new file mode 100644 index 000000000..149d7ec86 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/wmf_Import.xcu @@ -0,0 +1,27 @@ + + + wmf_MS_Windows_Metafile + SVWMF + WMF - MS Windows Metafile + + + WMF - Windows Metafile + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/xbm_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/xbm_Import.xcu new file mode 100644 index 000000000..170cd89be --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/xbm_Import.xcu @@ -0,0 +1,27 @@ + + + xbm_X_Consortium + SVIXBM + XBM - X-Consortium + + + XBM - X Bitmap + + IMPORT + diff --git a/filter/source/config/fragments/internalgraphicfilters/xpm_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/xpm_Import.xcu new file mode 100644 index 000000000..bdc51fd31 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/xpm_Import.xcu @@ -0,0 +1,27 @@ + + + xpm_XPM + SVIXPM + XPM + + + XPM - X PixMap + + IMPORT + diff --git a/filter/source/config/fragments/langfilter.xsl b/filter/source/config/fragments/langfilter.xsl new file mode 100644 index 000000000..b26a522d1 --- /dev/null +++ b/filter/source/config/fragments/langfilter.xsl @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu b/filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu new file mode 100644 index 000000000..14a03a846 --- /dev/null +++ b/filter/source/config/fragments/types/MS_Excel_2007_Binary.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + xlsb + + false + Calc MS Excel 2007 Binary + Microsoft Excel 2007 Binary + + diff --git a/filter/source/config/fragments/types/MS_Excel_2007_VBA_XML.xcu b/filter/source/config/fragments/types/MS_Excel_2007_VBA_XML.xcu new file mode 100644 index 000000000..70c99bbf7 --- /dev/null +++ b/filter/source/config/fragments/types/MS_Excel_2007_VBA_XML.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + xlsm + application/vnd.ms-excel.sheet.macroEnabled.12 + false + Calc MS Excel 2007 VBA XML + Microsoft Excel 2007–365 VBA XML + + diff --git a/filter/source/config/fragments/types/MS_Excel_2007_XML.xcu b/filter/source/config/fragments/types/MS_Excel_2007_XML.xcu new file mode 100644 index 000000000..73d2daee3 --- /dev/null +++ b/filter/source/config/fragments/types/MS_Excel_2007_XML.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + xlsx + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + false + Calc MS Excel 2007 XML + Excel 2007–365 + + diff --git a/filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu b/filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu new file mode 100644 index 000000000..d0a828def --- /dev/null +++ b/filter/source/config/fragments/types/MS_Excel_2007_XML_Template.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + xltx xltm + application/vnd.openxmlformats-officedocument.spreadsheetml.template + false + Calc MS Excel 2007 XML Template + Excel 2007–365 Template + + diff --git a/filter/source/config/fragments/types/MS_PowerPoint_2007_XML.xcu b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML.xcu new file mode 100644 index 000000000..75b9f95d4 --- /dev/null +++ b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + pptx + application/vnd.openxmlformats-officedocument.presentationml.presentation + true + Impress MS PowerPoint 2007 XML + PowerPoint 2007–365 + + diff --git a/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_AutoPlay.xcu b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_AutoPlay.xcu new file mode 100644 index 000000000..7c8dc62e2 --- /dev/null +++ b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_AutoPlay.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + ppsx + application/vnd.openxmlformats-officedocument.presentationml.slideshow + true + Impress MS PowerPoint 2007 XML AutoPlay + PowerPoint 2007–365 + + diff --git a/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_Template.xcu b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_Template.xcu new file mode 100644 index 000000000..c64c11276 --- /dev/null +++ b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_Template.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + potx potm + application/vnd.openxmlformats-officedocument.presentationml.template + true + Impress MS PowerPoint 2007 XML Template + PowerPoint 2007–365 Template + + diff --git a/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_VBA.xcu b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_VBA.xcu new file mode 100644 index 000000000..51203bac1 --- /dev/null +++ b/filter/source/config/fragments/types/MS_PowerPoint_2007_XML_VBA.xcu @@ -0,0 +1,28 @@ + + + + com.sun.star.comp.oox.FormatDetector + + pptm + application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml + true + Impress MS PowerPoint 2007 XML VBA + PowerPoint 2007–365 VBA + + diff --git a/filter/source/config/fragments/types/MWAW_Bitmap.xcu b/filter/source/config/fragments/types/MWAW_Bitmap.xcu new file mode 100644 index 000000000..532f10609 --- /dev/null +++ b/filter/source/config/fragments/types/MWAW_Bitmap.xcu @@ -0,0 +1,27 @@ + + + + + com.sun.star.comp.Draw.MWAWDrawImportFilter + + + * + + + + true + + + MWAW_Bitmap + + + Legacy Mac Bitmap + + diff --git a/filter/source/config/fragments/types/MWAW_Database.xcu b/filter/source/config/fragments/types/MWAW_Database.xcu new file mode 100644 index 000000000..491d23a6c --- /dev/null +++ b/filter/source/config/fragments/types/MWAW_Database.xcu @@ -0,0 +1,27 @@ + + + + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + + * + + + + true + + + MWAW_Database + + + Legacy Mac Database + + diff --git a/filter/source/config/fragments/types/MWAW_Drawing.xcu b/filter/source/config/fragments/types/MWAW_Drawing.xcu new file mode 100644 index 000000000..3edba277e --- /dev/null +++ b/filter/source/config/fragments/types/MWAW_Drawing.xcu @@ -0,0 +1,27 @@ + + + + + com.sun.star.comp.Draw.MWAWDrawImportFilter + + + * + + + + true + + + MWAW_Drawing + + + Legacy Mac Drawing + + diff --git a/filter/source/config/fragments/types/MWAW_Presentation.xcu b/filter/source/config/fragments/types/MWAW_Presentation.xcu new file mode 100644 index 000000000..2f96bff69 --- /dev/null +++ b/filter/source/config/fragments/types/MWAW_Presentation.xcu @@ -0,0 +1,27 @@ + + + + + com.sun.star.comp.Impress.MWAWImpressImportFilter + + + * + + + + true + + + MWAW_Presentation + + + Legacy Mac Presentation + + diff --git a/filter/source/config/fragments/types/MWAW_Spreadsheet.xcu b/filter/source/config/fragments/types/MWAW_Spreadsheet.xcu new file mode 100644 index 000000000..5ebb8e8a8 --- /dev/null +++ b/filter/source/config/fragments/types/MWAW_Spreadsheet.xcu @@ -0,0 +1,27 @@ + + + + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + + * + + + + true + + + MWAW_Spreadsheet + + + Legacy Mac Spreadsheet + + diff --git a/filter/source/config/fragments/types/MWAW_Text_Document.xcu b/filter/source/config/fragments/types/MWAW_Text_Document.xcu new file mode 100644 index 000000000..6e2b1cdde --- /dev/null +++ b/filter/source/config/fragments/types/MWAW_Text_Document.xcu @@ -0,0 +1,27 @@ + + + + + com.sun.star.comp.Writer.MWAWImportFilter + + + * + + + + true + + + MWAW_Text_Document + + + Legacy Mac Text Document + + diff --git a/filter/source/config/fragments/types/Palm_Text_Document.xcu b/filter/source/config/fragments/types/Palm_Text_Document.xcu new file mode 100644 index 000000000..e067f9f0a --- /dev/null +++ b/filter/source/config/fragments/types/Palm_Text_Document.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Writer.EBookImportFilter + + + pdb + + + application/vnd.palm + + + true + + + Palm_Text_Document + + + Palm Text Document + + diff --git a/filter/source/config/fragments/types/StarBase.xcu b/filter/source/config/fragments/types/StarBase.xcu new file mode 100644 index 000000000..5f335c07f --- /dev/null +++ b/filter/source/config/fragments/types/StarBase.xcu @@ -0,0 +1,29 @@ + + + org.openoffice.comp.dbflt.DBTypeDetection + private:factory/sdatabase* + odb + application/vnd.sun.xml.base + false + StarOffice XML (Base) + + OpenDocument Database + + StarBase 6.0 + diff --git a/filter/source/config/fragments/types/StarBaseReport.xcu b/filter/source/config/fragments/types/StarBaseReport.xcu new file mode 100644 index 000000000..0489dc789 --- /dev/null +++ b/filter/source/config/fragments/types/StarBaseReport.xcu @@ -0,0 +1,43 @@ + + + + com.sun.star.comp.report.ORptTypeDetection + + + private:factory/sreport* + + + orp + + + application/vnd.sun.xml.report + + + false + + + StarOffice XML (Base) Report + + + OpenDocument Database Report + + + StarBaseReport 9.0 + + diff --git a/filter/source/config/fragments/types/StarBaseReportChart.xcu b/filter/source/config/fragments/types/StarBaseReportChart.xcu new file mode 100644 index 000000000..0ef9a5463 --- /dev/null +++ b/filter/source/config/fragments/types/StarBaseReportChart.xcu @@ -0,0 +1,41 @@ + + + + + + + + odc + + + application/vnd.sun.xml.report.chart + + + false + + + StarOffice XML (Base) Report Chart + + + StarOffice XML (Base) Report Chart 9 + + + StarOffice XML (Base) Report Chart 9 + + diff --git a/filter/source/config/fragments/types/StarOffice_Drawing.xcu b/filter/source/config/fragments/types/StarOffice_Drawing.xcu new file mode 100644 index 000000000..cad6f68c3 --- /dev/null +++ b/filter/source/config/fragments/types/StarOffice_Drawing.xcu @@ -0,0 +1,27 @@ + + + + + org.libreoffice.comp.Draw.StarOfficeDrawImportFilter + + + sda + + + + true + + + StarOffice_Drawing + + + Legacy StarOffice Drawing + + diff --git a/filter/source/config/fragments/types/StarOffice_Presentation.xcu b/filter/source/config/fragments/types/StarOffice_Presentation.xcu new file mode 100644 index 000000000..02c0f3af6 --- /dev/null +++ b/filter/source/config/fragments/types/StarOffice_Presentation.xcu @@ -0,0 +1,27 @@ + + + + + org.libreoffice.comp.Impress.StarOfficePresentationImportFilter + + + sdd + + + + true + + + StarOffice_Presentation + + + Legacy StarOffice Presentation + + diff --git a/filter/source/config/fragments/types/StarOffice_Spreadsheet.xcu b/filter/source/config/fragments/types/StarOffice_Spreadsheet.xcu new file mode 100644 index 000000000..f4f472b94 --- /dev/null +++ b/filter/source/config/fragments/types/StarOffice_Spreadsheet.xcu @@ -0,0 +1,27 @@ + + + + + org.libreoffice.comp.Calc.StarOfficeCalcImportFilter + + + sdc + + + + true + + + StarOffice_Spreadsheet + + + Legacy StarOffice Spreadsheet + + diff --git a/filter/source/config/fragments/types/StarOffice_Writer.xcu b/filter/source/config/fragments/types/StarOffice_Writer.xcu new file mode 100644 index 000000000..ca10b9328 --- /dev/null +++ b/filter/source/config/fragments/types/StarOffice_Writer.xcu @@ -0,0 +1,27 @@ + + + + + org.libreoffice.comp.Writer.StarOfficeWriterImportFilter + + + sdw + + + + true + + + StarOffice_Writer + + + Legacy StarOffice Text Document + + diff --git a/filter/source/config/fragments/types/Unified_Office_Format_presentation.xcu b/filter/source/config/fragments/types/Unified_Office_Format_presentation.xcu new file mode 100644 index 000000000..11f2a392b --- /dev/null +++ b/filter/source/config/fragments/types/Unified_Office_Format_presentation.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + uop;uof + + false + + + Unified Office Format presentation + + doctype:vnd.uof.presentation + diff --git a/filter/source/config/fragments/types/Unified_Office_Format_spreadsheet.xcu b/filter/source/config/fragments/types/Unified_Office_Format_spreadsheet.xcu new file mode 100644 index 000000000..71971bd1b --- /dev/null +++ b/filter/source/config/fragments/types/Unified_Office_Format_spreadsheet.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + uos;uof + + false + + + Unified Office Format spreadsheet + + doctype:vnd.uof.spreadsheet + diff --git a/filter/source/config/fragments/types/Unified_Office_Format_text.xcu b/filter/source/config/fragments/types/Unified_Office_Format_text.xcu new file mode 100644 index 000000000..be991d466 --- /dev/null +++ b/filter/source/config/fragments/types/Unified_Office_Format_text.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + uot;uof + + false + + + Unified Office Format text + + doctype:vnd.uof.text + diff --git a/filter/source/config/fragments/types/XHTML_File.xcu b/filter/source/config/fragments/types/XHTML_File.xcu new file mode 100644 index 000000000..6117ca3fe --- /dev/null +++ b/filter/source/config/fragments/types/XHTML_File.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + html xhtml + application/xhtml+xml + false + + + XHTML + + + diff --git a/filter/source/config/fragments/types/bmp_MS_Windows.xcu b/filter/source/config/fragments/types/bmp_MS_Windows.xcu new file mode 100644 index 000000000..7f60fae33 --- /dev/null +++ b/filter/source/config/fragments/types/bmp_MS_Windows.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + bmp + image/x-MS-bmp + false + BMP - MS Windows + + BMP - Windows Bitmap + + + diff --git a/filter/source/config/fragments/types/calc8.xcu b/filter/source/config/fragments/types/calc8.xcu new file mode 100644 index 000000000..36c6601e7 --- /dev/null +++ b/filter/source/config/fragments/types/calc8.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/scalc* + ods + application/vnd.oasis.opendocument.spreadsheet + true + calc8 + + Calc 8 + + Calc 8 + diff --git a/filter/source/config/fragments/types/calc8_template.xcu b/filter/source/config/fragments/types/calc8_template.xcu new file mode 100644 index 000000000..293283bb4 --- /dev/null +++ b/filter/source/config/fragments/types/calc8_template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + ots + application/vnd.oasis.opendocument.spreadsheet-template + false + calc8_template + + Calc 8 Template + + Calc 8 Template + diff --git a/filter/source/config/fragments/types/calc_ADO_rowset_XML.xcu b/filter/source/config/fragments/types/calc_ADO_rowset_XML.xcu new file mode 100644 index 000000000..2f02f568e --- /dev/null +++ b/filter/source/config/fragments/types/calc_ADO_rowset_XML.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + xml + + false + ADO Rowset XML + + ADO Rowset XML + + doctype:urn:schemas-microsoft-com:rowset + diff --git a/filter/source/config/fragments/types/calc_AppleNumbers.xcu b/filter/source/config/fragments/types/calc_AppleNumbers.xcu new file mode 100644 index 000000000..d2030b82a --- /dev/null +++ b/filter/source/config/fragments/types/calc_AppleNumbers.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Calc.NumbersImportFilter + + + numbers + + + application/x-iwork-numbers-sffnumbers + + + true + + + Apple Numbers + + + Apple Numbers + + diff --git a/filter/source/config/fragments/types/calc_ClarisWorks.xcu b/filter/source/config/fragments/types/calc_ClarisWorks.xcu new file mode 100644 index 000000000..105bae43c --- /dev/null +++ b/filter/source/config/fragments/types/calc_ClarisWorks.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + cwk + application/clarisworks + true + ClarisWorks_Calc + + ClarisWorks/AppleWorks Document + + + diff --git a/filter/source/config/fragments/types/calc_Claris_Resolve.xcu b/filter/source/config/fragments/types/calc_Claris_Resolve.xcu new file mode 100644 index 000000000..309eb47c6 --- /dev/null +++ b/filter/source/config/fragments/types/calc_Claris_Resolve.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + cwk + application/clarisworks + true + Claris_Resolve_Calc + + ClarisResolve Document + + + diff --git a/filter/source/config/fragments/types/calc_DIF.xcu b/filter/source/config/fragments/types/calc_DIF.xcu new file mode 100644 index 000000000..536e75d72 --- /dev/null +++ b/filter/source/config/fragments/types/calc_DIF.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.FormatDetector + + dif + + false + DIF + + Data Interchange Format + + + diff --git a/filter/source/config/fragments/types/calc_Gnumeric.xcu b/filter/source/config/fragments/types/calc_Gnumeric.xcu new file mode 100644 index 000000000..4c158cc34 --- /dev/null +++ b/filter/source/config/fragments/types/calc_Gnumeric.xcu @@ -0,0 +1,17 @@ + + + com.sun.star.comp.sc.OrcusFilterDetect + + gnumeric gnm + application/x-gnumeric + false + Gnumeric Spreadsheet + Gnumeric Spreadsheet + + diff --git a/filter/source/config/fragments/types/calc_HTML.xcu b/filter/source/config/fragments/types/calc_HTML.xcu new file mode 100644 index 000000000..51bf8f192 --- /dev/null +++ b/filter/source/config/fragments/types/calc_HTML.xcu @@ -0,0 +1,35 @@ + + + + com.sun.star.comp.filters.PlainTextFilterDetect + + xls + text/html + false + + + HTML Table + + + diff --git a/filter/source/config/fragments/types/calc_Lotus.xcu b/filter/source/config/fragments/types/calc_Lotus.xcu new file mode 100644 index 000000000..2b047e3f0 --- /dev/null +++ b/filter/source/config/fragments/types/calc_Lotus.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.FormatDetector + + wk1 wks 123 + application/vnd.lotus-1-2-3 + true + Lotus + + Lotus + + + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_2003_XML.xcu b/filter/source/config/fragments/types/calc_MS_Excel_2003_XML.xcu new file mode 100644 index 000000000..a3ee903b9 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_2003_XML.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.sc.OrcusFilterDetect + + xml xls + + false + + + Microsoft Excel 2003 XML + + doctype:Workbook + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_40.xcu b/filter/source/config/fragments/types/calc_MS_Excel_40.xcu new file mode 100644 index 000000000..b99cfc485 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_40.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xls xlw xlc xlm + application/vnd.ms-excel + false + MS Excel 4.0 + + Microsoft Excel 4.0 + + + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_40_VorlageTemplate.xcu b/filter/source/config/fragments/types/calc_MS_Excel_40_VorlageTemplate.xcu new file mode 100644 index 000000000..69304a7ad --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_40_VorlageTemplate.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xlt + application/vnd.ms-excel + false + MS Excel 4.0 Vorlage/Template + + MS Excel 4.0 Template + + + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_5095.xcu b/filter/source/config/fragments/types/calc_MS_Excel_5095.xcu new file mode 100644 index 000000000..c1e537132 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_5095.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xls xlc xlm xlw + application/vnd.ms-excel + false + MS Excel 5.0/95 + + Microsoft Excel 5.0 + + Biff5 + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_5095_VorlageTemplate.xcu b/filter/source/config/fragments/types/calc_MS_Excel_5095_VorlageTemplate.xcu new file mode 100644 index 000000000..ead4b0426 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_5095_VorlageTemplate.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xlt + application/vnd.ms-excel + false + MS Excel 5.0/95 Vorlage/Template + + MS Excel 5.0 Template + + Biff5 + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_95.xcu b/filter/source/config/fragments/types/calc_MS_Excel_95.xcu new file mode 100644 index 000000000..25e1d3380 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_95.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xls xlc xlm xlw + application/vnd.ms-excel + false + MS Excel 95 + + Microsoft Excel 95 + + Biff5 + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_95_VorlageTemplate.xcu b/filter/source/config/fragments/types/calc_MS_Excel_95_VorlageTemplate.xcu new file mode 100644 index 000000000..fc3e68f96 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_95_VorlageTemplate.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xlt + application/vnd.ms-excel + false + MS Excel 95 Vorlage/Template + + MS Excel 95 Template + + Biff5 + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_97.xcu b/filter/source/config/fragments/types/calc_MS_Excel_97.xcu new file mode 100644 index 000000000..56d5f2647 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_97.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xls xlc xlm xlw xlk et + application/vnd.ms-excel + true + MS Excel 97 + + Excel 97–2003 + + Biff8 + diff --git a/filter/source/config/fragments/types/calc_MS_Excel_97_VorlageTemplate.xcu b/filter/source/config/fragments/types/calc_MS_Excel_97_VorlageTemplate.xcu new file mode 100644 index 000000000..f8cd624f7 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Excel_97_VorlageTemplate.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.ExcelBiffFormatDetector + + xlt ett + application/vnd.ms-excel + false + MS Excel 97 Vorlage/Template + + Excel 97–2000 Template + + Biff8 + diff --git a/filter/source/config/fragments/types/calc_MS_Multiplan.xcu b/filter/source/config/fragments/types/calc_MS_Multiplan.xcu new file mode 100644 index 000000000..7f9b3c3c5 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Multiplan.xcu @@ -0,0 +1,25 @@ + + + + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + mp + + + true + + + Microsoft Multiplan + + + Microsoft Multiplan + + diff --git a/filter/source/config/fragments/types/calc_MS_Works_Document.xcu b/filter/source/config/fragments/types/calc_MS_Works_Document.xcu new file mode 100644 index 000000000..f45dfe109 --- /dev/null +++ b/filter/source/config/fragments/types/calc_MS_Works_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + wks wdb + + true + MS_Works_Calc + + Microsoft Works Document + + + diff --git a/filter/source/config/fragments/types/calc_Mac_Works.xcu b/filter/source/config/fragments/types/calc_Mac_Works.xcu new file mode 100644 index 000000000..9a9d37342 --- /dev/null +++ b/filter/source/config/fragments/types/calc_Mac_Works.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Calc.MWAWCalcImportFilter + + wps + application/vnd.ms-works + true + Mac_Works_Calc + + Microsoft Works for Mac Document (v1 - v4) + + + diff --git a/filter/source/config/fragments/types/calc_ODS_FlatXML.xcu b/filter/source/config/fragments/types/calc_ODS_FlatXML.xcu new file mode 100644 index 000000000..22064e799 --- /dev/null +++ b/filter/source/config/fragments/types/calc_ODS_FlatXML.xcu @@ -0,0 +1,31 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + fods ods xml + application/vnd.oasis.opendocument.spreadsheet-flat-xml + false + OpenDocument Spreadsheet Flat XML + + OpenDocument Spreadsheet (Flat XML) + + + doctype:office:mimetype="application/vnd.oasis.opendocument.spreadsheet" + + diff --git a/filter/source/config/fragments/types/calc_OOXML.xcu b/filter/source/config/fragments/types/calc_OOXML.xcu new file mode 100644 index 000000000..5b17c1c1d --- /dev/null +++ b/filter/source/config/fragments/types/calc_OOXML.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + xlsx xlsm + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + false + Calc Office Open XML + Office Open XML Spreadsheet + + diff --git a/filter/source/config/fragments/types/calc_OOXML_Template.xcu b/filter/source/config/fragments/types/calc_OOXML_Template.xcu new file mode 100644 index 000000000..677762fa7 --- /dev/null +++ b/filter/source/config/fragments/types/calc_OOXML_Template.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + xltx xltm + application/vnd.openxmlformats-officedocument.spreadsheetml.template + false + Calc Office Open XML Template + Office Open XML Spreadsheet Template + + diff --git a/filter/source/config/fragments/types/calc_QPro.xcu b/filter/source/config/fragments/types/calc_QPro.xcu new file mode 100644 index 000000000..e43a63bae --- /dev/null +++ b/filter/source/config/fragments/types/calc_QPro.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.FormatDetector + + wb2 + + true + Quattro Pro 6.0 + + Quattro Pro 6.0 + + + diff --git a/filter/source/config/fragments/types/calc_SYLK.xcu b/filter/source/config/fragments/types/calc_SYLK.xcu new file mode 100644 index 000000000..4f0d72cab --- /dev/null +++ b/filter/source/config/fragments/types/calc_SYLK.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.FormatDetector + + slk sylk + text/spreadsheet + false + SYLK + + SYLK + + + diff --git a/filter/source/config/fragments/types/calc_StarOffice_XML_Calc.xcu b/filter/source/config/fragments/types/calc_StarOffice_XML_Calc.xcu new file mode 100644 index 000000000..79e57ae81 --- /dev/null +++ b/filter/source/config/fragments/types/calc_StarOffice_XML_Calc.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sxc + application/vnd.sun.xml.calc + false + StarOffice XML (Calc) + + Calc 6.0 + + Calc 6.0 + diff --git a/filter/source/config/fragments/types/calc_StarOffice_XML_Calc_Template.xcu b/filter/source/config/fragments/types/calc_StarOffice_XML_Calc_Template.xcu new file mode 100644 index 000000000..df5f73741 --- /dev/null +++ b/filter/source/config/fragments/types/calc_StarOffice_XML_Calc_Template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + stc + application/vnd.sun.xml.calc.template + false + calc_StarOffice_XML_Calc_Template + + Calc 6.0 Template + + Calc 6.0 + diff --git a/filter/source/config/fragments/types/calc_WPS_Lotus_Document.xcu b/filter/source/config/fragments/types/calc_WPS_Lotus_Document.xcu new file mode 100644 index 000000000..abea24321 --- /dev/null +++ b/filter/source/config/fragments/types/calc_WPS_Lotus_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + wk1 wk3 wk4 123 + + true + WPS_Lotus_Calc + + Lotus Wk1-Wk3 + + + diff --git a/filter/source/config/fragments/types/calc_WPS_QPro_Document.xcu b/filter/source/config/fragments/types/calc_WPS_QPro_Document.xcu new file mode 100644 index 000000000..2c8529db0 --- /dev/null +++ b/filter/source/config/fragments/types/calc_WPS_QPro_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Calc.MSWorksCalcImportFilter + + wb1 wb2 wq1 wq2 + + true + WPS_QPro_Calc + + QuattroPro Document + + + diff --git a/filter/source/config/fragments/types/calc_dBase.xcu b/filter/source/config/fragments/types/calc_dBase.xcu new file mode 100644 index 000000000..d37ec5a64 --- /dev/null +++ b/filter/source/config/fragments/types/calc_dBase.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.calc.FormatDetector + + dbf + + false + dBase + + dBASE + + + diff --git a/filter/source/config/fragments/types/chart8.xcu b/filter/source/config/fragments/types/chart8.xcu new file mode 100644 index 000000000..5a2fd0c1d --- /dev/null +++ b/filter/source/config/fragments/types/chart8.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/schart* + odc + application/vnd.oasis.opendocument.chart + true + chart8 + + Chart 8 + + Chart 8 + diff --git a/filter/source/config/fragments/types/chart_StarOffice_XML_Chart.xcu b/filter/source/config/fragments/types/chart_StarOffice_XML_Chart.xcu new file mode 100644 index 000000000..1292786f8 --- /dev/null +++ b/filter/source/config/fragments/types/chart_StarOffice_XML_Chart.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sxs + application/vnd.sun.xml.chart + false + StarOffice XML (Chart) + + Chart 6.0 + + Chart 6.0 + diff --git a/filter/source/config/fragments/types/component_Bibliography.xcu b/filter/source/config/fragments/types/component_Bibliography.xcu new file mode 100644 index 000000000..526a4b20b --- /dev/null +++ b/filter/source/config/fragments/types/component_Bibliography.xcu @@ -0,0 +1,29 @@ + + + .component:Bibliography/* + + + false + + Bibliography component + + + + + diff --git a/filter/source/config/fragments/types/component_DB.xcu b/filter/source/config/fragments/types/component_DB.xcu new file mode 100644 index 000000000..0c1f3ac5a --- /dev/null +++ b/filter/source/config/fragments/types/component_DB.xcu @@ -0,0 +1,29 @@ + + + .component:DB* + + + false + + DB component + + + + + diff --git a/filter/source/config/fragments/types/draw8.xcu b/filter/source/config/fragments/types/draw8.xcu new file mode 100644 index 000000000..cf15c4923 --- /dev/null +++ b/filter/source/config/fragments/types/draw8.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/sdraw* + odg + application/vnd.oasis.opendocument.graphics + true + draw8 + + Draw 8 + + Draw 8 + diff --git a/filter/source/config/fragments/types/draw8_template.xcu b/filter/source/config/fragments/types/draw8_template.xcu new file mode 100644 index 000000000..b20422ad4 --- /dev/null +++ b/filter/source/config/fragments/types/draw8_template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + otg + application/vnd.oasis.opendocument.graphics-template + false + draw8_template + + Draw 8 Template + + Draw 8 Template + diff --git a/filter/source/config/fragments/types/draw_ClarisWorks.xcu b/filter/source/config/fragments/types/draw_ClarisWorks.xcu new file mode 100644 index 000000000..9581d21ab --- /dev/null +++ b/filter/source/config/fragments/types/draw_ClarisWorks.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.MWAWDrawImportFilter + + cwk + application/clarisworks + true + ClarisWorks_Draw + + ClarisWorks/AppleWorks Document + + + diff --git a/filter/source/config/fragments/types/draw_CorelDraw_Document.xcu b/filter/source/config/fragments/types/draw_CorelDraw_Document.xcu new file mode 100644 index 000000000..57c637394 --- /dev/null +++ b/filter/source/config/fragments/types/draw_CorelDraw_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.CDRImportFilter + + cdr + application/vnd.corel-draw + true + Corel Draw Document + + Corel Draw + + + diff --git a/filter/source/config/fragments/types/draw_Corel_Presentation_Exchange.xcu b/filter/source/config/fragments/types/draw_Corel_Presentation_Exchange.xcu new file mode 100644 index 000000000..73b43832b --- /dev/null +++ b/filter/source/config/fragments/types/draw_Corel_Presentation_Exchange.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.CMXImportFilter + + cmx + image/x-cmx + true + Corel Presentation Exchange + + Corel Presentation Exchange + + + diff --git a/filter/source/config/fragments/types/draw_Freehand_Document.xcu b/filter/source/config/fragments/types/draw_Freehand_Document.xcu new file mode 100644 index 000000000..44308542c --- /dev/null +++ b/filter/source/config/fragments/types/draw_Freehand_Document.xcu @@ -0,0 +1,12 @@ + + com.sun.star.comp.Draw.FreehandImportFilter + + fh fh1 fh2 fh3 fh4 fh5 fh6 fh7 fh8 fh9 fh10 fh11 + image/x-freehand + true + Freehand Document + + Adobe/Macromedia Freehand + + + diff --git a/filter/source/config/fragments/types/draw_ODG_FlatXML.xcu b/filter/source/config/fragments/types/draw_ODG_FlatXML.xcu new file mode 100644 index 000000000..e8272cd1a --- /dev/null +++ b/filter/source/config/fragments/types/draw_ODG_FlatXML.xcu @@ -0,0 +1,31 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + fodg odg xml + application/vnd.oasis.opendocument.graphics-flat-xml + false + OpenDocument Drawing Flat XML + + OpenDocument Drawing (Flat XML) + + + doctype:office:mimetype="application/vnd.oasis.opendocument.graphics" + + diff --git a/filter/source/config/fragments/types/draw_PageMaker_Document.xcu b/filter/source/config/fragments/types/draw_PageMaker_Document.xcu new file mode 100644 index 000000000..0ec1bf23b --- /dev/null +++ b/filter/source/config/fragments/types/draw_PageMaker_Document.xcu @@ -0,0 +1,12 @@ + + org.libreoffice.comp.Draw.PageMakerImportFilter + + p65 pm pm6 pmd + application/x-pagemaker + true + PageMaker Document + + Adobe PageMaker + + + diff --git a/filter/source/config/fragments/types/draw_Publisher_Document.xcu b/filter/source/config/fragments/types/draw_Publisher_Document.xcu new file mode 100644 index 000000000..cb56d145a --- /dev/null +++ b/filter/source/config/fragments/types/draw_Publisher_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.MSPUBImportFilter + + pub + application/x-mspublisher + true + Publisher Document + + Microsoft Publisher 2003 + + + diff --git a/filter/source/config/fragments/types/draw_QXP_Document.xcu b/filter/source/config/fragments/types/draw_QXP_Document.xcu new file mode 100644 index 000000000..901efc34c --- /dev/null +++ b/filter/source/config/fragments/types/draw_QXP_Document.xcu @@ -0,0 +1,12 @@ + + org.libreoffice.comp.Draw.QXPImportFilter + + qxd qxt + + true + QXP Document + + QuarkXPress + + + diff --git a/filter/source/config/fragments/types/draw_StarOffice_XML_Draw.xcu b/filter/source/config/fragments/types/draw_StarOffice_XML_Draw.xcu new file mode 100644 index 000000000..d2a4f1f6a --- /dev/null +++ b/filter/source/config/fragments/types/draw_StarOffice_XML_Draw.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sxd + application/vnd.sun.xml.draw + false + StarOffice XML (Draw) + + OpenOffice.org 1.0 Drawing + + Draw 6.0 + diff --git a/filter/source/config/fragments/types/draw_StarOffice_XML_Draw_Template.xcu b/filter/source/config/fragments/types/draw_StarOffice_XML_Draw_Template.xcu new file mode 100644 index 000000000..fcbb470d7 --- /dev/null +++ b/filter/source/config/fragments/types/draw_StarOffice_XML_Draw_Template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + std + application/vnd.sun.xml.draw.template + false + draw_StarOffice_XML_Draw_Template + + Draw 6.0 Template + + Draw 6.0 + diff --git a/filter/source/config/fragments/types/draw_Visio_Document.xcu b/filter/source/config/fragments/types/draw_Visio_Document.xcu new file mode 100644 index 000000000..b6c6992a3 --- /dev/null +++ b/filter/source/config/fragments/types/draw_Visio_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.VisioImportFilter + + vdx vsd vsdm vsdx + application/vnd.visio + true + Visio Document + + Microsoft Visio + + + diff --git a/filter/source/config/fragments/types/draw_WordPerfect_Graphics.xcu b/filter/source/config/fragments/types/draw_WordPerfect_Graphics.xcu new file mode 100644 index 000000000..6e0a52ee7 --- /dev/null +++ b/filter/source/config/fragments/types/draw_WordPerfect_Graphics.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.WPGImportFilter + + wpg + image/x-wpg + true + WordPerfect Graphics + + WordPerfect Graphics + + + diff --git a/filter/source/config/fragments/types/draw_ZMF_Document.xcu b/filter/source/config/fragments/types/draw_ZMF_Document.xcu new file mode 100644 index 000000000..ba67d5b96 --- /dev/null +++ b/filter/source/config/fragments/types/draw_ZMF_Document.xcu @@ -0,0 +1,12 @@ + + org.libreoffice.comp.Draw.ZMFImportFilter + + zmf + + true + ZMF Document + + Zoner Callisto/Draw + + + diff --git a/filter/source/config/fragments/types/dxf_AutoCAD_Interchange.xcu b/filter/source/config/fragments/types/dxf_AutoCAD_Interchange.xcu new file mode 100644 index 000000000..a785f8569 --- /dev/null +++ b/filter/source/config/fragments/types/dxf_AutoCAD_Interchange.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + dxf + image/vnd.dxf + false + DXF - AutoCAD Interchange + + DXF - AutoCAD Interchange Format + + + diff --git a/filter/source/config/fragments/types/emf_MS_Windows_Metafile.xcu b/filter/source/config/fragments/types/emf_MS_Windows_Metafile.xcu new file mode 100644 index 000000000..2003217aa --- /dev/null +++ b/filter/source/config/fragments/types/emf_MS_Windows_Metafile.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + emf emz + image/x-emf + false + EMF - MS Windows Metafile + + EMF - Enhanced Meta File + + + diff --git a/filter/source/config/fragments/types/eps_Encapsulated_PostScript.xcu b/filter/source/config/fragments/types/eps_Encapsulated_PostScript.xcu new file mode 100644 index 000000000..7097c98aa --- /dev/null +++ b/filter/source/config/fragments/types/eps_Encapsulated_PostScript.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + eps + image/x-eps + false + EPS - Encapsulated PostScript + + EPS - Encapsulated PostScript + + + diff --git a/filter/source/config/fragments/types/generic_HTML.xcu b/filter/source/config/fragments/types/generic_HTML.xcu new file mode 100644 index 000000000..92ac87ffb --- /dev/null +++ b/filter/source/config/fragments/types/generic_HTML.xcu @@ -0,0 +1,30 @@ + + + com.sun.star.comp.filters.PlainTextFilterDetect + private:factory/swriter/web* + + html xhtml htm + text/html + false + HTML + + HTML Document + + + diff --git a/filter/source/config/fragments/types/generic_Text.xcu b/filter/source/config/fragments/types/generic_Text.xcu new file mode 100644 index 000000000..45df03f62 --- /dev/null +++ b/filter/source/config/fragments/types/generic_Text.xcu @@ -0,0 +1,28 @@ + + + com.sun.star.comp.filters.PlainTextFilterDetect + + csv tsv tab txt + text/plain + false + + Text + + + diff --git a/filter/source/config/fragments/types/gif_Graphics_Interchange.xcu b/filter/source/config/fragments/types/gif_Graphics_Interchange.xcu new file mode 100644 index 000000000..9fbf3ec32 --- /dev/null +++ b/filter/source/config/fragments/types/gif_Graphics_Interchange.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + gif + image/gif + false + GIF - Graphics Interchange + + GIF - Graphics Interchange + + + diff --git a/filter/source/config/fragments/types/graphic_HTML.xcu b/filter/source/config/fragments/types/graphic_HTML.xcu new file mode 100644 index 000000000..e918bbd50 --- /dev/null +++ b/filter/source/config/fragments/types/graphic_HTML.xcu @@ -0,0 +1,29 @@ + + + + + html htm + text/html + false + + + HTML + + + diff --git a/filter/source/config/fragments/types/impress8.xcu b/filter/source/config/fragments/types/impress8.xcu new file mode 100644 index 000000000..d26d404f4 --- /dev/null +++ b/filter/source/config/fragments/types/impress8.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/simpress* + odp + application/vnd.oasis.opendocument.presentation + true + impress8 + + Impress 8 + + Impress 8 + diff --git a/filter/source/config/fragments/types/impress8_template.xcu b/filter/source/config/fragments/types/impress8_template.xcu new file mode 100644 index 000000000..5c3170a97 --- /dev/null +++ b/filter/source/config/fragments/types/impress8_template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + otp + application/vnd.oasis.opendocument.presentation-template + false + impress8_template + + Impress 8 Template + + Impress 8 Template + diff --git a/filter/source/config/fragments/types/impress_AppleKeynote.xcu b/filter/source/config/fragments/types/impress_AppleKeynote.xcu new file mode 100644 index 000000000..797df7ae0 --- /dev/null +++ b/filter/source/config/fragments/types/impress_AppleKeynote.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Impress.KeynoteImportFilter + + + key + + + application/x-iwork-keynote-sffkey + + + true + + + Apple Keynote + + + Apple Keynote + + diff --git a/filter/source/config/fragments/types/impress_CGM_Computer_Graphics_Metafile.xcu b/filter/source/config/fragments/types/impress_CGM_Computer_Graphics_Metafile.xcu new file mode 100644 index 000000000..5f96f709f --- /dev/null +++ b/filter/source/config/fragments/types/impress_CGM_Computer_Graphics_Metafile.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + cgm + image/cgm + false + CGM - Computer Graphics Metafile + + CGM - Computer Graphics Metafile + + + diff --git a/filter/source/config/fragments/types/impress_ClarisWorks.xcu b/filter/source/config/fragments/types/impress_ClarisWorks.xcu new file mode 100644 index 000000000..396a6d677 --- /dev/null +++ b/filter/source/config/fragments/types/impress_ClarisWorks.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Impress.MWAWPresentationImportFilter + + cwk + application/clarisworks + true + ClarisWorks_Impress + + ClarisWorks/AppleWorks Presentation + + + diff --git a/filter/source/config/fragments/types/impress_MS_PowerPoint_97.xcu b/filter/source/config/fragments/types/impress_MS_PowerPoint_97.xcu new file mode 100644 index 000000000..0f1e119ac --- /dev/null +++ b/filter/source/config/fragments/types/impress_MS_PowerPoint_97.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + ppt dps + application/vnd.ms-powerpoint + false + MS PowerPoint 97 + + PowerPoint 97–2003 + + + diff --git a/filter/source/config/fragments/types/impress_MS_PowerPoint_97_AutoPlay.xcu b/filter/source/config/fragments/types/impress_MS_PowerPoint_97_AutoPlay.xcu new file mode 100644 index 000000000..b9e4a739f --- /dev/null +++ b/filter/source/config/fragments/types/impress_MS_PowerPoint_97_AutoPlay.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pps + application/vnd.ms-powerpoint + false + MS PowerPoint 97 AutoPlay + + PowerPoint 97–2003 + + + diff --git a/filter/source/config/fragments/types/impress_MS_PowerPoint_97_Vorlage.xcu b/filter/source/config/fragments/types/impress_MS_PowerPoint_97_Vorlage.xcu new file mode 100644 index 000000000..1cecfc87e --- /dev/null +++ b/filter/source/config/fragments/types/impress_MS_PowerPoint_97_Vorlage.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pot dpt + application/vnd.ms-powerpoint + false + MS PowerPoint 97 Vorlage + + PowerPoint 97–2000 Template + + + diff --git a/filter/source/config/fragments/types/impress_ODP_FlatXML.xcu b/filter/source/config/fragments/types/impress_ODP_FlatXML.xcu new file mode 100644 index 000000000..6e9792f98 --- /dev/null +++ b/filter/source/config/fragments/types/impress_ODP_FlatXML.xcu @@ -0,0 +1,31 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + fodp odp xml + application/vnd.oasis.opendocument.presentation-flat-xml + false + OpenDocument Presentation Flat XML + + OpenDocument Presentation (Flat XML) + + + doctype:office:mimetype="application/vnd.oasis.opendocument.presentation" + + diff --git a/filter/source/config/fragments/types/impress_OOXML_Presentation.xcu b/filter/source/config/fragments/types/impress_OOXML_Presentation.xcu new file mode 100644 index 000000000..6264ce716 --- /dev/null +++ b/filter/source/config/fragments/types/impress_OOXML_Presentation.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + pptx pptm + application/vnd.openxmlformats-officedocument.presentationml.presentation + true + Impress Office Open XML + Office Open XML Presentation + + diff --git a/filter/source/config/fragments/types/impress_OOXML_Presentation_AutoPlay.xcu b/filter/source/config/fragments/types/impress_OOXML_Presentation_AutoPlay.xcu new file mode 100644 index 000000000..78c638dae --- /dev/null +++ b/filter/source/config/fragments/types/impress_OOXML_Presentation_AutoPlay.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + ppsx + application/vnd.openxmlformats-officedocument.presentationml.slideshow + true + Impress Office Open XML AutoPlay + Office Open XML Presentation AutoPlay + + diff --git a/filter/source/config/fragments/types/impress_OOXML_Presentation_Template.xcu b/filter/source/config/fragments/types/impress_OOXML_Presentation_Template.xcu new file mode 100644 index 000000000..c34d39541 --- /dev/null +++ b/filter/source/config/fragments/types/impress_OOXML_Presentation_Template.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + potx potm + application/vnd.openxmlformats-officedocument.presentationml.template + true + Impress Office Open XML Template + Office Open XML Presentation Template + + diff --git a/filter/source/config/fragments/types/impress_PowerPoint3.xcu b/filter/source/config/fragments/types/impress_PowerPoint3.xcu new file mode 100644 index 000000000..4c6885943 --- /dev/null +++ b/filter/source/config/fragments/types/impress_PowerPoint3.xcu @@ -0,0 +1,22 @@ + + + + + com.sun.star.comp.Impress.MWAWPresentationImportFilter + + + ppt pot + + + PowerPoint 3 + + + Microsoft PowerPoint 1-4 + + diff --git a/filter/source/config/fragments/types/impress_StarOffice_XML_Impress.xcu b/filter/source/config/fragments/types/impress_StarOffice_XML_Impress.xcu new file mode 100644 index 000000000..311c43b66 --- /dev/null +++ b/filter/source/config/fragments/types/impress_StarOffice_XML_Impress.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sxi + application/vnd.sun.xml.impress + false + StarOffice XML (Impress) + + OpenOffice.org 1.0 Presentation + + Impress 6.0 + diff --git a/filter/source/config/fragments/types/impress_StarOffice_XML_Impress_Template.xcu b/filter/source/config/fragments/types/impress_StarOffice_XML_Impress_Template.xcu new file mode 100644 index 000000000..2df7deae8 --- /dev/null +++ b/filter/source/config/fragments/types/impress_StarOffice_XML_Impress_Template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sti + application/vnd.sun.xml.impress.template + false + impress_StarOffice_XML_Impress_Template + + Impress 6.0 Template + + Impress 6.0 + diff --git a/filter/source/config/fragments/types/jpg_JPEG.xcu b/filter/source/config/fragments/types/jpg_JPEG.xcu new file mode 100644 index 000000000..45f587430 --- /dev/null +++ b/filter/source/config/fragments/types/jpg_JPEG.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + jpg jpeg jfif jif jpe + image/jpeg + false + JPG - JPEG + + JPEG - Joint Photographic Experts Group + + + diff --git a/filter/source/config/fragments/types/math8.xcu b/filter/source/config/fragments/types/math8.xcu new file mode 100644 index 000000000..787f5baec --- /dev/null +++ b/filter/source/config/fragments/types/math8.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/smath* + odf + application/vnd.oasis.opendocument.formula + true + math8 + + Math 8 + + Math 8 + diff --git a/filter/source/config/fragments/types/math_MathML_XML_Math.xcu b/filter/source/config/fragments/types/math_MathML_XML_Math.xcu new file mode 100644 index 000000000..b8a4ae3ed --- /dev/null +++ b/filter/source/config/fragments/types/math_MathML_XML_Math.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.math.FormatDetector + + mml + application/mathml+xml + false + MathML XML (Math) + + MathML 2.0 + + + diff --git a/filter/source/config/fragments/types/math_MathType_3x.xcu b/filter/source/config/fragments/types/math_MathType_3x.xcu new file mode 100644 index 000000000..21c22d15d --- /dev/null +++ b/filter/source/config/fragments/types/math_MathType_3x.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.math.FormatDetector + + xxx + + false + MathType 3.x + + MathType3.x + + DS Equation + diff --git a/filter/source/config/fragments/types/math_StarOffice_XML_Math.xcu b/filter/source/config/fragments/types/math_StarOffice_XML_Math.xcu new file mode 100644 index 000000000..c1d31ac8d --- /dev/null +++ b/filter/source/config/fragments/types/math_StarOffice_XML_Math.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sxm + application/vnd.sun.xml.math + false + StarOffice XML (Math) + + OpenOffice.org 1.0 Formula + + Math 6.0 + diff --git a/filter/source/config/fragments/types/met_OS2_Metafile.xcu b/filter/source/config/fragments/types/met_OS2_Metafile.xcu new file mode 100644 index 000000000..708a498ee --- /dev/null +++ b/filter/source/config/fragments/types/met_OS2_Metafile.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + met + image/x-met + false + MET - OS/2 Metafile + + MET - OS/2 Metafile + + + diff --git a/filter/source/config/fragments/types/mov_MOV.xcu b/filter/source/config/fragments/types/mov_MOV.xcu new file mode 100644 index 000000000..7471a78a7 --- /dev/null +++ b/filter/source/config/fragments/types/mov_MOV.xcu @@ -0,0 +1,20 @@ + + + com.sun.star.comp.draw.FormatDetector + + mov MOV + application/movie + false + MOV - MOV + + MOV - QuickTime File Format + + + diff --git a/filter/source/config/fragments/types/oxt_OpenOffice_Extension.xcu b/filter/source/config/fragments/types/oxt_OpenOffice_Extension.xcu new file mode 100644 index 000000000..ee11dad05 --- /dev/null +++ b/filter/source/config/fragments/types/oxt_OpenOffice_Extension.xcu @@ -0,0 +1,29 @@ + + + + oxt + + false + + OpenOffice Extension + + + com.sun.star.comp.framework.OXTFileHandler + + diff --git a/filter/source/config/fragments/types/pbm_Portable_Bitmap.xcu b/filter/source/config/fragments/types/pbm_Portable_Bitmap.xcu new file mode 100644 index 000000000..28e489fdb --- /dev/null +++ b/filter/source/config/fragments/types/pbm_Portable_Bitmap.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pbm + image/x-portable-bitmap + false + PBM - Portable Bitmap + + PBM - Portable Bitmap + + + diff --git a/filter/source/config/fragments/types/pcd_Photo_CD_Base.xcu b/filter/source/config/fragments/types/pcd_Photo_CD_Base.xcu new file mode 100644 index 000000000..6465a0f4f --- /dev/null +++ b/filter/source/config/fragments/types/pcd_Photo_CD_Base.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pcd + image/x-photo-cd + false + draw_PCD_Photo_CD_Base + + PCD - Photo CD Base + + + diff --git a/filter/source/config/fragments/types/pcd_Photo_CD_Base16.xcu b/filter/source/config/fragments/types/pcd_Photo_CD_Base16.xcu new file mode 100644 index 000000000..4caacf6ef --- /dev/null +++ b/filter/source/config/fragments/types/pcd_Photo_CD_Base16.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pcd + image/x-photo-cd + false + draw_PCD_Photo_CD_Base16 + + PCD - Photo CD Base16 + + + diff --git a/filter/source/config/fragments/types/pcd_Photo_CD_Base4.xcu b/filter/source/config/fragments/types/pcd_Photo_CD_Base4.xcu new file mode 100644 index 000000000..8cb48b1f5 --- /dev/null +++ b/filter/source/config/fragments/types/pcd_Photo_CD_Base4.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pcd + image/x-photo-cd + false + draw_PCD_Photo_CD_Base4 + + PCD - Photo CD Base4 + + + diff --git a/filter/source/config/fragments/types/pct_Mac_Pict.xcu b/filter/source/config/fragments/types/pct_Mac_Pict.xcu new file mode 100644 index 000000000..d2abc377d --- /dev/null +++ b/filter/source/config/fragments/types/pct_Mac_Pict.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pct pict + image/x-pict + false + PCT - Mac Pict + + PCT - Mac Pict + + + diff --git a/filter/source/config/fragments/types/pcx_Zsoft_Paintbrush.xcu b/filter/source/config/fragments/types/pcx_Zsoft_Paintbrush.xcu new file mode 100644 index 000000000..5365bd8aa --- /dev/null +++ b/filter/source/config/fragments/types/pcx_Zsoft_Paintbrush.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pcx + image/x-pcx + false + PCX - Zsoft Paintbrush + + PCX - Zsoft Paintbrush + + + diff --git a/filter/source/config/fragments/types/pdf_Portable_Document_Format.xcu b/filter/source/config/fragments/types/pdf_Portable_Document_Format.xcu new file mode 100644 index 000000000..056b42287 --- /dev/null +++ b/filter/source/config/fragments/types/pdf_Portable_Document_Format.xcu @@ -0,0 +1,29 @@ + + + + + pdf + application/pdf + false + + + PDF - Portable Document Format + + + diff --git a/filter/source/config/fragments/types/pgm_Portable_Graymap.xcu b/filter/source/config/fragments/types/pgm_Portable_Graymap.xcu new file mode 100644 index 000000000..fd6c4c4ee --- /dev/null +++ b/filter/source/config/fragments/types/pgm_Portable_Graymap.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + pgm + image/x-portable-graymap + false + PGM - Portable Graymap + + PGM - Portable Graymap + + + diff --git a/filter/source/config/fragments/types/png_Portable_Network_Graphic.xcu b/filter/source/config/fragments/types/png_Portable_Network_Graphic.xcu new file mode 100644 index 000000000..7fe5e2adb --- /dev/null +++ b/filter/source/config/fragments/types/png_Portable_Network_Graphic.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + png + image/png + false + PNG - Portable Network Graphic + + PNG - Portable Network Graphic + + + diff --git a/filter/source/config/fragments/types/ppm_Portable_Pixelmap.xcu b/filter/source/config/fragments/types/ppm_Portable_Pixelmap.xcu new file mode 100644 index 000000000..9fd7b8b9e --- /dev/null +++ b/filter/source/config/fragments/types/ppm_Portable_Pixelmap.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + ppm + image/x-portable-pixmap + false + PPM - Portable Pixelmap + + PPM - Portable Pixelmap + + + diff --git a/filter/source/config/fragments/types/psd_Adobe_Photoshop.xcu b/filter/source/config/fragments/types/psd_Adobe_Photoshop.xcu new file mode 100644 index 000000000..586541451 --- /dev/null +++ b/filter/source/config/fragments/types/psd_Adobe_Photoshop.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + psd + image/vnd.adobe.photoshop + false + PSD - Adobe Photoshop + + PSD - Adobe Photoshop + + + diff --git a/filter/source/config/fragments/types/ras_Sun_Rasterfile.xcu b/filter/source/config/fragments/types/ras_Sun_Rasterfile.xcu new file mode 100644 index 000000000..81b9238d1 --- /dev/null +++ b/filter/source/config/fragments/types/ras_Sun_Rasterfile.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + ras + image/x-cmu-raster + false + RAS - Sun Rasterfile + + RAS - Sun Raster Image + + + diff --git a/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu b/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu new file mode 100644 index 000000000..a2015a536 --- /dev/null +++ b/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.SVGFilter + + svg svgz + image/svg+xml + false + SVG - Scalable Vector Graphics + + SVG - Scalable Vector Graphics + + + diff --git a/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics_Draw.xcu b/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics_Draw.xcu new file mode 100644 index 000000000..4b3b9cab5 --- /dev/null +++ b/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics_Draw.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Draw.SVGFilter + + svg svgz + image/svg+xml + true + SVG - Scalable Vector Graphics Draw + + SVG - Scalable Vector Graphics Draw + + + diff --git a/filter/source/config/fragments/types/svm_StarView_Metafile.xcu b/filter/source/config/fragments/types/svm_StarView_Metafile.xcu new file mode 100644 index 000000000..5d81959b5 --- /dev/null +++ b/filter/source/config/fragments/types/svm_StarView_Metafile.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + svm + image/x-svm + false + SVM - StarView Metafile + + SVM - StarView Meta File + + + diff --git a/filter/source/config/fragments/types/tga_Truevision_TARGA.xcu b/filter/source/config/fragments/types/tga_Truevision_TARGA.xcu new file mode 100644 index 000000000..248637d2f --- /dev/null +++ b/filter/source/config/fragments/types/tga_Truevision_TARGA.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + tga + image/x-targa + false + TGA - Truevision TARGA + + TGA - Truevision Targa + + + diff --git a/filter/source/config/fragments/types/tif_Tag_Image_File.xcu b/filter/source/config/fragments/types/tif_Tag_Image_File.xcu new file mode 100644 index 000000000..a84e66623 --- /dev/null +++ b/filter/source/config/fragments/types/tif_Tag_Image_File.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + tif tiff + image/tiff + false + TIF - Tag Image File + + TIFF - Tagged Image File Format + + + diff --git a/filter/source/config/fragments/types/wav_Wave_Audio_File.xcu b/filter/source/config/fragments/types/wav_Wave_Audio_File.xcu new file mode 100644 index 000000000..f30623270 --- /dev/null +++ b/filter/source/config/fragments/types/wav_Wave_Audio_File.xcu @@ -0,0 +1,29 @@ + + + + wav + + false + + Wave Audio File + + + com.sun.star.comp.framework.SoundHandler + + diff --git a/filter/source/config/fragments/types/webp_WebP.xcu b/filter/source/config/fragments/types/webp_WebP.xcu new file mode 100644 index 000000000..e58984fbe --- /dev/null +++ b/filter/source/config/fragments/types/webp_WebP.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + webp + image/webp + false + WEBP - WebP + + WEBP - WebP Image + + + diff --git a/filter/source/config/fragments/types/wmf_MS_Windows_Metafile.xcu b/filter/source/config/fragments/types/wmf_MS_Windows_Metafile.xcu new file mode 100644 index 000000000..7564dd057 --- /dev/null +++ b/filter/source/config/fragments/types/wmf_MS_Windows_Metafile.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + wmf wmz + image/x-wmf + false + WMF - MS Windows Metafile + + WMF - Windows Metafile + + + diff --git a/filter/source/config/fragments/types/writer8.xcu b/filter/source/config/fragments/types/writer8.xcu new file mode 100644 index 000000000..8a2effbde --- /dev/null +++ b/filter/source/config/fragments/types/writer8.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/swriter + odt + application/vnd.oasis.opendocument.text + true + writer8 + + Writer 8 + + Writer 8 + diff --git a/filter/source/config/fragments/types/writer8_template.xcu b/filter/source/config/fragments/types/writer8_template.xcu new file mode 100644 index 000000000..eeb4b3512 --- /dev/null +++ b/filter/source/config/fragments/types/writer8_template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + ott + application/vnd.oasis.opendocument.text-template + true + writer8_template + + Writer 8 Template + + Writer 8 Template + diff --git a/filter/source/config/fragments/types/writer_AbiWord_Document.xcu b/filter/source/config/fragments/types/writer_AbiWord_Document.xcu new file mode 100644 index 000000000..bb4527729 --- /dev/null +++ b/filter/source/config/fragments/types/writer_AbiWord_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.AbiWordImportFilter + + abw zabw + application/x-abiword + true + AbiWord + + AbiWord Document + + + diff --git a/filter/source/config/fragments/types/writer_ApplePages.xcu b/filter/source/config/fragments/types/writer_ApplePages.xcu new file mode 100644 index 000000000..823a766b5 --- /dev/null +++ b/filter/source/config/fragments/types/writer_ApplePages.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Writer.PagesImportFilter + + + pages + + + application/x-iwork-pages-sffpages + + + true + + + Apple Pages + + + Apple Pages + + diff --git a/filter/source/config/fragments/types/writer_BroadBand_eBook.xcu b/filter/source/config/fragments/types/writer_BroadBand_eBook.xcu new file mode 100644 index 000000000..129f33005 --- /dev/null +++ b/filter/source/config/fragments/types/writer_BroadBand_eBook.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Writer.EBookImportFilter + + + lrf + + + application/x-sony-bbeb + + + true + + + BroadBand eBook + + + BroadBand eBook + + diff --git a/filter/source/config/fragments/types/writer_ClarisWorks.xcu b/filter/source/config/fragments/types/writer_ClarisWorks.xcu new file mode 100644 index 000000000..f716ef01a --- /dev/null +++ b/filter/source/config/fragments/types/writer_ClarisWorks.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MWAWImportFilter + + cwk + application/clarisworks + true + ClarisWorks + + ClarisWorks/AppleWorks Document + + + diff --git a/filter/source/config/fragments/types/writer_DocBook_File.xcu b/filter/source/config/fragments/types/writer_DocBook_File.xcu new file mode 100644 index 000000000..613588493 --- /dev/null +++ b/filter/source/config/fragments/types/writer_DocBook_File.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + xml + application/docbook+xml + false + DocBook File + + DocBook + + doctype:-//OASIS//DTD DocBook XML V4 + diff --git a/filter/source/config/fragments/types/writer_DosWord.xcu b/filter/source/config/fragments/types/writer_DosWord.xcu new file mode 100644 index 000000000..37333886a --- /dev/null +++ b/filter/source/config/fragments/types/writer_DosWord.xcu @@ -0,0 +1,22 @@ + + + + + com.sun.star.comp.Writer.MSWorksImportFilter + + + doc + + + DosWord + + + Microsoft Word for DOS + + diff --git a/filter/source/config/fragments/types/writer_EPUB_Document.xcu b/filter/source/config/fragments/types/writer_EPUB_Document.xcu new file mode 100644 index 000000000..51a0a73c2 --- /dev/null +++ b/filter/source/config/fragments/types/writer_EPUB_Document.xcu @@ -0,0 +1,29 @@ + + + + + epub + application/epub+zip + false + + + EPUB Document + + + diff --git a/filter/source/config/fragments/types/writer_FictionBook_2.xcu b/filter/source/config/fragments/types/writer_FictionBook_2.xcu new file mode 100644 index 000000000..a6a543713 --- /dev/null +++ b/filter/source/config/fragments/types/writer_FictionBook_2.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Writer.EBookImportFilter + + + fb2 zip + + + application/x-fictionbook+xml + + + true + + + FictionBook 2 + + + FictionBook 2.0 + + diff --git a/filter/source/config/fragments/types/writer_LotusWordPro_Document.xcu b/filter/source/config/fragments/types/writer_LotusWordPro_Document.xcu new file mode 100644 index 000000000..ca30d232c --- /dev/null +++ b/filter/source/config/fragments/types/writer_LotusWordPro_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.LotusWordProImportFilter + + lwp + application/vnd.lotus-wordpro + false + LotusWordPro + + LotusWordPro Document + + + diff --git a/filter/source/config/fragments/types/writer_MIZI_Hwp_97.xcu b/filter/source/config/fragments/types/writer_MIZI_Hwp_97.xcu new file mode 100644 index 000000000..063795749 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MIZI_Hwp_97.xcu @@ -0,0 +1,29 @@ + + + com.sun.comp.hwpimport.HwpImportFilter + + hwp + application/x-hwp + false + writer_MIZI_Hwp_97 + + Hangul WP 97 + + + diff --git a/filter/source/config/fragments/types/writer_MS_WinWord_5.xcu b/filter/source/config/fragments/types/writer_MS_WinWord_5.xcu new file mode 100644 index 000000000..87ee89e85 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_WinWord_5.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + + doc + application/msword + false + MS WinWord 5 + + Microsoft WinWord 1/2/5 + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_WinWord_60.xcu b/filter/source/config/fragments/types/writer_MS_WinWord_60.xcu new file mode 100644 index 000000000..21c3d854c --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_WinWord_60.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + + doc + application/msword + false + MS WinWord 6.0 + + Microsoft Word 6.0 + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Word_2003_XML.xcu b/filter/source/config/fragments/types/writer_MS_Word_2003_XML.xcu new file mode 100644 index 000000000..60d132e20 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_2003_XML.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + xml doc + + false + MS Word 2003 XML + + Word 2003 XML + + doctype:wordDocument + diff --git a/filter/source/config/fragments/types/writer_MS_Word_2007_XML.xcu b/filter/source/config/fragments/types/writer_MS_Word_2007_XML.xcu new file mode 100644 index 000000000..75cb091cd --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_2007_XML.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + docx + application/msword + true + MS Word 2007 XML + Word 2007–365 + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Word_2007_XML_Template.xcu b/filter/source/config/fragments/types/writer_MS_Word_2007_XML_Template.xcu new file mode 100644 index 000000000..391cc20ce --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_2007_XML_Template.xcu @@ -0,0 +1,27 @@ + + + com.sun.star.comp.oox.FormatDetector + + dotx dotm + application/msword + true + MS Word 2007 XML Template + Word 2007–365 Template + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Word_2007_XML_VBA.xcu b/filter/source/config/fragments/types/writer_MS_Word_2007_XML_VBA.xcu new file mode 100644 index 000000000..8a44c1e5f --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_2007_XML_VBA.xcu @@ -0,0 +1,17 @@ + + + com.sun.star.comp.oox.FormatDetector + + docm + application/msword + true + MS Word 2007 XML VBA + Word 2007–365 VBA + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Word_95.xcu b/filter/source/config/fragments/types/writer_MS_Word_95.xcu new file mode 100644 index 000000000..2051a5135 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_95.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + + doc + application/msword + false + MS Word 95 + + Microsoft Word 95 + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Word_95_Vorlage.xcu b/filter/source/config/fragments/types/writer_MS_Word_95_Vorlage.xcu new file mode 100644 index 000000000..be6e9bbd5 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_95_Vorlage.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + + dot + application/msword + false + MS Word 95 Vorlage + + MS Word 95 Template + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Word_97.xcu b/filter/source/config/fragments/types/writer_MS_Word_97.xcu new file mode 100644 index 000000000..d1e250157 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_97.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + + doc wps + application/msword + true + MS Word 97 + + Word 97–2003 + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Word_97_Vorlage.xcu b/filter/source/config/fragments/types/writer_MS_Word_97_Vorlage.xcu new file mode 100644 index 000000000..4aa82a4fb --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Word_97_Vorlage.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + + dot wpt + application/msword + true + MS Word 97 Vorlage + + Word 97–2000 Template + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_MS_Works_Document.xcu b/filter/source/config/fragments/types/writer_MS_Works_Document.xcu new file mode 100644 index 000000000..51e50ed24 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Works_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MSWorksImportFilter + + wps + application/vnd.ms-works + true + MS_Works + + Microsoft Works Document + + + diff --git a/filter/source/config/fragments/types/writer_MS_Write.xcu b/filter/source/config/fragments/types/writer_MS_Write.xcu new file mode 100644 index 000000000..48ae04b3c --- /dev/null +++ b/filter/source/config/fragments/types/writer_MS_Write.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MSWorksImportFilter + + wri + application/x-mswrite + true + MS_Write + + Microsoft Write + + + diff --git a/filter/source/config/fragments/types/writer_MacWrite.xcu b/filter/source/config/fragments/types/writer_MacWrite.xcu new file mode 100644 index 000000000..9be82f113 --- /dev/null +++ b/filter/source/config/fragments/types/writer_MacWrite.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MWAWImportFilter + + mw mcw + application/macwriteii + true + MacWrite + + MacWrite Document + + + diff --git a/filter/source/config/fragments/types/writer_Mac_Word.xcu b/filter/source/config/fragments/types/writer_Mac_Word.xcu new file mode 100644 index 000000000..b598559da --- /dev/null +++ b/filter/source/config/fragments/types/writer_Mac_Word.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MWAWImportFilter + + doc + application/msword + true + Mac_Word + + Microsoft Word for Mac (v1 - v5) + + + diff --git a/filter/source/config/fragments/types/writer_Mac_Works.xcu b/filter/source/config/fragments/types/writer_Mac_Works.xcu new file mode 100644 index 000000000..9785ebc82 --- /dev/null +++ b/filter/source/config/fragments/types/writer_Mac_Works.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MWAWImportFilter + + wps + application/vnd.ms-works + true + Mac_Works + + Microsoft Works for Mac Document (v1 - v4) + + + diff --git a/filter/source/config/fragments/types/writer_Mariner_Write.xcu b/filter/source/config/fragments/types/writer_Mariner_Write.xcu new file mode 100644 index 000000000..d3df7576d --- /dev/null +++ b/filter/source/config/fragments/types/writer_Mariner_Write.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MWAWImportFilter + + mwd + + true + Mariner_Write + + Mariner Write Mac Classic v1.6 - v3.5 + + + diff --git a/filter/source/config/fragments/types/writer_ODT_FlatXML.xcu b/filter/source/config/fragments/types/writer_ODT_FlatXML.xcu new file mode 100644 index 000000000..fc170564b --- /dev/null +++ b/filter/source/config/fragments/types/writer_ODT_FlatXML.xcu @@ -0,0 +1,31 @@ + + + com.sun.star.comp.filters.XMLFilterDetect + + fodt odt xml + application/vnd.oasis.opendocument.text-flat-xml + false + OpenDocument Text Flat XML + + OpenDocument Text (Flat XML) + + + doctype:office:mimetype="application/vnd.oasis.opendocument.text" + + diff --git a/filter/source/config/fragments/types/writer_OOXML.xcu b/filter/source/config/fragments/types/writer_OOXML.xcu new file mode 100644 index 000000000..8d6a025fd --- /dev/null +++ b/filter/source/config/fragments/types/writer_OOXML.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.oox.FormatDetector + + docx docm + application/vnd.openxmlformats-officedocument.wordprocessingml.document + true + Office Open XML Text + + Office Open XML Text Document (Transitional) + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_OOXML_Template.xcu b/filter/source/config/fragments/types/writer_OOXML_Template.xcu new file mode 100644 index 000000000..39f499eb6 --- /dev/null +++ b/filter/source/config/fragments/types/writer_OOXML_Template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.oox.FormatDetector + + dotx dotm + application/vnd.openxmlformats-officedocument.wordprocessingml.template + true + Office Open XML Text Template + + Office Open XML Text Template (Transitional) + + MSWordDoc + diff --git a/filter/source/config/fragments/types/writer_PalmDoc.xcu b/filter/source/config/fragments/types/writer_PalmDoc.xcu new file mode 100644 index 000000000..f45718ab8 --- /dev/null +++ b/filter/source/config/fragments/types/writer_PalmDoc.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Writer.EBookImportFilter + + + pdb + + + application/x-aportisdoc + + + true + + + PalmDoc + + + PalmDoc eBook + + diff --git a/filter/source/config/fragments/types/writer_Plucker_eBook.xcu b/filter/source/config/fragments/types/writer_Plucker_eBook.xcu new file mode 100644 index 000000000..000d872a5 --- /dev/null +++ b/filter/source/config/fragments/types/writer_Plucker_eBook.xcu @@ -0,0 +1,29 @@ + + + + + org.libreoffice.comp.Writer.EBookImportFilter + + + pdb + + + application/prs.plucker + + + true + + + Plucker eBook + + + Plucker eBook + + diff --git a/filter/source/config/fragments/types/writer_PocketWord_File.xcu b/filter/source/config/fragments/types/writer_PocketWord_File.xcu new file mode 100644 index 000000000..3f146aba5 --- /dev/null +++ b/filter/source/config/fragments/types/writer_PocketWord_File.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MSWorksImportFilter + + psw + application/x-pocket-word + false + PocketWord File + + Pocket Word + + doctype:pwi + diff --git a/filter/source/config/fragments/types/writer_Rich_Text_Format.xcu b/filter/source/config/fragments/types/writer_Rich_Text_Format.xcu new file mode 100644 index 000000000..76f28fb36 --- /dev/null +++ b/filter/source/config/fragments/types/writer_Rich_Text_Format.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + + rtf + application/rtf + false + Rich Text Format + + Rich Text Format + + + diff --git a/filter/source/config/fragments/types/writer_StarOffice_XML_Writer.xcu b/filter/source/config/fragments/types/writer_StarOffice_XML_Writer.xcu new file mode 100644 index 000000000..e8dd8c275 --- /dev/null +++ b/filter/source/config/fragments/types/writer_StarOffice_XML_Writer.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sxw + application/vnd.sun.xml.writer + false + StarOffice XML (Writer) + + OpenOffice.org 1.0 Text Document + + Writer 6.0 + diff --git a/filter/source/config/fragments/types/writer_StarOffice_XML_Writer_Template.xcu b/filter/source/config/fragments/types/writer_StarOffice_XML_Writer_Template.xcu new file mode 100644 index 000000000..b5b19b58e --- /dev/null +++ b/filter/source/config/fragments/types/writer_StarOffice_XML_Writer_Template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + stw + application/vnd.sun.xml.writer.template + true + writer_StarOffice_XML_Writer_Template + + Writer 6.0 Template + + Writer 6.0 + diff --git a/filter/source/config/fragments/types/writer_T602_Document.xcu b/filter/source/config/fragments/types/writer_T602_Document.xcu new file mode 100644 index 000000000..e9b3df39c --- /dev/null +++ b/filter/source/config/fragments/types/writer_T602_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.T602ImportFilter + + 602 + application/x-t602 + true + T602Document + + T602 Document + + + diff --git a/filter/source/config/fragments/types/writer_WordPerfect_Document.xcu b/filter/source/config/fragments/types/writer_WordPerfect_Document.xcu new file mode 100644 index 000000000..ba358d9b2 --- /dev/null +++ b/filter/source/config/fragments/types/writer_WordPerfect_Document.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.WordPerfectImportFilter + + wpd + application/vnd.wordperfect + true + WordPerfect + + WordPerfect Document + + + diff --git a/filter/source/config/fragments/types/writer_WriteNow.xcu b/filter/source/config/fragments/types/writer_WriteNow.xcu new file mode 100644 index 000000000..b41b8af4b --- /dev/null +++ b/filter/source/config/fragments/types/writer_WriteNow.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.Writer.MWAWImportFilter + + wn nx^d + + true + WriteNow + + WriteNow Document + + + diff --git a/filter/source/config/fragments/types/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu b/filter/source/config/fragments/types/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu new file mode 100644 index 000000000..e920809e6 --- /dev/null +++ b/filter/source/config/fragments/types/writer_globaldocument_StarOffice_XML_Writer_GlobalDocument.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + sxg + application/vnd.sun.xml.writer.global + false + writer_globaldocument_StarOffice_XML_Writer_GlobalDocument + + Writer 6.0 Master Document + + Writer/Global 6.0 + diff --git a/filter/source/config/fragments/types/writer_indexing_export_xml.xcu b/filter/source/config/fragments/types/writer_indexing_export_xml.xcu new file mode 100644 index 000000000..4cda6e597 --- /dev/null +++ b/filter/source/config/fragments/types/writer_indexing_export_xml.xcu @@ -0,0 +1,21 @@ + + + + + + xml + + false + + + Writer Indexing Export XML + + + diff --git a/filter/source/config/fragments/types/writer_layout_dump_xml.xcu b/filter/source/config/fragments/types/writer_layout_dump_xml.xcu new file mode 100644 index 000000000..1f3a93de8 --- /dev/null +++ b/filter/source/config/fragments/types/writer_layout_dump_xml.xcu @@ -0,0 +1,29 @@ + + + + + xml + + false + + + Writer Layout Dump + + + diff --git a/filter/source/config/fragments/types/writer_web_HTML_help.xcu b/filter/source/config/fragments/types/writer_web_HTML_help.xcu new file mode 100644 index 000000000..c558ebe6d --- /dev/null +++ b/filter/source/config/fragments/types/writer_web_HTML_help.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.text.FormatDetector + vnd.sun.star.help://* + + + false + writer_web_HTML_help + + Help content + + + diff --git a/filter/source/config/fragments/types/writer_web_StarOffice_XML_Writer_Web_Template.xcu b/filter/source/config/fragments/types/writer_web_StarOffice_XML_Writer_Web_Template.xcu new file mode 100644 index 000000000..e81eebb28 --- /dev/null +++ b/filter/source/config/fragments/types/writer_web_StarOffice_XML_Writer_Web_Template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + stw + application/vnd.sun.xml.writer.web + false + writer_web_StarOffice_XML_Writer_Web_Template + + Writer/Web 6.0 Template + + Writer/Web 6.0 + diff --git a/filter/source/config/fragments/types/writerglobal8.xcu b/filter/source/config/fragments/types/writerglobal8.xcu new file mode 100644 index 000000000..550a2a5ab --- /dev/null +++ b/filter/source/config/fragments/types/writerglobal8.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/swriter/GlobalDocument* + odm + application/vnd.oasis.opendocument.text-master + true + writerglobal8 + + Writer 8 Master Document + + Writer/Global 8 + diff --git a/filter/source/config/fragments/types/writerglobal8_template.xcu b/filter/source/config/fragments/types/writerglobal8_template.xcu new file mode 100644 index 000000000..10c866b5f --- /dev/null +++ b/filter/source/config/fragments/types/writerglobal8_template.xcu @@ -0,0 +1,19 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + private:factory/swriter/GlobalDocument* + otm + application/vnd.oasis.opendocument.text-master-template + true + writerglobal8_template + + Writer 8 Master Document Template + + Writer/Global 8 Template + diff --git a/filter/source/config/fragments/types/writerweb8_writer_template.xcu b/filter/source/config/fragments/types/writerweb8_writer_template.xcu new file mode 100644 index 000000000..9d1ace8ed --- /dev/null +++ b/filter/source/config/fragments/types/writerweb8_writer_template.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.filters.StorageFilterDetect + + oth + application/vnd.oasis.opendocument.text-web + false + writerweb8_writer_template + + Writer/Web 8 Template + + Writer/Web 8 + diff --git a/filter/source/config/fragments/types/xbm_X_Consortium.xcu b/filter/source/config/fragments/types/xbm_X_Consortium.xcu new file mode 100644 index 000000000..55685d500 --- /dev/null +++ b/filter/source/config/fragments/types/xbm_X_Consortium.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + xbm + image/x-xbitmap + false + XBM - X-Consortium + + XBM - X Bitmap + + + diff --git a/filter/source/config/fragments/types/xpm_XPM.xcu b/filter/source/config/fragments/types/xpm_XPM.xcu new file mode 100644 index 000000000..585211ad8 --- /dev/null +++ b/filter/source/config/fragments/types/xpm_XPM.xcu @@ -0,0 +1,29 @@ + + + com.sun.star.comp.draw.FormatDetector + + xpm + image/x-xpixmap + false + XPM + + XPM - X PixMap + + + diff --git a/filter/source/config/tools/merge/FCFGMerge.cfg b/filter/source/config/tools/merge/FCFGMerge.cfg new file mode 100644 index 000000000..8a0b4b78f --- /dev/null +++ b/filter/source/config/tools/merge/FCFGMerge.cfg @@ -0,0 +1,112 @@ +# +# 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 . +# + +#************************************************ +# Specify the verbose mode of this tool. +# 1 = show errors only +# 2 = show errors/warnings (default) +# 3 = show errors/warnings and some generic infos +# 4 = show anything (including detailed infos) +# +# [OPTIONAL] +#************************************************ + +loglevel = 2 + +#************************************************ +# This extension is used for all XML files. It doesn't +# matter if it's used for reading fragments or writing +# XML packages. +# Must be given without any additional signes like "." +# or "*."! +# +# [REQUIRED] +#************************************************ + +extension_xcu=xcu + +#************************************************ +# This extension is used for all Package files. It doesn't +# matter if it's used for reading such files or writing +# it. +# Must be given without any additional signes like "." +# or "*."! +# +# [REQUIRED] +#************************************************ + +extension_pkg=pkg + +#************************************************ +# These values are used to generate a correct XML +# header. +# Note: The property "xmlpackage" must be specified +# via command line. There exists more than one +# possible value. +# +# [REQUIRED] +#************************************************ + +xmlversion = 1.0 +xmlencoding = UTF-8 +xmlpath = org.openoffice.TypeDetection +#xmlpackage = + +#************************************************ +# These values are used to name the configuration +# sets inside the generated XCM file for different +# item groups like e.g. types, filters etcpp. +# +# [REQUIRED] +#************************************************ + +setname_types = Types +setname_filters = Filters +setname_frameloaders = FrameLoaders +setname_contenthandlers = ContentHandlers + +subdir_types = types +subdir_filters = filters +subdir_frameloaders = frameloaders +subdir_contenthandlers = contenthandlers + +#************************************************ +# This delimiter is used to split every +# item list of the package configuration files +# (which are temp. created by the make process) +# into its tokens. +# +# [REQUIRED] +#************************************************ +delimiter=, + +#************************************************ +# Enable/disable removing of leading/trailing whitespaces +# during splitting stringlists. +# +# [REQUIRED] +#************************************************ +trim=true + +#************************************************ +# Enable/disable removing of leading/trailing "-signs +# during splitting stringlists. +# +# [REQUIRED] +#************************************************ +decode=false diff --git a/filter/source/config/tools/merge/pyAltFCFGMerge b/filter/source/config/tools/merge/pyAltFCFGMerge new file mode 100755 index 000000000..7040108e8 --- /dev/null +++ b/filter/source/config/tools/merge/pyAltFCFGMerge @@ -0,0 +1,590 @@ +#!/usr/bin/env python +#_____________________________________________ +# Caolan McNamara caolanm@redhat.com +# converted from original java written by Andreas Schluens so we can continue +# to build 680 OpenOffice.org series without java +# this is not really a replacement for the existing java tool, just the +# minimum required to make it work for now, the existing tool is still +# the canonical base, changes to it will have to be mirrored here until +# there is a java which is available for use by all +#_____________________________________________ + +import sys, string, os.path, codecs + +CFGFILE = os.environ["SRCDIR"] + "/filter/source/config/tools/merge/FCFGMerge.cfg" + +PROP_XMLVERSION = "xmlversion" # // <= global cfg file +PROP_XMLENCODING = "xmlencoding" # // <= global cfg file +PROP_XMLPATH = "xmlpath" # // <= global cfg file +PROP_XMLPACKAGE = "xmlpackage" # // <= global cfg file +PROP_SETNAME_TYPES = "setname_types" # // <= global cfg file +PROP_SETNAME_FILTERS = "setname_filters" # // <= global cfg file +PROP_SETNAME_LOADERS = "setname_frameloaders" # // <= global cfg file +PROP_SETNAME_HANDLERS = "setname_contenthandlers" # // <= global cfg file +PROP_SUBDIR_TYPES = "subdir_types" # // <= global cfg file +PROP_SUBDIR_FILTERS = "subdir_filters" # // <= global cfg file +PROP_SUBDIR_LOADERS = "subdir_frameloaders" # // <= global cfg file +PROP_SUBDIR_HANDLERS = "subdir_contenthandlers" # // <= global cfg file +PROP_EXTENSION_XCU = "extension_xcu" # // <= global cfg file +PROP_EXTENSION_PKG = "extension_pkg" # // <= global cfg file +PROP_DELIMITER = "delimiter" # // <= global cfg file +PROP_TRIM = "trim" # // <= global cfg file +PROP_DECODE = "decode" # // <= global cfg file +PROP_FRAGMENTSDIR = "fragmentsdir" # // <= cmdline +PROP_TEMPDIR = "tempdir" # // <= cmdline +PROP_OUTDIR = "outdir" # // <= cmdline +PROP_PKG = "pkg" # // <= cmdline +PROP_TCFG = "tcfg" # // <= cmdline +PROP_FCFG = "fcfg" # // <= cmdline +PROP_LCFG = "lcfg" # // <= cmdline +PROP_CCFG = "ccfg" # // <= cmdline +PROP_LANGUAGEPACK = "languagepack" # // <= cmdline +PROP_VERBOSE = "verbose" # // <= cmdline +PROP_SHARE_SUBDIR_NAME = "share_subdir_name" # // <= cmdline +PROP_ITEMS = "items" # // <= pkg cfg files! + +#---begin java.util.Properties copy---# +r""" + +An incomplete clean room implementation of +java.util.Properties written in Python. + +Copyright (C) 2002,2004 - Ollie Rutherfurd + +Based on: + + http://java.sun.com/j2se/1.3/docs/api/java/util/Properties.html + +Missing: + + - Currently, u\XXXX sequences are escaped when saving, but not unescaped + when read... + +License: Python License + +Example Usage: + +>>> from properties import Properties +>>> props = Properties() +>>> props['one'] = '1' +>>> props['your name'] = "I don't know" +>>> print('\n'.join(list(props.keys()))) +your name +one +>>> from StringIO import StringIO +>>> buff = StringIO() +>>> props.store(buff, "a little example...") +>>> buff.seek(0) +>>> print(buff.read()) +# a little example... +your\ name=I\ don\'t\ know +one=1 +>>> print(props['your name']) +I don't know + +$Id: pyAltFCFGMerge,v 1.3 2007-12-07 10:57:44 vg Exp $ + +""" + +__all__ = ['Properties'] + + +def dec2hex(n): + h = hex(n)[2:].upper() + return '\\u' + '0' * (4 - len(h)) + h + + +def escapestr(s): + buff = [] + # QUESTION: escape leading or trailing spaces? + for c in s: + if c == '\\': + buff.append('\\\\') + elif c == '\t': + buff.append('\\t') + elif c == '\n': + buff.append('\\n') + elif c == '\r': + buff.append('\\r') + elif c == ' ': + buff.append('\\ ') + elif c == "'": + buff.append("\\'") + elif c == '"': + buff.append('\\"') + elif c == '#': + buff.append('\\#') + elif c == '!': + buff.append('\\!') + elif c == '=': + buff.append('\\=') + elif 32 <= ord(c) <= 126: + buff.append(c) + else: + buff.append(dec2hex(c)) + + return ''.join(buff) + + +# TODO: add support for \uXXXX? +def unescapestr(line): + buff = [] + escape = 0 + for i in range(len(line)): + c = line[i] + if c == '\\': + if escape: + escape = 0 + buff.append('\\') + continue + else: + # this is to deal with '\' + # acting as a line continuation + # character + if i == len(line) - 1: + buff.append('\\') + break + else: + escape = 1 + continue + elif c == 'n': + if escape: + escape = 0 + buff.append('\n') + continue + elif c == 'r': + if escape: + escape = 0 + buff.append('\r') + continue + elif c == 't': + if escape: + escape = 0 + buff.append('\t') + continue + + buff.append(c) + + # make sure escape doesn't stay one + # all expected escape sequences either break + # or continue, so this should be safe + if escape: + escape = 0 + + return ''.join(buff) + + +class Properties(dict): + def __init__(self, defaults={}): + dict.__init__(self) + for n,v in list(defaults.items()): + self[n] = v + + def __getittem__(self,key): + try: + return dict.__getittem__(self,key) + except KeyError: + return None + + def read(self,filename): + """ + Reads properties from a file (java Property class + reads from an input stream -- see load()). + """ + f = None + try: + f = open(filename) + self.load(f) + finally: + if f: + f.close() + + def load(self, buff): + """ + Reads properties from a stream (StringIO, file, etc...) + """ + props = readprops(buff) + for n,v in list(props.items()): + self[n] = v + +def readprops(buff): + name,value = None,'' + props = {} + continued = 0 + + while 1: + line = buff.readline() + if not line: + break + line = line.strip() + + # empty line + if not line: + continue + + # comment + if line[0] in ('#','!'): + continue + + # find name + i,escaped = 0,0 + while i < len(line): + c = line[i] + + if c == '\\': + if escaped: + escaped = 0 + else: + escaped = 1 + i += 1 + continue + + elif c in (' ', '\t', ':', '=') and not escaped: + name = unescapestr(line[:i]) + break + + # make sure escaped doesn't stay on + if escaped: + escaped = 0 + + i += 1 + + # no delimiter was found, name is entire line, there is no value + if name is None: + name = unescapestr(line.lstrip()) + + # skip delimiter + while line[i:i + 1] in ('\t', ' ', ':', '='): + i += 1 + + value = unescapestr(line[i:].strip()) + while value[-1:] == '\\': + value = value[:-1] # remove \ + line = buff.readline() + if not line: + break + value += unescapestr(line.strip()) + + props[name] = value + + return props +#---end java.util.Properties copy---# + +# It's a simple command line tool, which can merge different XML fragments +# together. Such fragments must exist as files on disk, will be moved into +# one file together on disk. + +def run(sCmdLine): + aCfg = ConfigHelper(CFGFILE, sCmdLine) + if aCfg.getValueWithDefault(PROP_VERBOSE,None) == None: + sys.stdout=None + + printCopyright() + + # help requested? + if aCfg.isHelp(): + printHelp() + sys.exit(-1) + + #create new merge object and start operation + aMerger = Merger(aCfg) + aMerger.merge() + + sys.exit(0) + +def printOut(s): + if sys.stdout is None: + return + print(s) + +#prints out a copyright message on stdout. +def printCopyright(): + printOut("FCFGMerge") + printOut("Copyright: 2003 by Red Hat, Inc., based on FCFGMerge.java` by Sun") + printOut("All Rights Reserved.") + +# Prints out a help message on stdout. +def printHelp(): + printOut("____________________________________________________________") + printOut("usage: FCFGMerge cfg=" ) + printOut("parameters:" ) + printOut("\tcfg=" ) + printOut("\t\tmust point to a system file, which contains" ) + printOut("\t\tall necessary configuration data for the merge process.") + printOut("\tFurther cou can specify every parameter allowed in the" ) + printOut("\tconfig file as command line parameter too, to overwrite" ) + printOut("\tthe value from the file." ) + +# Return a list of tokens given a base string and a string of +# separators, optionally including the separators if asked for""" +def StringTokenizer(mstring, separators, isSepIncluded = 0): + token = '' + tokenList = [] + for c in mstring: + if c in separators: + if token != '': + tokenList.append(token) + token = '' + if isSepIncluded: + tokenList.append(c) + else: + token += c + if token: + tokenList.append(token) + return tokenList + +# Can be used to analyze command line parameters +# and merge it together with might existing config +# files. That provides the possibility to overwrite +# config values via command line parameter. + +class ConfigHelper: + def __init__(self, sPropFile, lCommandLineArgs): + self.m_bEmpty = 1 + # first load prop file, so its values can be overwritten + # by command line args later + # Do it only, if a valid file name was given. + # But in case this file name is wrong, throw an exception. + # So the outside code can react! + if sPropFile is not None and len(sPropFile) > 0: + self.props = Properties() + self.props.read(sPropFile) + + count = 0 + if lCommandLineArgs is not None: + count = len(lCommandLineArgs) + self.m_bEmpty = (count < 1) + + # printOut(lCommandLineArgs, "and len is", count) + for arg in range(count): + # is it a named-value argument? + # Note: we ignore double "=" signs! => search from left to right + pos = lCommandLineArgs[arg].find('=') + if pos != -1: + sArg = lCommandLineArgs[arg][0:pos] + sValue = lCommandLineArgs[arg][pos + 1:] + self.props[sArg] = sValue + continue + + # is it a boolean argument? + # Note: Because "--" and "-" will be interpreted as the same + # we search from right to left! + pos = lCommandLineArgs[arg].rfind('-') + if pos == -1: + pos = lCommandLineArgs[arg].rfind('/') + if pos != -1: + sArg = lCommandLineArgs[arg][pos + 1:] + self.props[sArg] = 1 + continue + + raise Exception("Invalid command line detected. The argument \"" + \ + lCommandLineArgs[arg] + "\" use an unsupported format.") + + def isHelp(self): + return ("help" in self.props) or ("?" in self.props) or ("?" in self.props) + + def getValue(self, sProp): + if sProp not in self.props: + raise Exception("The requested config value \"" + sProp + "\" "\ + "does not exists!"); + return self.props[sProp]; + + def getValueWithDefault(self, sProp, default): + if sProp not in self.props: + return default; + return self.props[sProp]; + + def getStringList(self, sProp, sDelimiter, bTrim, bDecode): + if sProp not in self.props: + raise Exception("The requested config value \"" + sProp + "\" does "\ + "not exists!"); + sValue = self.props[sProp] + + lValue = [] + lTokens = StringTokenizer(sValue, sDelimiter) + for sToken in lTokens: + if bTrim: + sToken = sToken.strip() + # remove "" + if ((bDecode) and (sToken.find("\"") == 0) and \ + (sToken.rfind("\"") == len(sToken) - 1)): + sToken = sToken[1, len(sToken) - 1] + lValue.append(sToken) + + return lValue + +def generateHeader(sVersion, sEncoding, sPath, sPackage, bLanguagePack): + sHeader = "\n" + + if bLanguagePack: + sHeader += "\n" + else: + sHeader += "\n" + return sHeader + +def generateFooter(): + return "\n" + +# Can merge different xml fragments together. + +class Merger: + def __init__(self, aCfg): + self.m_aCfg = aCfg + + self.m_aFragmentsDir = self.m_aCfg.getValue(PROP_FRAGMENTSDIR) + + sDelimiter = self.m_aCfg.getValue(PROP_DELIMITER) + bTrim = self.m_aCfg.getValue(PROP_TRIM) + bDecode = self.m_aCfg.getValue(PROP_DECODE) + + try: + aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_TCFG), None) + self.m_lTypes = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) + except: + self.m_lTypes = [] + + try: + aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_FCFG), None) + self.m_lFilters = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) + except: + self.m_lFilters = [] + + try: + aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_LCFG), None) + self.m_lLoaders = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) + except: + self.m_lLoaders = [] + + try: + aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_CCFG), None) + self.m_lHandlers = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) + except: + self.m_lHandlers = [] + + # Merges the xml sets returned by getFragments(...), adds an xml header + # and footer and writes the result to a file. + def merge(self): + sPackage = self.m_aCfg.getValue(PROP_PKG) + + printOut("create package \"" + sPackage + "\" ...") + printOut("generate package header ... ") + + sBuffer = generateHeader(\ + self.m_aCfg.getValue(PROP_XMLVERSION ),\ + self.m_aCfg.getValue(PROP_XMLENCODING),\ + self.m_aCfg.getValue(PROP_XMLPATH ),\ + self.m_aCfg.getValue(PROP_XMLPACKAGE ),\ + self.m_aCfg.getValueWithDefault(PROP_LANGUAGEPACK, False)) + + # counts all transferred fragments + # Can be used later to decide, if a generated package file + # contains "nothing"! + nItemCount = 0 + + for i in range(4): + sSetName = None + sSubDir = None + lFragments = None + + try: + if i == 0: # types + printOut("generate set for types ... ") + sSetName = self.m_aCfg.getValue(PROP_SETNAME_TYPES) + sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_TYPES) + lFragments = self.m_lTypes + elif i == 1: # filters + printOut("generate set for filter ... ") + sSetName = self.m_aCfg.getValue(PROP_SETNAME_FILTERS) + sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_FILTERS) + lFragments = self.m_lFilters + elif i == 2: # loaders + printOut("generate set for frame loader ... ") + sSetName = self.m_aCfg.getValue(PROP_SETNAME_LOADERS) + sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_LOADERS) + lFragments = self.m_lLoaders + elif i == 3: # handlers + printOut("generate set for content handler ... ") + sSetName = self.m_aCfg.getValue(PROP_SETNAME_HANDLERS) + sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_HANDLERS) + lFragments = self.m_lHandlers + except: + continue + + nItemCount = nItemCount + len(lFragments) + + sBuffer = sBuffer + self.getFragments(\ + os.path.join(self.m_aFragmentsDir, sSubDir), \ + sSetName, lFragments, 1) + + printOut("generate package footer ... ") + sBuffer = sBuffer + generateFooter() + + # Attention! + # If the package seem to be empty, it makes no sense to generate a + # corresponding xml file. We should suppress writing of this file on + # disk completely ... + if nItemCount < 1: + printOut("Package is empty and will not result into a xml file on "\ + "disk!? Please check configuration file.") + return + printOut("package contains " + str(nItemCount) + " items") + + aPackage = codecs.open(sPackage, 'w', "utf-8") + printOut("write temp package \"" + sPackage) + aPackage.write(sBuffer) + aPackage.close() + + # Reads the fragment files with the file names lFragments in directory aDir, + # formats them and returns a string that contains the merged fragments. + def getFragments(self, aDir, sSetName, lFragments, nPrettyTabs): + sBuffer = '' + sExtXcu = self.m_aCfg.getValue(PROP_EXTENSION_XCU); + sShareSubdirName = self.m_aCfg.getValue(PROP_SHARE_SUBDIR_NAME) + if len(sShareSubdirName) < 1: + raise Exception("no share subdir set") + + if len(lFragments) < 1: + return sBuffer + + for tabs in range(nPrettyTabs): + sBuffer = sBuffer + "\t" + sBuffer = sBuffer + "\n" + nPrettyTabs = nPrettyTabs + 1 + + for sFragment in lFragments: + sFragPath = os.path.join(aDir, sFragment + "." + sExtXcu) + try: + aFragmentFile = codecs.open(sFragPath, "r", "utf-8") + except: + # handle simple files only and check for existence! + raise Exception("fragment \"" + sFragPath + "\" does not exists.") + printOut("merge fragment \"" + sFragPath + "\" ...") + data = aFragmentFile.read() + aFragmentFile.close() + data = data.replace("$(share_subdir_name)", sShareSubdirName) + sBuffer = sBuffer + data + sBuffer = sBuffer + "\n" + + nPrettyTabs = nPrettyTabs - 1 + for tabs in range(nPrettyTabs): + sBuffer = sBuffer + "\t" + sBuffer = sBuffer + "\n" + return sBuffer + +run(sys.argv) + diff --git a/filter/source/docbook/DocBookTemplate.stw b/filter/source/docbook/DocBookTemplate.stw new file mode 100644 index 000000000..ebc95f9f6 Binary files /dev/null and b/filter/source/docbook/DocBookTemplate.stw differ diff --git a/filter/source/docbook/docbooktosoffheadings.xsl b/filter/source/docbook/docbooktosoffheadings.xsl new file mode 100644 index 000000000..08d183863 --- /dev/null +++ b/filter/source/docbook/docbooktosoffheadings.xsl @@ -0,0 +1,1416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Section SubTitle + + + + + + + + + + + + + + + + + + + + + + + + + + + Appendix Title + + + + + + + + + + + ArticleInfo + ArticleInfo + + + Document Title + + + + + Document SubTitle + + + + + + + + + + + + Appendix + Appendix + + + + + + + + + + + + + + + string + + + articleinfo.subtitle + + + + + + + string + + + articleinfo.subtitle + + + + + + + + + + + string + + + articleinfo.edition + + + + + + + string + + + articleinfo.edition + + + + + + + + + + + string + + + articleinfo.releaseinfo_ + + + + + + + + string + + + articleinfo.releaseinfo_ + + + + + + + + + + + + + string + + + + + articleinfo.author_ + + .firstname_ + + + + + + + + + string + + + + articleinfo.author_ + + .firstname_ + + + + + + + + + + + + + + + string + + + + + articleinfo.copyright_ + + .year_ + + + + + + + + + string + + + + articleinfo.copyright_ + + .year_ + + + + + + + + + + + + + + + + + string + + + + + articleinfo.copyright_ + + .holder_ + + + + + + + + + string + + + + articleinfo.copyright_ + + .holder_ + + + + + + + + + + + + + + + + + + + + string + + + articleinfo.author_ + + .affiliation_ + + .address_ + + + + + + + + string + + + articleinfo.author_ + + .affiliation_ + + .address_ + + + + + + + + + + + + + string + + + + articleinfo.author_ + + .affiliation_ + + .orgname_ + + + + + + + + + string + + + + articleinfo.author_ + + .affiliation_ + + .orgname_ + + + + + + + + + + + + + + + string + + + + articleinfo.author_ + + .surname_ + + + + + + + + string + + + articleinfo.author_ + + .surname_ + + + + + + + + + + + + + + + + + + + + Footnote + + + VarList Item + + + + Table Contents + + + Table Heading + + + + + Table Contents + + + Table Heading + + + + Text body + + + + + + + + + + + + + + + + + + + + + 1 + abstract + + + + + + + + 1 + appendix + + + + + + + 1 + Heading 1 + + + + + + + + 2 + Heading 2 + + + + + + + + 3 + Heading 3 + + + + + + + + 4 + Heading 4 + + + + + + + + 5 + + + + + + + + + + + + Table1 + + + + + + + + + + + + + + + Table1 + + + + + + + + Table + + + + + + + + Table1.A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Table1.A1 + + + Table1.A2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Table Heading + + + Table Contents + + + + + + + + + + + + + + + + + + + + + + + + + + L1 + + + + + + + + Var List + false + + + + + + + Ordered List + false + + + + + + + + + VarList Term + + + + + + + + + + + + + + + + + + + + + GuiMenuItem + + + + + + + GuiButton + + + + + + + GuiSubMenu + + + + + + + Emphasis + + + + + + + + GuiMenu + + + + + + + GuiSubMenu + + + + + + + + GuiLabel + + + + + + + GuiButton + + + + + + + KeyCap + + + + + + + + KeySym + + + + + + + + KeyCombo + + + + + + + Command + + + + + + + Application + + + + + + + FileName + + + + + + + SystemItem + + + + + + + ComputerOutput + + + + + + + fr1 + + + + + + + + + + 1cm + + + 1cm + + + embed + + + onLoad + + + <All formats> + + + + + + + + + + + + + + + + + Highlight + + + + + + + + simple + + + + + + + + + + + + + simple + + + # + + %7Cregion + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fr1 + + + + + + + + + + 1cm + + + 1cm + + + embed + + + onLoad + + + <All formats> + + + + + + + fr1 + + + + + + + + + + 1cm + + + 1cm + + + embed + + + onLoad + + + <All formats> + + + + + + + + + + + Mediaobject + + + + + + + SuperScript + + + + + + + SubScript + + + + + + + + + + + + + + Example + + + + \ No newline at end of file diff --git a/filter/source/docbook/sofftodocbookheadings.xsl b/filter/source/docbook/sofftodocbookheadings.xsl new file mode 100644 index 000000000..784c050a2 --- /dev/null +++ b/filter/source/docbook/sofftodocbookheadings.xsl @@ -0,0 +1,1152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 2 + 3 + 4 + + + + + + + + + + + + + + + + + + + + + + <xsl:apply-templates/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="text:p[@text:style-name='Document Title']"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="following-sibling::text:p[@text:style-name='Table']"/> + + +
+
+ + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + c + + + + + + + + + + + + + + + + + + + + + + + + + + + <tbody> + + + + + + </tbody> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:apply-templates/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + embedded: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/filter/source/graphic/GraphicExportFilter.cxx b/filter/source/graphic/GraphicExportFilter.cxx new file mode 100644 index 000000000..ee5843066 --- /dev/null +++ b/filter/source/graphic/GraphicExportFilter.cxx @@ -0,0 +1,235 @@ +/* -*- 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 "GraphicExportFilter.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace css; + +GraphicExportFilter::GraphicExportFilter( uno::Reference< uno::XComponentContext > xContext ) + : mxContext(std::move(xContext)) + , mnTargetWidth(0) + , mnTargetHeight(0) + , mbSelectionOnly(false) +{} + +GraphicExportFilter::~GraphicExportFilter() +{} + +// XServiceInfo +sal_Bool GraphicExportFilter::supportsService(const OUString& sServiceName) +{ + return cppu::supportsService(this, sServiceName); +} +OUString GraphicExportFilter::getImplementationName() +{ + return "com.sun.star.comp.GraphicExportFilter"; +} +css::uno::Sequence< OUString > GraphicExportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ExportFilter" }; +} + +void GraphicExportFilter::gatherProperties( const uno::Sequence< beans::PropertyValue > & rProperties ) +{ + OUString aInternalFilterName; + + for ( const beans::PropertyValue& rProperty : rProperties ) + { + if ( rProperty.Name == "FilterName" ) + { + rProperty.Value >>= aInternalFilterName; + const sal_Int32 nLen = aInternalFilterName.getLength(); + aInternalFilterName = aInternalFilterName.replaceFirst("calc_", ""); + if (aInternalFilterName.getLength() == nLen) + aInternalFilterName = aInternalFilterName.replaceFirst("writer_", ""); + if (aInternalFilterName.getLength() == nLen) + aInternalFilterName = aInternalFilterName.replaceFirst("web_", ""); + if (aInternalFilterName.getLength() == nLen) + aInternalFilterName = aInternalFilterName.replaceFirst("draw_", ""); + if (aInternalFilterName.getLength() == nLen) + aInternalFilterName = aInternalFilterName.replaceFirst("impress_", ""); + } + else if ( rProperty.Name == "FilterData" ) + { + rProperty.Value >>= maFilterDataSequence; + } + else if ( rProperty.Name == "OutputStream" ) + { + rProperty.Value >>= mxOutputStream; + } + else if ( rProperty.Name == "SelectionOnly" ) + { + rProperty.Value >>= mbSelectionOnly; + } + } + + for ( const beans::PropertyValue& rProp : std::as_const(maFilterDataSequence) ) + { + if ( rProp.Name == "PixelWidth" ) + { + rProp.Value >>= mnTargetWidth; + } + else if ( rProp.Name == "PixelHeight" ) + { + rProp.Value >>= mnTargetHeight; + } + } + + if ( aInternalFilterName.isEmpty() ) + return; + + GraphicFilter aGraphicFilter( true ); + + sal_uInt16 nFilterCount = aGraphicFilter.GetExportFormatCount(); + sal_uInt16 nFormat; + + for ( nFormat = 0; nFormat < nFilterCount; nFormat++ ) + { + if ( aGraphicFilter.GetExportInternalFilterName( nFormat ) == aInternalFilterName ) + break; + } + if ( nFormat < nFilterCount ) + { + maFilterExtension = aGraphicFilter.GetExportFormatShortName( nFormat ); + } +} + +sal_Bool SAL_CALL GraphicExportFilter::filter( const uno::Sequence< beans::PropertyValue > & rDescriptor ) +{ + gatherProperties(rDescriptor); + + if (mbSelectionOnly && mxDocument.is()) + { + uno::Reference< frame::XModel > xModel( mxDocument, uno::UNO_QUERY); + if (xModel.is()) + { + uno::Reference< frame::XController > xController( xModel->getCurrentController()); + if (xController.is()) + { + uno::Reference< drawing::XShapes > xShapes; + uno::Reference< drawing::XShape > xShape; + if (DocumentToGraphicRenderer::isShapeSelected( xShapes, xShape, xController)) + return filterExportShape( rDescriptor, xShapes, xShape); + } + } + } + + return filterRenderDocument(); +} + +bool GraphicExportFilter::filterRenderDocument() const +{ + DocumentToGraphicRenderer aRenderer( mxDocument, mbSelectionOnly ); + sal_Int32 nCurrentPage = aRenderer.getCurrentPage(); + Size aDocumentSizePixel = aRenderer.getDocumentSizeInPixels(nCurrentPage); + + Size aTargetSizePixel(mnTargetWidth, mnTargetHeight); + + if (mnTargetWidth == 0 || mnTargetHeight == 0) + aTargetSizePixel = aDocumentSizePixel; + + Graphic aGraphic = aRenderer.renderToGraphic(nCurrentPage, aDocumentSizePixel, aTargetSizePixel, COL_WHITE, /*bExtOutDevData=*/false); + + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + + sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( maFilterExtension ); + + SvMemoryStream aMemStream; + const GraphicConversionParameters aParameters(aTargetSizePixel, true, true); + + const ErrCode nResult = rFilter.ExportGraphic( aGraphic.GetBitmapEx(aParameters), u"", aMemStream, + nFilterFormat, &maFilterDataSequence ); + + if ( nResult == ERRCODE_NONE ) + { + SvOutputStream aOutputStream( mxOutputStream ); + aMemStream.Seek(0); + aOutputStream.WriteStream( aMemStream ); + + return true; + } + + return false; +} + +bool GraphicExportFilter::filterExportShape( + const css::uno::Sequence< css::beans::PropertyValue > & rDescriptor, + const css::uno::Reference< css::drawing::XShapes > & rxShapes, + const css::uno::Reference< css::drawing::XShape > & rxShape ) const +{ + uno::Reference< lang::XComponent > xSourceDoc; + if (rxShapes.is()) + xSourceDoc.set( rxShapes, uno::UNO_QUERY_THROW ); + else if (rxShape.is()) + xSourceDoc.set( rxShape, uno::UNO_QUERY_THROW ); + if (!xSourceDoc.is()) + return false; + + uno::Reference< drawing::XGraphicExportFilter > xGraphicExporter = + drawing::GraphicExportFilter::create( mxContext ); + if (!xGraphicExporter.is()) + return false; + + // Need to replace the internal filter name with the short name + // (extension). + uno::Sequence< beans::PropertyValue > aDescriptor( rDescriptor); + for (sal_Int32 i = 0; i < aDescriptor.getLength(); ++i) + { + if (aDescriptor[i].Name == "FilterName") + { + aDescriptor.getArray()[i].Value <<= maFilterExtension; + break; + } + } + + xGraphicExporter->setSourceDocument( xSourceDoc ); + return xGraphicExporter->filter( aDescriptor ); +} + +void SAL_CALL GraphicExportFilter::cancel( ) +{ +} + +void SAL_CALL GraphicExportFilter::setSourceDocument( const uno::Reference< lang::XComponent > & xDocument ) +{ + mxDocument = xDocument; +} + +void SAL_CALL GraphicExportFilter::initialize( const uno::Sequence< uno::Any > & ) +{ +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_GraphicExportFilter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new GraphicExportFilter(context)); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphic/GraphicExportFilter.hxx b/filter/source/graphic/GraphicExportFilter.hxx new file mode 100644 index 000000000..c78b25d70 --- /dev/null +++ b/filter/source/graphic/GraphicExportFilter.hxx @@ -0,0 +1,79 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star { + namespace drawing { + class XShapes; + class XShape; + } +} + +class GraphicExportFilter : + public cppu::WeakImplHelper < css::document::XFilter, css::document::XExporter, css::lang::XInitialization, css::lang::XServiceInfo > +{ + css::uno::Reference< css::uno::XComponentContext > mxContext; + css::uno::Reference< css::lang::XComponent > mxDocument; + css::uno::Reference< css::io::XOutputStream > mxOutputStream; + + css::uno::Sequence< css::beans::PropertyValue > maFilterDataSequence; + + OUString maFilterExtension; + sal_Int32 mnTargetWidth; + sal_Int32 mnTargetHeight; + bool mbSelectionOnly; + + void gatherProperties( const css::uno::Sequence< css::beans::PropertyValue > & rDescriptor ); + bool filterRenderDocument() const; + bool filterExportShape( + const css::uno::Sequence< css::beans::PropertyValue > & rDescriptor, + const css::uno::Reference< css::drawing::XShapes > & rxShapes, + const css::uno::Reference< css::drawing::XShape > & rxShape ) const; + +public: + explicit GraphicExportFilter( css::uno::Reference< css::uno::XComponentContext > xContext ); + virtual ~GraphicExportFilter() override; + + // XServiceInfo + virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override; + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XFilter + virtual sal_Bool SAL_CALL filter( const css::uno::Sequence< css::beans::PropertyValue > & rDescriptor ) override; + virtual void SAL_CALL cancel( ) override; + + // XExporter + virtual void SAL_CALL setSourceDocument( const css::uno::Reference< css::lang::XComponent > & xDocument ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any > & rArguments ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphic/graphicfilter.component b/filter/source/graphic/graphicfilter.component new file mode 100644 index 000000000..1040d1440 --- /dev/null +++ b/filter/source/graphic/graphicfilter.component @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/filter/source/graphicfilter/icgm/actimpr.cxx b/filter/source/graphicfilter/icgm/actimpr.cxx new file mode 100644 index 000000000..c77b55184 --- /dev/null +++ b/filter/source/graphicfilter/icgm/actimpr.cxx @@ -0,0 +1,1041 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "bitmap.hxx" +#include "elements.hxx" +#include "outact.hxx" + +#define MAX_PAGES_FOR_FUZZING 2048 + +using namespace ::com::sun::star; + +CGMImpressOutAct::CGMImpressOutAct(CGM& rCGM, const uno::Reference< frame::XModel > & rModel) + : mnCurrentPage(0) + , mnGroupActCount(0) + , mnGroupLevel(0) + , maGroupLevel() + , mpCGM(&rCGM) + , nFinalTextCount(0) +{ + if ( !mpCGM->mbStatus ) + return; + + bool bStatRet = false; + + uno::Reference< drawing::XDrawPagesSupplier > aDrawPageSup( rModel, uno::UNO_QUERY ); + if( aDrawPageSup.is() ) + { + maXDrawPages = aDrawPageSup->getDrawPages(); + if ( maXDrawPages.is() ) + { + maXMultiServiceFactory.set( rModel, uno::UNO_QUERY); + if( maXMultiServiceFactory.is() ) + { + maXDrawPage = *o3tl::doAccess>(maXDrawPages->getByIndex( 0 )); + if ( ImplInitPage() ) + bStatRet = true; + } + } + } + mpCGM->mbStatus = bStatRet; +} + +CGMImpressOutAct::~CGMImpressOutAct() +{ + for (auto &a : maLockedNewXShapes) + a->removeActionLock(); +} + +bool CGMImpressOutAct::ImplInitPage() +{ + bool bStatRet = false; + if( maXDrawPage.is() ) + { + maXShapes = maXDrawPage; + if ( maXShapes.is() ) + { + bStatRet = true; + } + } + return bStatRet; +} + +bool CGMImpressOutAct::ImplCreateShape( const OUString& rType ) +{ + if (utl::ConfigManager::IsFuzzing()) + return false; + uno::Reference< uno::XInterface > xNewShape( maXMultiServiceFactory->createInstance( rType ) ); + maXShape.set( xNewShape, uno::UNO_QUERY ); + maXPropSet.set( xNewShape, uno::UNO_QUERY ); + if ( maXShape.is() && maXPropSet.is() ) + { + maXShapes->add( maXShape ); + uno::Reference xLockable(maXShape, uno::UNO_QUERY); + if (xLockable) + { + xLockable->addActionLock(); + maLockedNewXShapes.push_back(xLockable); + } + return true; + } + return false; +} + +void CGMImpressOutAct::ImplSetOrientation( FloatPoint const & rRefPoint, double rOrientation ) +{ + maXPropSet->setPropertyValue( "RotationPointX", uno::Any(static_cast(rRefPoint.X)) ); + maXPropSet->setPropertyValue( "RotationPointY", uno::Any(static_cast(rRefPoint.Y)) ); + maXPropSet->setPropertyValue( "RotateAngle", uno::Any(static_cast( rOrientation * 100.0 )) ); +} + + +void CGMImpressOutAct::ImplSetLineBundle() +{ + drawing::LineStyle eLS; + + sal_uInt32 nLineColor; + LineType eLineType; + double fLineWidth; + + if ( mpCGM->pElement->nAspectSourceFlags & ASF_LINECOLOR ) + nLineColor = mpCGM->pElement->pLineBundle->GetColor(); + else + nLineColor = mpCGM->pElement->aLineBundle.GetColor(); + if ( mpCGM->pElement->nAspectSourceFlags & ASF_LINETYPE ) + eLineType = mpCGM->pElement->pLineBundle->eLineType; + else + eLineType = mpCGM->pElement->aLineBundle.eLineType; + if ( mpCGM->pElement->nAspectSourceFlags & ASF_LINEWIDTH ) + fLineWidth = mpCGM->pElement->pLineBundle->nLineWidth; + else + fLineWidth = mpCGM->pElement->aLineBundle.nLineWidth; + + maXPropSet->setPropertyValue( "LineColor", uno::Any(static_cast(nLineColor)) ); + + maXPropSet->setPropertyValue( "LineWidth", uno::Any(static_cast(fLineWidth)) ); + + switch( eLineType ) + { + case LT_NONE : + eLS = drawing::LineStyle_NONE; + break; + case LT_DASH : + case LT_DOT : + case LT_DASHDOT : + case LT_DOTDOTSPACE : + case LT_LONGDASH : + case LT_DASHDASHDOT : + eLS = drawing::LineStyle_DASH; + break; + case LT_SOLID : + default: + eLS = drawing::LineStyle_SOLID; + break; + } + maXPropSet->setPropertyValue( "LineStyle", uno::Any(eLS) ); + if ( eLS == drawing::LineStyle_DASH ) + { + drawing::LineDash aLineDash( drawing::DashStyle_RECTRELATIVE, 1, 50, 3, 33, 100 ); + maXPropSet->setPropertyValue( "LineDash", uno::Any(aLineDash) ); + } +} + +void CGMImpressOutAct::ImplSetFillBundle() +{ + drawing::LineStyle eLS; + drawing::FillStyle eFS; + + sal_uInt32 nEdgeColor = 0; + EdgeType eEdgeType; + double fEdgeWidth = 0; + + sal_uInt32 nFillColor; + FillInteriorStyle eFillStyle; + sal_uInt32 nHatchIndex; + + if ( mpCGM->pElement->eEdgeVisibility == EV_ON ) + { + if ( mpCGM->pElement->nAspectSourceFlags & ASF_EDGETYPE ) + eEdgeType = mpCGM->pElement->pEdgeBundle->eEdgeType; + else + eEdgeType = mpCGM->pElement->aEdgeBundle.eEdgeType; + if ( mpCGM->pElement->nAspectSourceFlags & ASF_EDGEWIDTH ) + fEdgeWidth = mpCGM->pElement->pEdgeBundle->nEdgeWidth; + else + fEdgeWidth = mpCGM->pElement->aEdgeBundle.nEdgeWidth; + if ( mpCGM->pElement->nAspectSourceFlags & ASF_EDGECOLOR ) + nEdgeColor = mpCGM->pElement->pEdgeBundle->GetColor(); + else + nEdgeColor = mpCGM->pElement->aEdgeBundle.GetColor(); + } + else + eEdgeType = ET_NONE; + + if ( mpCGM->pElement->nAspectSourceFlags & ASF_FILLINTERIORSTYLE ) + eFillStyle = mpCGM->pElement->pFillBundle->eFillInteriorStyle; + else + eFillStyle = mpCGM->pElement->aFillBundle.eFillInteriorStyle; + if ( mpCGM->pElement->nAspectSourceFlags & ASF_FILLCOLOR ) + nFillColor = mpCGM->pElement->pFillBundle->GetColor(); + else + nFillColor = mpCGM->pElement->aFillBundle.GetColor(); + if ( mpCGM->pElement->nAspectSourceFlags & ASF_HATCHINDEX ) + nHatchIndex = static_cast(mpCGM->pElement->pFillBundle->nFillHatchIndex); + else + nHatchIndex = static_cast(mpCGM->pElement->aFillBundle.nFillHatchIndex); + + maXPropSet->setPropertyValue( "FillColor", uno::Any(static_cast(nFillColor)) ); + + switch ( eFillStyle ) + { + case FIS_HATCH : + { + if ( nHatchIndex == 0 ) + eFS = drawing::FillStyle_NONE; + else + eFS = drawing::FillStyle_HATCH; + } + break; + case FIS_PATTERN : + case FIS_SOLID : + { + eFS = drawing::FillStyle_SOLID; + } + break; + + case FIS_GEOPATTERN : + { + if ( mpCGM->pElement->eTransparency == T_ON ) + nFillColor = mpCGM->pElement->nAuxiliaryColor; + eFS = drawing::FillStyle_NONE; + } + break; + + case FIS_INTERPOLATED : + case FIS_GRADIENT : + { + eFS = drawing::FillStyle_GRADIENT; + } + break; + + case FIS_HOLLOW : + case FIS_EMPTY : + default: + { + eFS = drawing::FillStyle_NONE; + } + } + + if ( mpCGM->mnAct4PostReset & ACT4_GRADIENT_ACTION ) + eFS = drawing::FillStyle_GRADIENT; + + if ( eFS == drawing::FillStyle_GRADIENT ) + { + maXPropSet->setPropertyValue( "FillGradient", uno::Any(*mpGradient) ); + } + maXPropSet->setPropertyValue( "FillStyle", uno::Any(eFS) ); + + eLS = drawing::LineStyle_NONE; + if ( eFillStyle == FIS_HOLLOW ) + { + eLS = drawing::LineStyle_SOLID; + maXPropSet->setPropertyValue( "LineColor", uno::Any(static_cast(nFillColor)) ); + maXPropSet->setPropertyValue( "LineWidth", uno::Any(sal_Int32(0)) ); + } + else if ( eEdgeType != ET_NONE ) + { + maXPropSet->setPropertyValue( "LineColor", uno::Any(static_cast(nEdgeColor)) ); + + maXPropSet->setPropertyValue( "LineWidth", uno::Any(static_cast(fEdgeWidth)) ); + + switch( eEdgeType ) + { + case ET_DASH : + case ET_DOT : + case ET_DASHDOT : + case ET_DASHDOTDOT : + case ET_DOTDOTSPACE : + case ET_LONGDASH : + case ET_DASHDASHDOT : + default: // case ET_SOLID : + { + eLS = drawing::LineStyle_SOLID; + } + break; + } + } + + maXPropSet->setPropertyValue( "LineStyle", uno::Any(eLS) ); + + if ( eFS != drawing::FillStyle_HATCH ) + return; + + drawing::Hatch aHatch; + + aHatch.Color = nFillColor; + if ( mpCGM->pElement->maHatchMap.find( nHatchIndex ) != mpCGM->pElement->maHatchMap.end() ) + { + HatchEntry& rHatchEntry = mpCGM->pElement->maHatchMap[ nHatchIndex ]; + switch ( rHatchEntry.HatchStyle ) + { + case 0 : aHatch.Style = drawing::HatchStyle_SINGLE; break; + case 1 : aHatch.Style = drawing::HatchStyle_DOUBLE; break; + case 2 : aHatch.Style = drawing::HatchStyle_TRIPLE; break; + } + aHatch.Distance = rHatchEntry.HatchDistance; + aHatch.Angle = rHatchEntry.HatchAngle; + } + else + { + aHatch.Style = drawing::HatchStyle_TRIPLE; + aHatch.Distance = 10 * ( nHatchIndex & 0x1f ) | 100; + aHatch.Angle = 15 * ( ( nHatchIndex & 0x1f ) - 5 ); + } + maXPropSet->setPropertyValue( "FillHatch", uno::Any(aHatch) ); +} + +void CGMImpressOutAct::ImplSetTextBundle( const uno::Reference< beans::XPropertySet > & rProperty ) +{ + sal_uInt32 nTextFontIndex; + sal_uInt32 nTextColor; + + if ( mpCGM->pElement->nAspectSourceFlags & ASF_TEXTFONTINDEX ) + nTextFontIndex = mpCGM->pElement->pTextBundle->nTextFontIndex; + else + nTextFontIndex = mpCGM->pElement->aTextBundle.nTextFontIndex; + if ( mpCGM->pElement->nAspectSourceFlags & ASF_TEXTCOLOR ) + nTextColor = mpCGM->pElement->pTextBundle->GetColor(); + else + nTextColor = mpCGM->pElement->aTextBundle.GetColor(); + + rProperty->setPropertyValue( "CharColor", uno::Any(static_cast(nTextColor)) ); + + sal_uInt32 nFontType = 0; + awt::FontDescriptor aFontDescriptor; + FontEntry* pFontEntry = mpCGM->pElement->aFontList.GetFontEntry( nTextFontIndex ); + if ( pFontEntry ) + { + nFontType = pFontEntry->nFontType; + aFontDescriptor.Name = OUString(reinterpret_cast(pFontEntry->aFontName.data()), + pFontEntry->aFontName.size(), + RTL_TEXTENCODING_ASCII_US); + } + aFontDescriptor.Height = sal_Int16( mpCGM->pElement->nCharacterHeight * 1.50 ); + if ( nFontType & 1 ) + aFontDescriptor.Slant = awt::FontSlant_ITALIC; + if ( nFontType & 2 ) + aFontDescriptor.Weight = awt::FontWeight::BOLD; + else + aFontDescriptor.Weight = awt::FontWeight::NORMAL; + + if ( mpCGM->pElement->eUnderlineMode != UM_OFF ) + { + aFontDescriptor.Underline = awt::FontUnderline::SINGLE; + } + rProperty->setPropertyValue( "FontDescriptor", uno::Any(aFontDescriptor) ); +} + +void CGMImpressOutAct::InsertPage() +{ + if ( mnCurrentPage ) // one side is always existing, therefore the first side will be left out + { + uno::Reference< drawing::XDrawPage > xPage = maXDrawPages->insertNewByIndex( 0xffff ); + maXDrawPage = xPage; + if ( !ImplInitPage() ) + mpCGM->mbStatus = false; + if (mnCurrentPage > MAX_PAGES_FOR_FUZZING && utl::ConfigManager::IsFuzzing()) + { + // ofz#21753 that's enough pages for fuzzing, we're not doing anything productive now + mpCGM->mbStatus = false; + } + } + mnCurrentPage++; +} + +void CGMImpressOutAct::BeginGroup() +{ + if ( mnGroupLevel < CGM_OUTACT_MAX_GROUP_LEVEL ) + { + maGroupLevel[mnGroupLevel] = maXShapes->getCount(); + } + ++mnGroupLevel; + mnGroupActCount = mpCGM->mnActCount; +} + +void CGMImpressOutAct::EndGroup() +{ + if (!mnGroupLevel) + return; + --mnGroupLevel; + if ( mnGroupLevel >= CGM_OUTACT_MAX_GROUP_LEVEL ) + return; + + sal_uInt32 nFirstIndex = maGroupLevel[mnGroupLevel]; + if ( nFirstIndex == 0xffffffff ) + nFirstIndex = 0; + sal_uInt32 nCurrentCount = maXShapes->getCount(); + if ( ( nCurrentCount - nFirstIndex ) <= 1 ) + return; + + uno::Reference< drawing::XShapeGrouper > aXShapeGrouper; + aXShapeGrouper.set( maXDrawPage, uno::UNO_QUERY ); + if( !aXShapeGrouper.is() ) + return; + + uno::Reference< drawing::XShapes > aXShapes = drawing::ShapeCollection::create(comphelper::getProcessComponentContext()); + for ( sal_uInt32 i = nFirstIndex; i < nCurrentCount; i++ ) + { + uno::Reference< drawing::XShape > aXShape = *o3tl::doAccess>(maXShapes->getByIndex( i )); + if (aXShape.is() ) + { + aXShapes->add( aXShape ); + } + } + aXShapeGrouper->group( aXShapes ); +} + +void CGMImpressOutAct::EndGrouping() +{ + while ( mnGroupLevel ) + { + EndGroup(); + } +} + +void CGMImpressOutAct::DrawRectangle( FloatRect const & rFloatRect ) +{ + if (mnGroupActCount == (mpCGM->mnActCount - 1)) // POWERPOINT HACK !!! + return; + if (useless(rFloatRect.Left)) + { + SAL_WARN("filter.icgm", "bad left: " << rFloatRect.Left); + return; + } + if (useless(rFloatRect.Top)) + { + SAL_WARN("filter.icgm", "bad top: " << rFloatRect.Top); + return; + } + double fWidth = rFloatRect.Right - rFloatRect.Left; + if (useless(fWidth)) + { + SAL_WARN("filter.icgm", "bad width: " << fWidth); + return; + } + double fHeight = rFloatRect.Bottom - rFloatRect.Top; + if (useless(fHeight)) + { + SAL_WARN("filter.icgm", "bad height: " << fHeight); + return; + } + if (!ImplCreateShape( "com.sun.star.drawing.RectangleShape")) + return; + maXShape->setSize(awt::Size(fWidth, fHeight)); + maXShape->setPosition(awt::Point(rFloatRect.Left, rFloatRect.Top)); + ImplSetFillBundle(); +} + +void CGMImpressOutAct::DrawEllipse( FloatPoint const & rCenter, FloatPoint const & rSize, double& rOrientation ) +{ + if ( !ImplCreateShape( "com.sun.star.drawing.EllipseShape" ) ) + return; + + drawing::CircleKind eCircleKind = drawing::CircleKind_FULL; + uno::Any aAny( &eCircleKind, ::cppu::UnoType::get() ); + maXPropSet->setPropertyValue( "CircleKind", aAny ); + + tools::Long nXSize = static_cast( rSize.X * 2.0 ); // strange behaviour with an awt::Size of 0 + tools::Long nYSize = static_cast( rSize.Y * 2.0 ); + if ( nXSize < 1 ) + nXSize = 1; + if ( nYSize < 1 ) + nYSize = 1; + maXShape->setSize( awt::Size( nXSize, nYSize ) ); + maXShape->setPosition( awt::Point( static_cast( rCenter.X - rSize.X ), static_cast( rCenter.Y - rSize.Y ) ) ); + + if ( rOrientation != 0 ) + { + ImplSetOrientation( rCenter, rOrientation ); + } + ImplSetFillBundle(); +} + +void CGMImpressOutAct::DrawEllipticalArc( FloatPoint const & rCenter, FloatPoint const & rSize, double& rOrientation, + sal_uInt32 nType, double& fStartAngle, double& fEndAngle ) +{ + if ( !ImplCreateShape( "com.sun.star.drawing.EllipseShape" ) ) + return; + + uno::Any aAny; + drawing::CircleKind eCircleKind; + + + tools::Long nXSize = static_cast( rSize.X * 2.0 ); // strange behaviour with an awt::Size of 0 + tools::Long nYSize = static_cast( rSize.Y * 2.0 ); + if ( nXSize < 1 ) + nXSize = 1; + if ( nYSize < 1 ) + nYSize = 1; + + maXShape->setSize( awt::Size ( nXSize, nYSize ) ); + + if ( rOrientation != 0 ) + { + fStartAngle = NormAngle360(fStartAngle + rOrientation); + fEndAngle = NormAngle360(fEndAngle + rOrientation); + } + switch( nType ) + { + case 0 : eCircleKind = drawing::CircleKind_SECTION; break; + case 1 : eCircleKind = drawing::CircleKind_CUT; break; + case 2 : eCircleKind = drawing::CircleKind_ARC; break; + default : eCircleKind = drawing::CircleKind_FULL; break; + } + if ( static_cast(fStartAngle) == static_cast(fEndAngle) ) + { + eCircleKind = drawing::CircleKind_FULL; + maXPropSet->setPropertyValue( "CircleKind", uno::Any(eCircleKind) ); + } + else + { + maXPropSet->setPropertyValue( "CircleKind", uno::Any(eCircleKind) ); + maXPropSet->setPropertyValue( "CircleStartAngle", uno::Any(static_cast( fStartAngle * 100 )) ); + maXPropSet->setPropertyValue( "CircleEndAngle", uno::Any(static_cast( fEndAngle * 100 )) ); + } + maXShape->setPosition( awt::Point( static_cast( rCenter.X - rSize.X ), static_cast( rCenter.Y - rSize.Y ) ) ); + if ( rOrientation != 0 ) + { + ImplSetOrientation( rCenter, rOrientation ); + } + if ( eCircleKind == drawing::CircleKind_ARC ) + { + ImplSetLineBundle(); + } + else + { + ImplSetFillBundle(); + if ( nType == 2 ) + { + ImplSetLineBundle(); + aAny <<= drawing::FillStyle_NONE; + maXPropSet->setPropertyValue( "FillStyle", aAny ); + } + } +} + +void CGMImpressOutAct::DrawBitmap( CGMBitmapDescriptor* pBmpDesc ) +{ + if ( !pBmpDesc->mbStatus || pBmpDesc->mxBitmap.IsEmpty() ) + return; + + FloatPoint aOrigin = pBmpDesc->mnOrigin; + double fdx = pBmpDesc->mndx; + double fdy = pBmpDesc->mndy; + + BmpMirrorFlags nMirr = BmpMirrorFlags::NONE; + if ( pBmpDesc->mbVMirror ) + nMirr |= BmpMirrorFlags::Vertical; + if ( nMirr != BmpMirrorFlags::NONE ) + pBmpDesc->mxBitmap.Mirror( nMirr ); + + mpCGM->ImplMapPoint( aOrigin ); + mpCGM->ImplMapX( fdx ); + mpCGM->ImplMapY( fdy ); + + if ( !ImplCreateShape( "com.sun.star.drawing.GraphicObjectShape" ) ) + return; + + maXShape->setSize( awt::Size( static_cast(fdx), static_cast(fdy) ) ); + maXShape->setPosition( awt::Point( static_cast(aOrigin.X), static_cast(aOrigin.Y) ) ); + + if ( pBmpDesc->mnOrientation != 0 ) + { + ImplSetOrientation( aOrigin, pBmpDesc->mnOrientation ); + } + + uno::Reference< awt::XBitmap > xBitmap( VCLUnoHelper::CreateBitmap( pBmpDesc->mxBitmap ) ); + maXPropSet->setPropertyValue( "GraphicObjectFillBitmap", uno::Any(xBitmap) ); +} + +void CGMImpressOutAct::DrawPolygon( tools::Polygon& rPoly ) +{ + sal_uInt16 nPoints = rPoly.GetSize(); + + if ( !(( nPoints > 1 ) && ImplCreateShape( "com.sun.star.drawing.PolyPolygonShape" )) ) + return; + + drawing::PointSequenceSequence aRetval; + + // prepare inside polygons + aRetval.realloc( 1 ); + + // get pointer to outside arrays + drawing::PointSequence* pOuterSequence = aRetval.getArray(); + + // make room in arrays + pOuterSequence->realloc(static_cast(nPoints)); + + // get pointer to arrays + awt::Point* pInnerSequence = pOuterSequence->getArray(); + + for( sal_uInt16 n = 0; n < nPoints; n++ ) + *pInnerSequence++ = awt::Point( rPoly[ n ].X(), rPoly[n].Y() ); + + uno::Any aParam; + aParam <<= aRetval; + maXPropSet->setPropertyValue( "PolyPolygon", aParam ); + ImplSetFillBundle(); +} + +void CGMImpressOutAct::DrawPolyLine( tools::Polygon& rPoly ) +{ + sal_uInt16 nPoints = rPoly.GetSize(); + + if ( !(( nPoints > 1 ) && ImplCreateShape( "com.sun.star.drawing.PolyLineShape" )) ) + return; + + drawing::PointSequenceSequence aRetval; + + // prepare inside polygons + aRetval.realloc( 1 ); + + // get pointer to outside arrays + drawing::PointSequence* pOuterSequence = aRetval.getArray(); + + // make room in arrays + pOuterSequence->realloc(static_cast(nPoints)); + + // get pointer to arrays + awt::Point* pInnerSequence = pOuterSequence->getArray(); + + for( sal_uInt16 n = 0; n < nPoints; n++ ) + *pInnerSequence++ = awt::Point( rPoly[ n ].X(), rPoly[n].Y() ); + + uno::Any aParam; + aParam <<= aRetval; + maXPropSet->setPropertyValue( "PolyPolygon", aParam ); + ImplSetLineBundle(); +} + +void CGMImpressOutAct::DrawPolybezier( tools::Polygon& rPolygon ) +{ + sal_uInt16 nPoints = rPolygon.GetSize(); + if ( !(( nPoints > 1 ) && ImplCreateShape( "com.sun.star.drawing.OpenBezierShape" )) ) + return; + + drawing::PolyPolygonBezierCoords aRetval; + + aRetval.Coordinates.realloc( 1 ); + aRetval.Flags.realloc( 1 ); + + // get pointer to outside arrays + drawing::PointSequence* pOuterSequence = aRetval.Coordinates.getArray(); + drawing::FlagSequence* pOuterFlags = aRetval.Flags.getArray(); + + // make room in arrays + pOuterSequence->realloc( nPoints ); + pOuterFlags->realloc( nPoints ); + + awt::Point* pInnerSequence = pOuterSequence->getArray(); + drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray(); + + for( sal_uInt16 i = 0; i < nPoints; i++ ) + { + *pInnerSequence++ = awt::Point( rPolygon[ i ].X(), rPolygon[ i ].Y() ); + *pInnerFlags++ = static_cast(rPolygon.GetFlags( i )); + } + uno::Any aParam; + aParam <<= aRetval; + maXPropSet->setPropertyValue( "PolyPolygonBezier", aParam ); + ImplSetLineBundle(); +} + +void CGMImpressOutAct::DrawPolyPolygon( tools::PolyPolygon const & rPolyPolygon ) +{ + sal_uInt32 nNumPolys = rPolyPolygon.Count(); + if ( !(nNumPolys && ImplCreateShape( "com.sun.star.drawing.ClosedBezierShape" )) ) + return; + + drawing::PolyPolygonBezierCoords aRetval; + + // prepare inside polygons + aRetval.Coordinates.realloc(static_cast(nNumPolys)); + aRetval.Flags.realloc(static_cast(nNumPolys)); + + // get pointer to outside arrays + drawing::PointSequence* pOuterSequence = aRetval.Coordinates.getArray(); + drawing::FlagSequence* pOuterFlags = aRetval.Flags.getArray(); + + for( sal_uInt32 a = 0; a < nNumPolys; a++ ) + { + const tools::Polygon& aPolygon( rPolyPolygon.GetObject( a ) ); + sal_uInt32 nNumPoints = aPolygon.GetSize(); + + // make room in arrays + pOuterSequence->realloc(static_cast(nNumPoints)); + pOuterFlags->realloc(static_cast(nNumPoints)); + + // get pointer to arrays + awt::Point* pInnerSequence = pOuterSequence->getArray(); + drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray(); + + for( sal_uInt32 b = 0; b < nNumPoints; b++ ) + { + *pInnerSequence++ = awt::Point( aPolygon.GetPoint( b ).X(), aPolygon.GetPoint( b ).Y() ) ; + *pInnerFlags++ = static_cast(aPolygon.GetFlags( b )); + } + pOuterSequence++; + pOuterFlags++; + } + uno::Any aParam; + aParam <<= aRetval; + maXPropSet->setPropertyValue( "PolyPolygonBezier", aParam); + ImplSetFillBundle(); +} + +void CGMImpressOutAct::DrawText(awt::Point const & rTextPos, awt::Size const & rTextSize, const OUString& rString, FinalFlag eFlag) +{ + if ( !ImplCreateShape( "com.sun.star.drawing.TextShape" ) ) + return; + + uno::Any aAny; + tools::Long nWidth = rTextSize.Width; + tools::Long nHeight = rTextSize.Height; + + awt::Point aTextPos( rTextPos ); + switch ( mpCGM->pElement->eTextAlignmentV ) + { + case TAV_HALF : + { + aTextPos.Y = o3tl::saturating_add(aTextPos.X, static_cast((mpCGM->pElement->nCharacterHeight * -1.5) / 2)); + } + break; + + case TAV_BASE : + case TAV_BOTTOM : + case TAV_NORMAL : + aTextPos.Y = o3tl::saturating_add(aTextPos.Y, static_cast(mpCGM->pElement->nCharacterHeight * -1.5)); + break; + case TAV_TOP : + break; + case TAV_CAP: + case TAV_CONT: + break; // -Wall these two were not here. + } + + if ( nWidth < 0 ) + { + nWidth = -nWidth; + } + else if ( nWidth == 0 ) + { + nWidth = -1; + } + if ( nHeight < 0 ) + { + nHeight = -nHeight; + } + else if ( nHeight == 0 ) + { + nHeight = -1; + } + maXShape->setPosition( aTextPos ); + maXShape->setSize( awt::Size( nWidth, nHeight ) ); + double nX = mpCGM->pElement->nCharacterOrientation[ 2 ]; + double nY = mpCGM->pElement->nCharacterOrientation[ 3 ]; + double fSqrt = std::hypot(nX, nY); + double nOrientation = fSqrt != 0.0 ? basegfx::rad2deg(acos(nX / fSqrt)) : 0.0; + if ( nY < 0 ) + nOrientation = 360 - nOrientation; + + if ( nOrientation ) + { + maXPropSet->setPropertyValue( "RotationPointX", uno::Any(aTextPos.X) ); + maXPropSet->setPropertyValue( "RotationPointY", uno::Any(static_cast( aTextPos.Y + nHeight )) ); + maXPropSet->setPropertyValue( "RotateAngle", uno::Any(static_cast( nOrientation * 100 )) ); + } + if ( nWidth == -1 ) + { + aAny <<= true; + maXPropSet->setPropertyValue( "TextAutoGrowWidth", aAny ); + + drawing::TextAdjust eTextAdjust; + switch ( mpCGM->pElement->eTextAlignmentH ) + { + case TAH_RIGHT : + eTextAdjust = drawing::TextAdjust_RIGHT; + break; + case TAH_LEFT : + case TAH_CONT : + case TAH_NORMAL : + eTextAdjust = drawing::TextAdjust_LEFT; + break; + case TAH_CENTER : + eTextAdjust = drawing::TextAdjust_CENTER; + break; + } + maXPropSet->setPropertyValue( "TextHorizontalAdjust", uno::Any(eTextAdjust) ); + } + if ( nHeight == -1 ) + { + maXPropSet->setPropertyValue( "TextAutoGrowHeight", uno::Any(true) ); + } + uno::Reference< text::XText > xText; + uno::Any aFirstQuery( maXShape->queryInterface( cppu::UnoType::get())); + if( aFirstQuery >>= xText ) + { + uno::Reference< text::XTextCursor > aXTextCursor( xText->createTextCursor() ); + { + aXTextCursor->gotoEnd( false ); + uno::Reference< text::XTextRange > aCursorText; + uno::Any aSecondQuery( aXTextCursor->queryInterface( cppu::UnoType::get())); + if ( aSecondQuery >>= aCursorText ) + { + uno::Reference< beans::XPropertySet > aCursorPropSet; + + uno::Any aQuery( aCursorText->queryInterface( cppu::UnoType::get())); + if( aQuery >>= aCursorPropSet ) + { + if ( nWidth != -1 ) // paragraph adjusting in a valid textbox ? + { + switch ( mpCGM->pElement->eTextAlignmentH ) + { + case TAH_RIGHT : + aAny <<= sal_Int16(style::HorizontalAlignment_RIGHT); + break; + case TAH_LEFT : + case TAH_CONT : + case TAH_NORMAL : + aAny <<= sal_Int16(style::HorizontalAlignment_LEFT); + break; + case TAH_CENTER : + aAny <<= sal_Int16(style::HorizontalAlignment_CENTER); + break; + } + aCursorPropSet->setPropertyValue( "ParaAdjust", aAny ); + } + if ( nWidth > 0 && nHeight > 0 ) // restricted text + { + aAny <<= true; + maXPropSet->setPropertyValue( "TextFitToSize", aAny ); + } + aCursorText->setString(rString); + aXTextCursor->gotoEnd( true ); + ImplSetTextBundle( aCursorPropSet ); + } + } + } + } + if ( eFlag == FF_NOT_FINAL ) + { + nFinalTextCount = maXShapes->getCount(); + } +} + +void CGMImpressOutAct::AppendText( const char* pString ) +{ + if ( !nFinalTextCount ) + return; + + uno::Reference< drawing::XShape > aShape = *o3tl::doAccess>(maXShapes->getByIndex( nFinalTextCount - 1 )); + if ( !aShape.is() ) + return; + + uno::Reference< text::XText > xText; + uno::Any aFirstQuery( aShape->queryInterface( cppu::UnoType::get()) ); + if( !(aFirstQuery >>= xText) ) + return; + + OUString aStr(pString, strlen(pString), RTL_TEXTENCODING_ASCII_US); + + uno::Reference< text::XTextCursor > aXTextCursor( xText->createTextCursor() ); + if ( !aXTextCursor.is() ) + return; + + aXTextCursor->gotoEnd( false ); + uno::Reference< text::XTextRange > aCursorText; + uno::Any aSecondQuery(aXTextCursor->queryInterface( cppu::UnoType::get())); + if ( aSecondQuery >>= aCursorText ) + { + uno::Reference< beans::XPropertySet > aPropSet; + uno::Any aQuery(aCursorText->queryInterface( cppu::UnoType::get())); + if( aQuery >>= aPropSet ) + { + aCursorText->setString( aStr ); + aXTextCursor->gotoEnd( true ); + ImplSetTextBundle( aPropSet ); + } + } +} + + +void CGMImpressOutAct::BeginFigure() +{ + if (!maPoints.empty()) + EndFigure(); + + BeginGroup(); + maPoints.clear(); + maFlags.clear(); +} + +void CGMImpressOutAct::CloseRegion() +{ + if (maPoints.size() > 2) + { + NewRegion(); + DrawPolyPolygon( maPolyPolygon ); + maPolyPolygon.Clear(); + } +} + +void CGMImpressOutAct::NewRegion() +{ + if (maPoints.size() > 2) + { + tools::Polygon aPolygon(maPoints.size(), maPoints.data(), maFlags.data()); + maPolyPolygon.Insert( aPolygon ); + } + maPoints.clear(); + maFlags.clear(); +} + +void CGMImpressOutAct::EndFigure() +{ + NewRegion(); + DrawPolyPolygon( maPolyPolygon ); + maPolyPolygon.Clear(); + EndGroup(); + maPoints.clear(); + maFlags.clear(); +} + +void CGMImpressOutAct::RegPolyLine( tools::Polygon const & rPolygon, bool bReverse ) +{ + sal_uInt16 nPoints = rPolygon.GetSize(); + if ( !nPoints ) + return; + + if ( bReverse ) + { + for ( sal_uInt16 i = 0; i < nPoints; i++ ) + { + maPoints.push_back(rPolygon.GetPoint(nPoints - i - 1)); + maFlags.push_back(rPolygon.GetFlags(nPoints - i - 1)); + } + } + else + { + for ( sal_uInt16 i = 0; i < nPoints; i++ ) + { + maPoints.push_back(rPolygon.GetPoint(i)); + maFlags.push_back(rPolygon.GetFlags(i)); + } + } +} + +void CGMImpressOutAct::SetGradientOffset( tools::Long nHorzOfs, tools::Long nVertOfs ) +{ + if ( !mpGradient ) + mpGradient.reset( new awt::Gradient ); + mpGradient->XOffset = ( static_cast(nHorzOfs) & 0x7f ); + mpGradient->YOffset = ( static_cast(nVertOfs) & 0x7f ); +} + +void CGMImpressOutAct::SetGradientAngle( tools::Long nAngle ) +{ + if ( !mpGradient ) + mpGradient.reset( new awt::Gradient ); + mpGradient->Angle = sal::static_int_cast< sal_Int16 >(nAngle); +} + +void CGMImpressOutAct::SetGradientDescriptor( sal_uInt32 nColorFrom, sal_uInt32 nColorTo ) +{ + if ( !mpGradient ) + mpGradient.reset( new awt::Gradient ); + mpGradient->StartColor = nColorFrom; + mpGradient->EndColor = nColorTo; +} + +void CGMImpressOutAct::SetGradientStyle( sal_uInt32 nStyle ) +{ + if ( !mpGradient ) + mpGradient.reset( new awt::Gradient ); + switch ( nStyle ) + { + case 0xff : + { + mpGradient->Style = awt::GradientStyle_AXIAL; + } + break; + case 4 : + { + mpGradient->Style = awt::GradientStyle_RADIAL; // CONICAL + } + break; + case 3 : + { + mpGradient->Style = awt::GradientStyle_RECT; + } + break; + case 2 : + { + mpGradient->Style = awt::GradientStyle_ELLIPTICAL; + } + break; + default : + { + mpGradient->Style = awt::GradientStyle_LINEAR; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/bitmap.cxx b/filter/source/graphicfilter/icgm/bitmap.cxx new file mode 100644 index 000000000..67652d9ec --- /dev/null +++ b/filter/source/graphicfilter/icgm/bitmap.cxx @@ -0,0 +1,433 @@ +/* -*- 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 +#include +#include +#include + +#include "bitmap.hxx" +#include "elements.hxx" + +namespace { + +Color BMCOL(sal_uInt32 _col) { + return Color( static_cast(_col >> 16 ), static_cast( _col >> 8 ), static_cast(_col) ); +} + +} + +CGMBitmap::CGMBitmap( CGM& rCGM ) : + mpCGM ( &rCGM ), + pCGMBitmapDescriptor ( new CGMBitmapDescriptor ) +{ + ImplGetBitmap( *pCGMBitmapDescriptor ); +}; + + +CGMBitmap::~CGMBitmap() +{ +} + +namespace +{ + bool isLegalBitsPerPixel(sal_uInt32 nBitsPerPixel) + { + switch (nBitsPerPixel) + { + case 1: + case 2: + case 4: + case 8: + case 24: + return true; + default: + break; + } + return false; + } +} + +void CGMBitmap::ImplGetBitmap( CGMBitmapDescriptor& rDesc ) +{ + rDesc.mbStatus = true; + + if (!ImplGetDimensions(rDesc) || !rDesc.mpBuf) + return; + + if (!isLegalBitsPerPixel(rDesc.mnDstBitsPerPixel)) + { + rDesc.mbStatus = false; + return; + } + + try + { + if (rDesc.mnScanSize) + { + vcl::bitmap::RawBitmap aBitmap( Size( rDesc.mnX, rDesc.mnY ), 24 ); + + // the picture may either be read from left to right or right to left, from top to bottom ... + + tools::Long nxCount = rDesc.mnX + 1; // +1 because we are using prefix decreasing + tools::Long nyCount = rDesc.mnY + 1; + tools::Long nx, ny, nxC; + + switch ( rDesc.mnDstBitsPerPixel ) { + case 1 : { + std::vector palette(2); + if ( rDesc.mnLocalColorPrecision == 1 ) + palette = ImplGeneratePalette( rDesc ); + else { + palette[0] = BMCOL( mpCGM->pElement->nBackGroundColor ); + palette[1] = ( mpCGM->pElement->nAspectSourceFlags & ASF_FILLINTERIORSTYLE ) + ? BMCOL( mpCGM->pElement->pFillBundle->GetColor() ) + : BMCOL( mpCGM->pElement->aFillBundle.GetColor() ); + }; + for (ny = 0; rDesc.mbStatus && --nyCount; ny++, rDesc.mpBuf += rDesc.mnScanSize) { + nxC = nxCount; + for ( nx = 0; --nxC; nx++ ) { + // this is not fast, but a one bit/pixel format is rarely used + const sal_uInt8* pPos = rDesc.mpBuf + (nx >> 3); + if (pPos >= rDesc.mpEndBuf) + { + SAL_WARN("filter.icgm", "buffer is too small"); + rDesc.mbStatus = false; + break; + } + sal_uInt8 colorIndex = static_cast((*pPos >> ((nx & 7)^7))) & 1; + aBitmap.SetPixel(ny, nx, palette[colorIndex]); + } + } + } + break; + + case 2 : { + auto palette = ImplGeneratePalette( rDesc ); + for (ny = 0; rDesc.mbStatus && --nyCount; ny++, rDesc.mpBuf += rDesc.mnScanSize) { + nxC = nxCount; + for ( nx = 0; --nxC; nx++ ) { + // this is not fast, but a two bits/pixel format is rarely used + const sal_uInt8* pPos = rDesc.mpBuf + (nx >> 2); + if (pPos >= rDesc.mpEndBuf) + { + SAL_WARN("filter.icgm", "buffer is too small"); + rDesc.mbStatus = false; + break; + } + aBitmap.SetPixel(ny, nx, palette[static_cast( (*pPos >> (((nx & 3)^3) << 1))) & 3]); + } + } + } + break; + + case 4 : { + auto palette = ImplGeneratePalette( rDesc ); + for (ny = 0; rDesc.mbStatus && --nyCount; ny++, rDesc.mpBuf += rDesc.mnScanSize) { + nxC = nxCount; + sal_uInt8* pTemp = rDesc.mpBuf; + for ( nx = 0; --nxC; nx++ ) { + + if (pTemp >= rDesc.mpEndBuf) + { + SAL_WARN("filter.icgm", "buffer is too small"); + rDesc.mbStatus = false; + break; + } + + sal_uInt8 nDat = *pTemp++; + + aBitmap.SetPixel(ny, nx, palette[static_cast(nDat >> 4)]); + if ( --nxC ) { + ++nx; + aBitmap.SetPixel(ny, nx, palette[static_cast(nDat & 15)]); + } else + break; + } + } + } + break; + + case 8 : { + auto palette = ImplGeneratePalette( rDesc ); + for (ny = 0; rDesc.mbStatus && --nyCount; ny++, rDesc.mpBuf += rDesc.mnScanSize) { + sal_uInt8* pTemp = rDesc.mpBuf; + nxC = nxCount; + for ( nx = 0; --nxC; nx++ ) { + + if (pTemp >= rDesc.mpEndBuf) + { + SAL_WARN("filter.icgm", "buffer is too small"); + rDesc.mbStatus = false; + break; + } + + aBitmap.SetPixel(ny, nx, palette[*(pTemp++)]); + } + } + } + break; + + case 24 : { + Color aBitmapColor; + for (ny = 0; rDesc.mbStatus && --nyCount; ny++, rDesc.mpBuf += rDesc.mnScanSize) { + sal_uInt8* pTemp = rDesc.mpBuf; + nxC = nxCount; + for ( nx = 0; --nxC; nx++ ) { + + if (pTemp + 2 >= rDesc.mpEndBuf) + { + SAL_WARN("filter.icgm", "buffer is too small"); + rDesc.mbStatus = false; + break; + } + + aBitmapColor.SetRed( *pTemp++ ); + aBitmapColor.SetGreen( *pTemp++ ); + aBitmapColor.SetBlue( *pTemp++ ); + aBitmap.SetPixel(ny, nx, aBitmapColor); + } + } + } + break; + } + + if ( rDesc.mbStatus ) + rDesc.mxBitmap = vcl::bitmap::CreateFromData(std::move(aBitmap)); + } + + double nX = rDesc.mnR.X - rDesc.mnQ.X; + double nY = rDesc.mnR.Y - rDesc.mnQ.Y; + + rDesc.mndy = std::hypot(nX, nY); + + nX = rDesc.mnR.X - rDesc.mnP.X; + nY = rDesc.mnR.Y - rDesc.mnP.Y; + + rDesc.mndx = std::hypot(nX, nY); + + nX = rDesc.mnR.X - rDesc.mnP.X; + nY = rDesc.mnR.Y - rDesc.mnP.Y; + + double fSqrt = std::hypot(nX, nY); + rDesc.mnOrientation = fSqrt != 0.0 ? basegfx::rad2deg(acos(nX / fSqrt)) : 0.0; + if ( nY > 0 ) + rDesc.mnOrientation = 360 - rDesc.mnOrientation; + + nX = rDesc.mnQ.X - rDesc.mnR.X; + nY = rDesc.mnQ.Y - rDesc.mnR.Y; + + double fAngle = basegfx::deg2rad( 360 - rDesc.mnOrientation ); + double fSin = sin(fAngle); + double fCos = cos(fAngle); + nX = fCos * nX + fSin * nY; + nY = -( fSin * nX - fCos * nY ); + + fSqrt = std::hypot(nX, nY); + fAngle = fSqrt != 0.0 ? basegfx::rad2deg(acos(nX / fSqrt)) : 0.0; + if ( nY > 0 ) + fAngle = 360 - fAngle; + + if ( fAngle > 180 ) { // is the picture build upwards or downwards ? + rDesc.mnOrigin = rDesc.mnP; + } else { + rDesc.mbVMirror = true; + rDesc.mnOrigin = rDesc.mnP; + rDesc.mnOrigin.X += rDesc.mnQ.X - rDesc.mnR.X; + rDesc.mnOrigin.Y += rDesc.mnQ.Y - rDesc.mnR.Y; + } + } + catch (const std::bad_alloc&) + { + rDesc.mbStatus = false; + } +} + +std::vector CGMBitmap::ImplGeneratePalette( CGMBitmapDescriptor const & rDesc ) +{ + sal_uInt16 nColors = sal::static_int_cast< sal_uInt16 >( + 1 << rDesc.mnDstBitsPerPixel); + std::vector palette( nColors ); + for ( sal_uInt16 i = 0; i < nColors; i++ ) + { + palette[i] = BMCOL( mpCGM->pElement->aLatestColorTable[ i ] ); + } + return palette; +} + + +bool CGMBitmap::ImplGetDimensions( CGMBitmapDescriptor& rDesc ) +{ + mpCGM->ImplGetPoint( rDesc.mnP ); // parallelogram p < - > r + mpCGM->ImplGetPoint( rDesc.mnQ ); // | + mpCGM->ImplGetPoint( rDesc.mnR ); // q + sal_uInt32 nPrecision = mpCGM->pElement->nIntegerPrecision; + rDesc.mnX = mpCGM->ImplGetUI( nPrecision ); + rDesc.mnY = mpCGM->ImplGetUI( nPrecision ); + rDesc.mnLocalColorPrecision = mpCGM->ImplGetI( nPrecision ); + rDesc.mnScanSize = 0; + switch( rDesc.mnLocalColorPrecision ) + { + case tools::Long(0x80000001) : // monochrome ( bit = 0->backgroundcolor ) + case 0 : // bit = 1->fillcolor + rDesc.mnDstBitsPerPixel = 1; + break; + case 1 : // 2 color indexed ( monochrome ) + case -1 : + rDesc.mnDstBitsPerPixel = 1; + break; + case 2 : // 4 color indexed + case -2 : + rDesc.mnDstBitsPerPixel = 2; + break; + case 4 : // 16 color indexed + case -4 : + rDesc.mnDstBitsPerPixel = 4; + break; + case 8 : // 256 color indexed + case -8 : + rDesc.mnDstBitsPerPixel = 8; + rDesc.mnScanSize = rDesc.mnX; + break; + case 16 : // NS + case -16 : + rDesc.mbStatus = false; + break; + case 24 : // 24 bit directColor ( 8 bits each component ) + case -24 : + rDesc.mnDstBitsPerPixel = 24; + break; + case 32 : // NS + case -32 : + rDesc.mbStatus = false; + break; + + } + // mnCompressionMode == 0 : CCOMP_RUNLENGTH + // == 1 : CCOMP_PACKED ( no compression. each row starts on a 4 byte boundary ) + if ( ( rDesc.mnCompressionMode = mpCGM->ImplGetUI16() ) != 1 ) + rDesc.mbStatus = false; + + if ( !( rDesc.mnX || rDesc.mnY ) ) + rDesc.mbStatus = false; + + sal_uInt32 nHeaderSize = 2 + 3 * nPrecision + 3 * mpCGM->ImplGetPointSize(); + + sal_uInt32 nWidthBits; + if (o3tl::checked_multiply(rDesc.mnX, rDesc.mnDstBitsPerPixel, nWidthBits)) + { + rDesc.mbStatus = false; + return false; + } + + rDesc.mnScanSize = (nWidthBits + 7) >> 3; + + sal_uInt32 nScanSize; + nScanSize = rDesc.mnScanSize; + if ( ( nScanSize * rDesc.mnY + nHeaderSize ) != mpCGM->mnElementSize ) // try a scansize without dw alignment + { + nScanSize = ( rDesc.mnScanSize + 1 ) & ~1; + if ( ( nScanSize * rDesc.mnY + nHeaderSize ) != mpCGM->mnElementSize ) // then we'll try word alignment + { + nScanSize = ( rDesc.mnScanSize + 3 ) & ~3; + if ( ( nScanSize * rDesc.mnY + nHeaderSize ) != mpCGM->mnElementSize ) // and last we'll try dword alignment + { + nScanSize = ( rDesc.mnScanSize + 1 ) & ~1; // and LAST BUT NOT LEAST we'll try word alignment without aligning the last line + if ( ( nScanSize * ( rDesc.mnY - 1 ) + rDesc.mnScanSize + nHeaderSize ) != mpCGM->mnElementSize ) + { + nScanSize = ( rDesc.mnScanSize + 3 ) & ~3; + if ( ( nScanSize * ( rDesc.mnY - 1 ) + rDesc.mnScanSize + nHeaderSize ) != mpCGM->mnElementSize ) + { + mpCGM->mnParaSize = 0; // this format is corrupt + rDesc.mbStatus = false; + } + } + } + } + } + rDesc.mnScanSize = nScanSize; + if ( rDesc.mbStatus ) + { + rDesc.mpBuf = mpCGM->mpSource + mpCGM->mnParaSize; // mpBuf now points to the first scanline + rDesc.mpEndBuf = mpCGM->mpEndValidSource; + mpCGM->mnParaSize += rDesc.mnScanSize * rDesc.mnY; + } + return rDesc.mbStatus; +} + + +void CGMBitmap::ImplInsert( CGMBitmapDescriptor const & rSource, CGMBitmapDescriptor& rDest ) +{ + if (utl::ConfigManager::IsFuzzing() && rDest.mxBitmap.GetSizePixel().Height() + rSource.mnY > SAL_MAX_UINT16) + { + SAL_WARN("filter.icgm", "bitmap would expand too much"); + rDest.mbStatus = false; + return; + } + rDest.mxBitmap.Expand( 0, rSource.mnY ); + rDest.mxBitmap.CopyPixel( tools::Rectangle( Point( 0, rDest.mnY ), Size( rSource.mnX, rSource.mnY ) ), + tools::Rectangle( Point( 0, 0 ), Size( rSource.mnX, rSource.mnY ) ), &rSource.mxBitmap ); + + if ( ( rSource.mnR.Y == rDest.mnQ.Y ) && ( rSource.mnR.X == rDest.mnQ.X ) ) + { // Insert on Bottom + if ( mpCGM->mnVDCYmul == -1 ) + rDest.mnOrigin = rSource.mnOrigin; // new origin + FloatPoint aFloatPoint; + aFloatPoint.X = rSource.mnQ.X - rSource.mnR.X; + aFloatPoint.Y = rSource.mnQ.Y - rSource.mnR.Y; + rDest.mnQ.X += aFloatPoint.X; + rDest.mnQ.Y += aFloatPoint.Y; + rDest.mnP = rSource.mnP; + rDest.mnR = rSource.mnR; + } + else + { // Insert on Top + if ( mpCGM->mnVDCYmul == 1 ) + rDest.mnOrigin = rSource.mnOrigin; // new origin + rDest.mnP = rSource.mnP; + rDest.mnR = rSource.mnR; + } + rDest.mnY += rSource.mnY; + rDest.mndy += rSource.mndy; +}; + +std::unique_ptr CGMBitmap::GetNext() +{ + std::unique_ptr xCGMTempBitmap; + if (!pCGMBitmapDescriptor->mxBitmap.IsEmpty() && pCGMBitmapDescriptor->mbStatus) + { + xCGMTempBitmap.reset(new CGMBitmap(*mpCGM)); + if ( ( static_cast(xCGMTempBitmap->pCGMBitmapDescriptor->mnOrientation) == static_cast(pCGMBitmapDescriptor->mnOrientation) ) && + ( ( ( xCGMTempBitmap->pCGMBitmapDescriptor->mnR.X == pCGMBitmapDescriptor->mnQ.X ) && + ( xCGMTempBitmap->pCGMBitmapDescriptor->mnR.Y == pCGMBitmapDescriptor->mnQ.Y ) ) || + ( ( xCGMTempBitmap->pCGMBitmapDescriptor->mnQ.X == pCGMBitmapDescriptor->mnR.X ) && + ( xCGMTempBitmap->pCGMBitmapDescriptor->mnQ.Y == pCGMBitmapDescriptor->mnR.Y ) ) ) ) + { + ImplInsert( *(xCGMTempBitmap->pCGMBitmapDescriptor), *pCGMBitmapDescriptor ); + xCGMTempBitmap.reset(); + return xCGMTempBitmap; + } + + pCGMBitmapDescriptor.swap(xCGMTempBitmap->pCGMBitmapDescriptor); + } + return xCGMTempBitmap; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/bitmap.hxx b/filter/source/graphicfilter/icgm/bitmap.hxx new file mode 100644 index 000000000..3e7b80f51 --- /dev/null +++ b/filter/source/graphicfilter/icgm/bitmap.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ + +#pragma once + +#include "cgm.hxx" +#include +#include + +class CGM; + +class CGMBitmapDescriptor +{ + public: + sal_uInt8* mpBuf; + sal_uInt8* mpEndBuf; + BitmapEx mxBitmap; + bool mbStatus; + bool mbVMirror; + sal_uInt32 mnDstBitsPerPixel; + sal_uInt32 mnScanSize; // bytes per line + FloatPoint mnP, mnQ, mnR; + + FloatPoint mnOrigin; + double mndx, mndy; + double mnOrientation; + + sal_uInt32 mnX, mnY; + tools::Long mnLocalColorPrecision; + sal_uInt32 mnCompressionMode; + + CGMBitmapDescriptor() + : mpBuf(nullptr) + , mpEndBuf(nullptr) + , mbStatus(false) + , mbVMirror(false) + , mnDstBitsPerPixel(0) + , mnScanSize(0) + , mndx(0.0) + , mndy(0.0) + , mnOrientation(0.0) + , mnX(0) + , mnY(0) + , mnLocalColorPrecision(0) + , mnCompressionMode(0) + { }; +}; + +class CGMBitmap +{ + CGM* mpCGM; + std::unique_ptr + pCGMBitmapDescriptor; + bool ImplGetDimensions( CGMBitmapDescriptor& ); + std::vector ImplGeneratePalette( CGMBitmapDescriptor const & ); + void ImplGetBitmap( CGMBitmapDescriptor& ); + void ImplInsert( CGMBitmapDescriptor const & rSource, CGMBitmapDescriptor& rDest ); +public: + explicit CGMBitmap( CGM& rCGM ); + ~CGMBitmap(); + CGMBitmapDescriptor* GetBitmap() { return pCGMBitmapDescriptor.get();} + std::unique_ptr GetNext(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/bundles.cxx b/filter/source/graphicfilter/icgm/bundles.cxx new file mode 100644 index 000000000..64e63a750 --- /dev/null +++ b/filter/source/graphicfilter/icgm/bundles.cxx @@ -0,0 +1,141 @@ +/* -*- 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 "bundles.hxx" + +#include + +void Bundle::SetColor( sal_uInt32 nColor ) +{ + mnColor = nColor; +} + +CGMFList::CGMFList() + : nFontNameCount(0) + , nCharSetCount(0) +{ +} + +FontEntry* CGMFList::GetFontEntry( sal_uInt32 nIndex ) +{ + sal_uInt32 nInd = nIndex; + if ( nInd ) + nInd--; + return ( nInd < aFontEntryList.size() ) ? &aFontEntryList[nInd] : nullptr; +} + +static sal_Int8* ImplSearchEntry( sal_Int8* pSource, sal_Int8 const * pDest, sal_uInt32 nComp, sal_uInt32 nSize ) +{ + while ( nComp-- >= nSize ) + { + sal_uInt32 i; + for ( i = 0; i < nSize; i++ ) + { + if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) ) + break; + } + if ( i == nSize ) + return pSource; + pSource++; + } + return nullptr; +} + +void CGMFList::InsertName( sal_uInt8 const * pSource, sal_uInt32 nSize ) +{ + FontEntry* pFontEntry; + if (nFontNameCount == aFontEntryList.size()) + { + aFontEntryList.push_back(FontEntry()); + pFontEntry = &aFontEntryList.back(); + } + else + { + pFontEntry = &aFontEntryList[nFontNameCount]; + } + nFontNameCount++; + + if (nSize == 0) + return; + + std::vector aBuf(pSource, pSource + nSize); + sal_Int8* pFound = ImplSearchEntry(aBuf.data(), reinterpret_cast("ITALIC"), nSize, 6); + if (pFound) + { + pFontEntry->nFontType |= 1; + sal_uInt32 nPrev = pFound - aBuf.data(); + sal_uInt32 nToCopyOfs = 6; + if ( nPrev && ( pFound[ -1 ] == '-' || pFound[ -1 ] == ' ' ) ) + { + nPrev--; + pFound--; + nToCopyOfs++; + } + sal_uInt32 nToCopy = nSize - nToCopyOfs - nPrev; + if ( nToCopy ) + { + memmove( pFound, pFound + nToCopyOfs, nToCopy ); + } + nSize -= nToCopyOfs; + } + pFound = ImplSearchEntry(aBuf.data(), reinterpret_cast("BOLD"), nSize, 4); + if ( pFound ) + { + pFontEntry->nFontType |= 2; + + sal_uInt32 nPrev = pFound - aBuf.data(); + sal_uInt32 nToCopyOfs = 4; + if ( nPrev && ( pFound[ -1 ] == '-' || pFound[ -1 ] == ' ' ) ) + { + nPrev--; + pFound--; + nToCopyOfs++; + } + sal_uInt32 nToCopy = nSize - nToCopyOfs - nPrev; + if ( nToCopy ) + { + memmove( pFound, pFound + nToCopyOfs, nToCopy ); + } + nSize -= nToCopyOfs; + } + pFontEntry->aFontName.assign(aBuf.data(), aBuf.data() + nSize); +} + +void CGMFList::InsertCharSet( sal_uInt8 const * pSource, sal_uInt32 nSize ) +{ + FontEntry* pFontEntry; + if (nCharSetCount == aFontEntryList.size()) + { + aFontEntryList.push_back(FontEntry()); + pFontEntry = &aFontEntryList.back(); + } + else + { + pFontEntry = &aFontEntryList[nCharSetCount]; + } + nCharSetCount++; + + if (nSize == 0) + return; + + pFontEntry->aCharSetValue.assign(pSource, pSource + nSize); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/bundles.hxx b/filter/source/graphicfilter/icgm/bundles.hxx new file mode 100644 index 000000000..209eae6dd --- /dev/null +++ b/filter/source/graphicfilter/icgm/bundles.hxx @@ -0,0 +1,166 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include "cgmtypes.hxx" +#include +#include + + +class Bundle +{ + + tools::Long mnBundleIndex; + sal_uInt32 mnColor; + +public: + void SetColor( sal_uInt32 nColor ) ; + sal_uInt32 GetColor() const { return mnColor;} + tools::Long GetIndex() const { return mnBundleIndex; } ; + void SetIndex( tools::Long nBundleIndex ) { mnBundleIndex = nBundleIndex; } ; + + Bundle() + : mnBundleIndex( 0 ) + , mnColor( 0 ) + {}; + + virtual std::unique_ptr Clone() { return std::make_unique( *this ); }; + + virtual ~Bundle() {} ; + + Bundle(Bundle const &) = default; + Bundle(Bundle &&) = default; + Bundle & operator =(Bundle const &) = default; + Bundle & operator =(Bundle &&) = default; +}; + + +class LineBundle : public Bundle +{ +public: + + LineType eLineType; + double nLineWidth; + + LineBundle() + : eLineType(LT_SOLID) + , nLineWidth(0) + {} + + virtual std::unique_ptr Clone() override { return std::make_unique( *this ); } +}; + + +class MarkerBundle : public Bundle +{ +public: + + MarkerType eMarkerType; + double nMarkerSize; + + MarkerBundle() + : eMarkerType( MT_POINT ) + , nMarkerSize( 0.0 ) + {}; + + virtual std::unique_ptr Clone() override { return std::make_unique( *this ); } ; +}; + + +class EdgeBundle : public Bundle +{ +public: + + EdgeType eEdgeType; + double nEdgeWidth; + + EdgeBundle() + : eEdgeType(ET_NONE) + , nEdgeWidth(0) + {} + virtual std::unique_ptr Clone() override { return std::make_unique( *this ); } +}; + + +class TextBundle : public Bundle +{ +public: + + sal_uInt32 nTextFontIndex; + TextPrecision eTextPrecision; + double nCharacterExpansion; + double nCharacterSpacing; + + TextBundle() + : nTextFontIndex( 0 ) + , eTextPrecision( TPR_UNDEFINED ) + , nCharacterExpansion( 0.0 ) + , nCharacterSpacing( 0.0 ) + {}; + + virtual std::unique_ptr Clone() override { return std::make_unique( *this ); } ; +}; + + +class FillBundle : public Bundle +{ +public: + + FillInteriorStyle eFillInteriorStyle; + tools::Long nFillPatternIndex; + tools::Long nFillHatchIndex; + + FillBundle() + : eFillInteriorStyle(FIS_HOLLOW) + , nFillPatternIndex(0) + , nFillHatchIndex(0) + {} + virtual std::unique_ptr Clone() override { return std::make_unique( *this ); } +}; + + +struct FontEntry +{ + std::vector aFontName; + std::vector aCharSetValue; + sal_uInt32 nFontType; // bit 0 = 1 -> Italic, + // bit 1 = 1 -> Bold + FontEntry() + : nFontType(0) + { + } +}; + +class CGMFList +{ + sal_uInt32 nFontNameCount; + sal_uInt32 nCharSetCount; + std::vector aFontEntryList; + +public: + CGMFList(); + + FontEntry* GetFontEntry( sal_uInt32 ); + void InsertName( sal_uInt8 const * pSource, sal_uInt32 nSize ); + void InsertCharSet( sal_uInt8 const * pSource, sal_uInt32 nSize ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/cgm.cxx b/filter/source/graphicfilter/icgm/cgm.cxx new file mode 100644 index 000000000..1cf7c7ca0 --- /dev/null +++ b/filter/source/graphicfilter/icgm/cgm.cxx @@ -0,0 +1,741 @@ +/* -*- 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 +#include +#include +#include +#include "bitmap.hxx" +#include "chart.hxx" +#include "elements.hxx" +#include "outact.hxx" +#include +#include +#include + +using namespace ::com::sun::star; + +constexpr double gnOutdx = 28000; // Output size in 1/100TH mm +constexpr double gnOutdy = 21000; // on which is mapped + +CGM::CGM(uno::Reference< frame::XModel > const & rModel) + : mnVDCXadd(0) + , mnVDCYadd(0) + , mnVDCXmul(0) + , mnVDCYmul(0) + , mnVDCdx(0) + , mnVDCdy(0) + , mnXFraction(0) + , mnYFraction(0) + , mbAngReverse(false) + , mbStatus(true) + , mbMetaFile(false) + , mbIsFinished(false) + , mbPicture(false) + , mbPictureBody(false) + , mbFigure(false) + , mbFirstOutPut(false) + , mbInDefaultReplacement(false) + , mnAct4PostReset(0) + , mpOutAct(new CGMImpressOutAct(*this, rModel)) + , mpSource(nullptr) + , mpEndValidSource(nullptr) + , mnParaSize(0) + , mnActCount(0) + , mnEscape(0) + , mnElementClass(0) + , mnElementID(0) + , mnElementSize(0) +{ + pElement.reset( new CGMElements ); + pCopyOfE.reset( new CGMElements ); +} + +CGM::~CGM() +{ + maDefRepList.clear(); + maDefRepSizeList.clear(); +}; + +sal_uInt32 CGM::GetBackGroundColor() const +{ + return pElement ? pElement->aColorTable[ 0 ] : 0; +} + +sal_uInt32 CGM::ImplGetUI16() +{ + sal_uInt8* pSource = mpSource + mnParaSize; + if (mpEndValidSource - pSource < 2) + throw css::uno::Exception("attempt to read past end of input", nullptr); + mnParaSize += 2; + return ( pSource[ 0 ] << 8 ) + pSource[ 1 ]; +}; + +sal_uInt8 CGM::ImplGetByte( sal_uInt32 nSource, sal_uInt32 nPrecision ) +{ + return static_cast( nSource >> ( ( nPrecision - 1 ) << 3 ) ); +}; + +sal_Int32 CGM::ImplGetI( sal_uInt32 nPrecision ) +{ + sal_uInt8* pSource = mpSource + mnParaSize; + if (pSource > mpEndValidSource || o3tl::make_unsigned(mpEndValidSource - pSource) < nPrecision) + throw css::uno::Exception("attempt to read past end of input", nullptr); + mnParaSize += nPrecision; + switch( nPrecision ) + { + case 1 : + { + return static_cast(*pSource); + } + + case 2 : + { + return static_cast( ( pSource[ 0 ] << 8 ) | pSource[ 1 ] ); + } + + case 3 : + { + return ( ( pSource[ 0 ] << 24 ) | ( pSource[ 1 ] << 16 ) | pSource[ 2 ] << 8 ) >> 8; + } + case 4: + { + return static_cast( ( pSource[ 0 ] << 24 ) | ( pSource[ 1 ] << 16 ) | ( pSource[ 2 ] << 8 ) | ( pSource[ 3 ] ) ); + } + default: + mbStatus = false; + return 0; + } +} + +sal_uInt32 CGM::ImplGetUI( sal_uInt32 nPrecision ) +{ + sal_uInt8* pSource = mpSource + mnParaSize; + if (pSource > mpEndValidSource || o3tl::make_unsigned(mpEndValidSource - pSource) < nPrecision) + throw css::uno::Exception("attempt to read past end of input", nullptr); + mnParaSize += nPrecision; + switch( nPrecision ) + { + case 1 : + return static_cast(*pSource); + case 2 : + { + return static_cast( ( pSource[ 0 ] << 8 ) | pSource[ 1 ] ); + } + case 3 : + { + return ( pSource[ 0 ] << 16 ) | ( pSource[ 1 ] << 8 ) | pSource[ 2 ]; + } + case 4: + { + return static_cast( ( pSource[ 0 ] << 24 ) | ( pSource[ 1 ] << 16 ) | ( pSource[ 2 ] << 8 ) | ( pSource[ 3 ] ) ); + } + default: + mbStatus = false; + return 0; + } +} + +void CGM::ImplGetSwitch4( const sal_uInt8* pSource, sal_uInt8* pDest ) +{ + for ( int i = 0; i < 4; i++ ) + { + pDest[ i ] = pSource[ i ^ 3 ]; // Little Endian <-> Big Endian switch + } +} + +void CGM::ImplGetSwitch8( const sal_uInt8* pSource, sal_uInt8* pDest ) +{ + for ( int i = 0; i < 8; i++ ) + { + pDest[ i ] = pSource[ i ^ 7 ]; // Little Endian <-> Big Endian switch + } +} + +double CGM::ImplGetFloat( RealPrecision eRealPrecision, sal_uInt32 nRealSize ) +{ + void* pPtr; + sal_uInt8 aBuf[8]; + double nRetValue; + double fDoubleBuf; + float fFloatBuf; + +#ifdef OSL_BIGENDIAN + const bool bCompatible = true; +#else + const bool bCompatible = false; +#endif + + if (o3tl::make_unsigned(mpEndValidSource - (mpSource + mnParaSize)) < nRealSize) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + if ( bCompatible ) + { + pPtr = mpSource + mnParaSize; + } + else + { + if ( nRealSize == 4 ) + ImplGetSwitch4( mpSource + mnParaSize, &aBuf[0] ); + else + ImplGetSwitch8( mpSource + mnParaSize, &aBuf[0] ); + pPtr = &aBuf; + } + if ( eRealPrecision == RP_FLOAT ) + { + if ( nRealSize == 4 ) + { + memcpy( static_cast(&fFloatBuf), pPtr, 4 ); + nRetValue = static_cast(fFloatBuf); + } + else + { + memcpy( static_cast(&fDoubleBuf), pPtr, 8 ); + nRetValue = fDoubleBuf; + } + } + else // ->RP_FIXED + { + tools::Long nVal; + const int nSwitch = bCompatible ? 0 : 1 ; + if ( nRealSize == 4 ) + { + sal_uInt16* pShort = static_cast(pPtr); + nVal = pShort[ nSwitch ]; + nVal <<= 16; + nVal |= pShort[ nSwitch ^ 1 ]; + nRetValue = static_cast(nVal); + nRetValue /= 65536; + } + else + { + sal_Int32* pLong = static_cast(pPtr); + nRetValue = static_cast(abs( pLong[ nSwitch ] )); + nRetValue *= 65536; + nVal = static_cast( pLong[ nSwitch ^ 1 ] ); + nVal >>= 16; + nRetValue += static_cast(nVal); + if ( pLong[ nSwitch ] < 0 ) + { + nRetValue = -nRetValue; + } + nRetValue /= 65536; + } + } + mnParaSize += nRealSize; + return nRetValue; +} + +sal_uInt32 CGM::ImplGetPointSize() +{ + if ( pElement->eVDCType == VDC_INTEGER ) + return pElement->nVDCIntegerPrecision << 1; + else + return pElement->nVDCRealSize << 1; +} + +inline double CGM::ImplGetIX() +{ + return ( ( ImplGetI( pElement->nVDCIntegerPrecision ) + mnVDCXadd ) * mnVDCXmul ); +} + +inline double CGM::ImplGetFX() +{ + return ( ( ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ) + mnVDCXadd ) * mnVDCXmul ); +} + +inline double CGM::ImplGetIY() +{ + return ( ( ImplGetI( pElement->nVDCIntegerPrecision ) + mnVDCYadd ) * mnVDCYmul ); +} + +inline double CGM::ImplGetFY() +{ + return ( ( ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ) + mnVDCYadd ) * mnVDCYmul ); +} + +void CGM::ImplGetPoint( FloatPoint& rFloatPoint, bool bMap ) +{ + if ( pElement->eVDCType == VDC_INTEGER ) + { + rFloatPoint.X = ImplGetIX(); + rFloatPoint.Y = ImplGetIY(); + } + else // ->floating points + { + rFloatPoint.X = ImplGetFX(); + rFloatPoint.Y = ImplGetFY(); + } + if ( bMap ) + ImplMapPoint( rFloatPoint ); +} + +void CGM::ImplGetRectangle( FloatRect& rFloatRect, bool bMap ) +{ + if ( pElement->eVDCType == VDC_INTEGER ) + { + rFloatRect.Left = ImplGetIX(); + rFloatRect.Bottom = ImplGetIY(); + rFloatRect.Right = ImplGetIX(); + rFloatRect.Top = ImplGetIY(); + } + else // ->floating points + { + rFloatRect.Left = ImplGetFX(); + rFloatRect.Bottom = ImplGetFY(); + rFloatRect.Right = ImplGetFX(); + rFloatRect.Top = ImplGetFY(); + } + if ( bMap ) + { + ImplMapX( rFloatRect.Left ); + ImplMapX( rFloatRect.Right ); + ImplMapY( rFloatRect.Top ); + ImplMapY( rFloatRect.Bottom ); + rFloatRect.Justify(); + } +} + +void CGM::ImplGetRectangleNS( FloatRect& rFloatRect ) +{ + if ( pElement->eVDCType == VDC_INTEGER ) + { + rFloatRect.Left = ImplGetI( pElement->nVDCIntegerPrecision ); + rFloatRect.Bottom = ImplGetI( pElement->nVDCIntegerPrecision ); + rFloatRect.Right = ImplGetI( pElement->nVDCIntegerPrecision ); + rFloatRect.Top = ImplGetI( pElement->nVDCIntegerPrecision ); + } + else // ->floating points + { + rFloatRect.Left = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + rFloatRect.Bottom = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + rFloatRect.Right = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + rFloatRect.Top = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + } +} + +sal_uInt32 CGM::ImplGetBitmapColor( bool bDirect ) +{ + // the background color is always a direct color + + sal_uInt32 nTmp; + if ( ( pElement->eColorSelectionMode == CSM_DIRECT ) || bDirect ) + { + sal_uInt32 nColor = ImplGetByte( ImplGetUI( pElement->nColorPrecision ), 1 ); + sal_uInt32 nDiff = pElement->nColorValueExtent[ 3 ] - pElement->nColorValueExtent[ 0 ] + 1; + + if ( !nDiff ) + nDiff++; + nColor = ( ( nColor - pElement->nColorValueExtent[ 0 ] ) << 8 ) / nDiff; + nTmp = nColor << 16 & 0xff0000; + + nColor = ImplGetByte( ImplGetUI( pElement->nColorPrecision ), 1 ); + nDiff = pElement->nColorValueExtent[ 4 ] - pElement->nColorValueExtent[ 1 ] + 1; + if ( !nDiff ) + nDiff++; + nColor = ( ( nColor - pElement->nColorValueExtent[ 1 ] ) << 8 ) / nDiff; + nTmp |= nColor << 8 & 0xff00; + + nColor = ImplGetByte( ImplGetUI( pElement->nColorPrecision ), 1 ); + nDiff = pElement->nColorValueExtent[ 5 ] - pElement->nColorValueExtent[ 2 ] + 1; + if ( !nDiff ) + nDiff++; + nColor = ( ( nColor - pElement->nColorValueExtent[ 2 ] ) << 8 ) / nDiff; + nTmp |= static_cast(nColor); + } + else + { + sal_uInt32 nIndex = ImplGetUI( pElement->nColorIndexPrecision ); + nTmp = pElement->aColorTable[ static_cast(nIndex) ] ; + } + return nTmp; +} + +// call this function each time after the mapmode settings has been changed +void CGM::ImplSetMapMode() +{ + int nAngReverse = 1; + mnVDCdx = pElement->aVDCExtent.Right - pElement->aVDCExtent.Left; + + mnVDCXadd = -pElement->aVDCExtent.Left; + mnVDCXmul = 1; + if ( mnVDCdx < 0 ) + { + nAngReverse ^= 1; + mnVDCdx = -mnVDCdx; + mnVDCXmul = -1; + } + + mnVDCdy = pElement->aVDCExtent.Bottom - pElement->aVDCExtent.Top; + mnVDCYadd = -pElement->aVDCExtent.Top; + mnVDCYmul = 1; + if ( mnVDCdy < 0 ) + { + nAngReverse ^= 1; + mnVDCdy = -mnVDCdy; + mnVDCYmul = -1; + } + if ( nAngReverse ) + mbAngReverse = true; + else + mbAngReverse = false; + + if (mnVDCdy == 0.0 || mnVDCdx == 0.0 || gnOutdy == 0.0) + { + mbStatus = false; + return; + } + + double fQuo1 = mnVDCdx / mnVDCdy; + double fQuo2 = gnOutdx / gnOutdy; + if ( fQuo2 < fQuo1 ) + { + mnXFraction = gnOutdx / mnVDCdx; + mnYFraction = gnOutdy * ( fQuo2 / fQuo1 ) / mnVDCdy; + } + else + { + mnXFraction = gnOutdx * ( fQuo1 / fQuo2 ) / mnVDCdx; + mnYFraction = gnOutdy / mnVDCdy; + } +} + +void CGM::ImplMapDouble( double& nNumb ) +{ + if ( pElement->eDeviceViewPortMap != DVPM_FORCED ) + return; + + // point is 1mm * ScalingFactor + switch ( pElement->eDeviceViewPortMode ) + { + case DVPM_FRACTION : + { + nNumb *= ( mnXFraction + mnYFraction ) / 2; + } + break; + + case DVPM_METRIC : + { + // nNumb *= ( 100 * pElement->nDeviceViewPortScale ); + nNumb *= ( mnXFraction + mnYFraction ) / 2; + if ( pElement->nDeviceViewPortScale < 0 ) + nNumb = -nNumb; + } + break; + + case DVPM_DEVICE : + { + + } + break; + + default: + + break; + } +} + +void CGM::ImplMapX( double& nNumb ) +{ + if ( pElement->eDeviceViewPortMap != DVPM_FORCED ) + return; + + // point is 1mm * ScalingFactor + switch ( pElement->eDeviceViewPortMode ) + { + case DVPM_FRACTION : + { + nNumb *= mnXFraction; + } + break; + + case DVPM_METRIC : + { + // nNumb *= ( 100 * pElement->nDeviceViewPortScale ); + nNumb *= mnXFraction; + if ( pElement->nDeviceViewPortScale < 0 ) + nNumb = -nNumb; + } + break; + + case DVPM_DEVICE : + { + + } + break; + + default: + + break; + } +} + +void CGM::ImplMapY( double& nNumb ) +{ + if ( pElement->eDeviceViewPortMap != DVPM_FORCED ) + return; + + // point is 1mm * ScalingFactor + switch ( pElement->eDeviceViewPortMode ) + { + case DVPM_FRACTION : + { + nNumb *= mnYFraction; + } + break; + + case DVPM_METRIC : + { + // nNumb *= ( 100 * pElement->nDeviceViewPortScale ); + nNumb *= mnYFraction; + if ( pElement->nDeviceViewPortScale < 0 ) + nNumb = -nNumb; + } + break; + + case DVPM_DEVICE : + { + + } + break; + + default: + + break; + } +} + +// convert a point to the current VC mapmode (1/100TH mm) +void CGM::ImplMapPoint( FloatPoint& rFloatPoint ) +{ + if ( pElement->eDeviceViewPortMap != DVPM_FORCED ) + return; + + // point is 1mm * ScalingFactor + switch ( pElement->eDeviceViewPortMode ) + { + case DVPM_FRACTION : + { + rFloatPoint.X *= mnXFraction; + rFloatPoint.Y *= mnYFraction; + } + break; + + case DVPM_METRIC : + { + rFloatPoint.X *= mnXFraction; + rFloatPoint.Y *= mnYFraction; + if ( pElement->nDeviceViewPortScale < 0 ) + { + rFloatPoint.X = -rFloatPoint.X; + rFloatPoint.Y = -rFloatPoint.Y; + } + } + break; + + case DVPM_DEVICE : + { + + } + break; + + default: + + break; + } +} + +void CGM::ImplDoClass() +{ + switch ( mnElementClass ) + { + case 0 : ImplDoClass0(); break; + case 1 : ImplDoClass1(); break; + case 2 : ImplDoClass2(); break; + case 3 : ImplDoClass3(); break; + case 4 : + { + ImplDoClass4(); + mnAct4PostReset = 0; + } + break; + case 5 : ImplDoClass5(); break; + case 6 : ImplDoClass6(); break; + case 7 : ImplDoClass7(); break; + case 8 : ImplDoClass8(); break; + case 9 : ImplDoClass9(); break; + case 15 :ImplDoClass15(); break; + default: break; + } + mnActCount++; +}; + +void CGM::ImplDefaultReplacement() +{ + if (maDefRepList.empty()) + return; + + if (mbInDefaultReplacement) + { + SAL_WARN("filter.icgm", "recursion in ImplDefaultReplacement"); + return; + } + + mbInDefaultReplacement = true; + + sal_uInt32 nOldEscape = mnEscape; + sal_uInt32 nOldElementClass = mnElementClass; + sal_uInt32 nOldElementID = mnElementID; + sal_uInt32 nOldElementSize = mnElementSize; + sal_uInt8* pOldBuf = mpSource; + sal_uInt8* pOldEndValidSource = mpEndValidSource; + + for ( size_t i = 0, n = maDefRepList.size(); i < n; ++i ) + { + sal_uInt8* pBuf = maDefRepList[ i ].get(); + sal_uInt32 nElementSize = maDefRepSizeList[ i ]; + mpEndValidSource = pBuf + nElementSize; + sal_uInt32 nCount = 0; + while ( mbStatus && ( nCount < nElementSize ) ) + { + mpSource = pBuf + nCount; + mnParaSize = 0; + mnEscape = ImplGetUI16(); + mnElementClass = mnEscape >> 12; + mnElementID = ( mnEscape & 0x0fe0 ) >> 5; + mnElementSize = mnEscape & 0x1f; + if ( mnElementSize == 31 ) + { + mnElementSize = ImplGetUI16(); + } + nCount += mnParaSize; + mnParaSize = 0; + mpSource = pBuf + nCount; + if ( mnElementSize & 1 ) + nCount++; + nCount += mnElementSize; + if ( ( mnElementClass != 1 ) || ( mnElementID != 0xc ) ) // recursion is not possible here!! + ImplDoClass(); + } + } + mnEscape = nOldEscape; + mnElementClass = nOldElementClass; + mnElementID = nOldElementID; + mnParaSize = mnElementSize = nOldElementSize; + mpSource = pOldBuf; + mpEndValidSource = pOldEndValidSource; + + mbInDefaultReplacement = false; +} + +bool CGM::Write( SvStream& rIStm ) +{ + if ( !mpBuf ) + mpBuf.reset( new sal_uInt8[ 0xffff ] ); + + mnParaSize = 0; + mpSource = mpBuf.get(); + if (rIStm.ReadBytes(mpSource, 2) != 2) + return false; + mpEndValidSource = mpSource + 2; + mnEscape = ImplGetUI16(); + mnElementClass = mnEscape >> 12; + mnElementID = ( mnEscape & 0x0fe0 ) >> 5; + mnElementSize = mnEscape & 0x1f; + + if ( mnElementSize == 31 ) + { + if (rIStm.ReadBytes(mpSource + mnParaSize, 2) != 2) + return false; + mpEndValidSource = mpSource + mnParaSize + 2; + mnElementSize = ImplGetUI16(); + } + mnParaSize = 0; + if (mnElementSize) + { + if (rIStm.ReadBytes(mpSource, mnElementSize) != mnElementSize) + return false; + mpEndValidSource = mpSource + mnElementSize; + } + + if ( mnElementSize & 1 ) + rIStm.SeekRel( 1 ); + ImplDoClass(); + + return mbStatus; +}; + +// GraphicImport - the exported function +extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32 +ImportCGM(SvStream& rIn, uno::Reference< frame::XModel > const & rXModel, css::uno::Reference const & aXStatInd) +{ + + sal_uInt32 nStatus = 0; // retvalue == 0 -> ERROR + // == 0xffrrggbb -> background color in the lower 24 bits + + if( rXModel.is() ) + { + try + { + CGM aCGM(rXModel); + if (aCGM.IsValid()) + { + rIn.SetEndian(SvStreamEndian::BIG); + sal_uInt64 const nInSize = rIn.remainingSize(); + rIn.Seek(0); + + sal_uInt32 nNext = 0; + sal_uInt32 nAdd = nInSize / 20; + bool bProgressBar = aXStatInd.is(); + if ( bProgressBar ) + aXStatInd->start( "CGM Import" , nInSize ); + + while (aCGM.IsValid() && (rIn.Tell() < nInSize) && !aCGM.IsFinished()) + { + if ( bProgressBar ) + { + sal_uInt32 nCurrentPos = rIn.Tell(); + if ( nCurrentPos >= nNext ) + { + aXStatInd->setValue( nCurrentPos ); + nNext = nCurrentPos + nAdd; + } + } + + if (!aCGM.Write(rIn)) + break; + } + if ( aCGM.IsValid() ) + { + nStatus = aCGM.GetBackGroundColor() | 0xff000000; + } + if ( bProgressBar ) + aXStatInd->end(); + } + } + catch (const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("filter.icgm", ""); + nStatus = 0; + } + } + return nStatus; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/cgm.hxx b/filter/source/graphicfilter/icgm/cgm.hxx new file mode 100644 index 000000000..b344cb22e --- /dev/null +++ b/filter/source/graphicfilter/icgm/cgm.hxx @@ -0,0 +1,151 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include +#include +#include "cgmtypes.hxx" + +class Graphic; +class SvStream; +class CGMChart; +class CGMBitmap; +class CGMImpressOutAct; +class CGMElements; +class GDIMetaFile; +class VirtualDevice; + +class CGM +{ + friend class CGMChart; + friend class CGMBitmap; + friend class CGMElements; + friend class CGMImpressOutAct; + + double mnVDCXadd; + double mnVDCYadd; + double mnVDCXmul; + double mnVDCYmul; + double mnVDCdx; + double mnVDCdy; + double mnXFraction; + double mnYFraction; + bool mbAngReverse; // AngularDirection + + bool mbStatus; + bool mbMetaFile; + bool mbIsFinished; + bool mbPicture; + bool mbPictureBody; + bool mbFigure; + bool mbFirstOutPut; + bool mbInDefaultReplacement; + sal_uInt32 mnAct4PostReset; + std::unique_ptr mpBitmapInUse; + std::unique_ptr mpChart; // if sal_True->"SHWSLIDEREC" + // otherwise "BEGINPIC" commands + // controls page inserting + std::unique_ptr pElement; + std::unique_ptr pCopyOfE; + std::unique_ptr mpOutAct; + ::std::vector< std::unique_ptr > maDefRepList; + ::std::vector< sal_uInt32 > maDefRepSizeList; + + sal_uInt8* mpSource; // start of source buffer that is not increased + // ( instead use mnParaCount to index ) + sal_uInt8* mpEndValidSource; // end position in source buffer of last valid data + sal_uInt32 mnParaSize; // actual parameter size which has been done so far + sal_uInt32 mnActCount; // increased by each action + std::unique_ptr + mpBuf; // source stream operation -> then this is allocated for + // the temp input buffer + + sal_uInt32 mnEscape; + sal_uInt32 mnElementClass; + sal_uInt32 mnElementID; + sal_uInt32 mnElementSize; // full parameter size for the latest action + + sal_uInt32 ImplGetUI16(); + static sal_uInt8 ImplGetByte( sal_uInt32 nSource, sal_uInt32 nPrecision ); + sal_Int32 ImplGetI( sal_uInt32 nPrecision ); + sal_uInt32 ImplGetUI( sal_uInt32 nPrecision ); + static void ImplGetSwitch4( const sal_uInt8* pSource, sal_uInt8* pDest ); + static void ImplGetSwitch8( const sal_uInt8* pSource, sal_uInt8* pDest ); + double ImplGetFloat( RealPrecision, sal_uInt32 nRealSize ); + sal_uInt32 ImplGetBitmapColor( bool bDirectColor = false ); + void ImplSetMapMode(); + void ImplSetUnderlineMode(); + void ImplMapDouble( double& ); + void ImplMapX( double& ); + void ImplMapY( double& ); + void ImplMapPoint( FloatPoint& ); + inline double ImplGetIY(); + inline double ImplGetFY(); + inline double ImplGetIX(); + inline double ImplGetFX(); + sal_uInt32 ImplGetPointSize(); + void ImplGetPoint( FloatPoint& rFloatPoint, bool bMap = false ); + void ImplGetRectangle( FloatRect&, bool bMap = false ); + void ImplGetRectangleNS( FloatRect& ); + void ImplGetVector( double* ); + static double ImplGetOrientation( FloatPoint const & rCenter, FloatPoint const & rPoint ); + static void ImplSwitchStartEndAngle( double& rStartAngle, double& rEndAngle ); + bool ImplGetEllipse( FloatPoint& rCenter, FloatPoint& rRadius, double& rOrientation ); + + void ImplDefaultReplacement(); + void ImplDoClass(); + void ImplDoClass0(); + void ImplDoClass1(); + void ImplDoClass2(); + void ImplDoClass3(); + void ImplDoClass4(); + void ImplDoClass5(); + void ImplDoClass6(); + void ImplDoClass7(); + void ImplDoClass8(); + void ImplDoClass9(); + void ImplDoClass15(); + + public: + + ~CGM(); + + CGM(css::uno::Reference< css::frame::XModel > const & rModel); + sal_uInt32 GetBackGroundColor() const; + bool IsValid() const { return mbStatus; }; + bool IsFinished() const { return mbIsFinished; }; + bool Write( SvStream& rIStm ); + +}; + +inline bool useless(double value) +{ + if (!std::isfinite(value)) + return true; + int exp; + std::frexp(value, &exp); + const int maxbits = sizeof(tools::Long) * 8; + return exp > maxbits; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/cgmtypes.hxx b/filter/source/graphicfilter/icgm/cgmtypes.hxx new file mode 100644 index 000000000..5b7def212 --- /dev/null +++ b/filter/source/graphicfilter/icgm/cgmtypes.hxx @@ -0,0 +1,127 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +struct FloatPoint +{ + double X; + double Y; + FloatPoint():X(0), Y(0){}; +}; + +struct FloatRect +{ + double Left; + double Top; + double Right; + double Bottom; + FloatRect():Left(0), Top(0), Right(0), Bottom(0){}; + void Justify() + { + double fTemp; + if ( Left > Right ) + { + fTemp = Left; + Left = Right; + Right = fTemp; + } + if ( Top > Bottom ) + { + fTemp = Top; + Top = Bottom; + Bottom = fTemp; + } + } +}; + +struct HatchEntry +{ + int HatchStyle; + tools::Long HatchDistance; + tools::Long HatchAngle; +}; + +#define ASF_LINETYPE 0x00000001UL +#define ASF_LINEWIDTH 0x00000002UL +#define ASF_LINECOLOR 0x00000004UL +#define ASF_MARKERTYPE 0x00000008UL +#define ASF_MARKERSIZE 0x00000010UL +#define ASF_MARKERCOLOR 0x00000020UL // NS +#define ASF_FILLINTERIORSTYLE 0x00000040UL +#define ASF_HATCHINDEX 0x00000080UL +#define ASF_PATTERNINDEX 0x00000100UL +#define ASF_BITMAPINDEX 0x00000200UL // NS +#define ASF_FILLCOLOR 0x00000400UL +#define ASF_EDGETYPE 0x00000800UL +#define ASF_EDGEWIDTH 0x00001000UL +#define ASF_EDGECOLOR 0x00002000UL +#define ASF_TEXTFONTINDEX 0x00004000UL +#define ASF_TEXTPRECISION 0x00008000UL +#define ASF_CHARACTEREXPANSION 0x00010000UL +#define ASF_CHARACTERSPACING 0x00020000UL +#define ASF_TEXTCOLOR 0x00040000UL + +#define ACT4_GRADIENT_ACTION 0x00000001UL + +enum RealPrecision { RP_FLOAT = 0, RP_FIXED = 1 }; + +enum ScalingMode { SM_ABSTRACT = 0, SM_METRIC = 1 }; + +enum VDCType { VDC_INTEGER = 0, VDC_REAL = 1 }; +enum DeviceViewPortMode { DVPM_FRACTION = 0, DVPM_METRIC = 1, DVPM_DEVICE = 2 }; +enum DeviceViewPortMap { DVPM_NOT_FORCED = 0, DVPM_FORCED = 1 }; +enum DeviceViewPortMapH { DVPMH_LEFT = 0, DVPMH_CENTER = 1, CVPMH_RIGHT = 2 }; +enum DeviceViewPortMapV { DVPMV_BOTTOM = 0, DVPMV_CENTER = 1, DVPMV_TOP = 2 }; + +enum ClipIndicator { CI_OFF = 0, CI_ON = 1 }; + +enum ColorSelectionMode { CSM_INDEXED = 0, CSM_DIRECT = 1 }; +enum ColorModel { CM_RGB = 0, CM_CMYK = 1 }; + +enum CharacterCodingA { CCA_BASIC_7 = 0, CCA_BASIC_8 = 1, CCA_EXT_7 = 2, CCA_EXT_8 = 3 }; +enum TextPrecision { TPR_STRING = 0, TPR_CHARACTER = 1, TPR_STROKE = 2, TPR_UNDEFINED = 0xffff }; +enum TextPath { TPR_RIGHT = 0, TPR_LEFT = 1, TPR_UP = 2, TPR_DOWN = 3 }; +enum TextAlignmentH { TAH_NORMAL = 0, TAH_LEFT = 1, TAH_CENTER = 2, TAH_RIGHT = 3, TAH_CONT = 4 }; +enum TextAlignmentV { TAV_NORMAL = 0, TAV_TOP = 1, TAV_CAP = 2, TAV_HALF = 3, TAV_BASE = 4, TAV_BOTTOM = 5, TAV_CONT = 6 }; +enum UnderlineMode { UM_OFF = 0, UM_LOW = 1, UM_HIGH = 2, UM_STRIKEOUT = 4, UM_OVERSCORE = 8 }; +enum FinalFlag { FF_NOT_FINAL = 0, FF_FINAL = 1 }; + +enum LineType { LT_SOLID = 1, LT_DASH = 2, LT_DOT = 3, LT_DASHDOT = 4, LT_DASHDOTDOT = 5, // Standard + LT_NONE = -4, LT_DOTDOTSPACE = -3, LT_LONGDASH = -2, LT_DASHDASHDOT = -1 }; // GDSF Styles +enum SpecMode { SM_ABSOLUTE = 0, SM_SCALED = 1 }; +enum LineCapType { LCT_BUTT = 0, LCT_ROUND = 1, LCT_SQUARE = 2, LCT_TRIANGLE = 3, LCT_ARROW = 4, LCT_NONE = -1 }; +enum LineJoinType { LJT_MITER = 0, LJT_ROUND = 1, LJT_BEVEL = 2, LJT_NONE = -1 }; + + +enum EdgeType { ET_SOLID = 1, ET_DASH = 2, ET_DOT = 3, ET_DASHDOT = 4, ET_DASHDOTDOT = 5, // Standard + ET_NONE = -4, ET_DOTDOTSPACE = -3, ET_LONGDASH = -2, ET_DASHDASHDOT = -1 }; // GDSF Styles +enum EdgeVisibility { EV_OFF = 0, EV_ON = 1 }; + +enum MarkerType { MT_POINT = 1, MT_PLUS = 2, MT_STAR = 3, MT_CIRCLE = 4, MT_CROSS = 5 }; + +enum Transparency { T_OFF = 0, T_ON = 1 }; + +enum FillInteriorStyle { FIS_HOLLOW = 0, FIS_SOLID = 1, FIS_PATTERN = 2, FIS_HATCH = 3, FIS_EMPTY = 4, FIS_GEOPATTERN = 5, + FIS_INTERPOLATED = 6, FIS_GRADIENT = 7 }; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/chart.cxx b/filter/source/graphicfilter/icgm/chart.cxx new file mode 100644 index 000000000..91818149a --- /dev/null +++ b/filter/source/graphicfilter/icgm/chart.cxx @@ -0,0 +1,57 @@ +/* -*- 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 "chart.hxx" + + +CGMChart::CGMChart() + : mnCurrentFileType(0) +{ + for ( sal_Int8 i = 0; i < 7; i++ ) + { + mDataNode[ i ].nZoneEnum = i; + } +} + +CGMChart::~CGMChart() +{ + // delete the whole textentry structure + for (const auto & pTextEntry : maTextEntryList) + { + if ( pTextEntry ) + delete [] pTextEntry->pText; + } +} + +void CGMChart::InsertTextEntry( std::unique_ptr pTextEntry ) +{ + maTextEntryList.push_back( std::move(pTextEntry) ); +} + +void CGMChart::ResetAnnotation() +{ + mDataNode[ 0 ].nZoneEnum = 0; +} + +bool CGMChart::IsAnnotation() const +{ + return ( mDataNode[ 0 ].nZoneEnum == 0 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/chart.hxx b/filter/source/graphicfilter/icgm/chart.hxx new file mode 100644 index 000000000..ef77ace0e --- /dev/null +++ b/filter/source/graphicfilter/icgm/chart.hxx @@ -0,0 +1,84 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include + +/* FILE TYPE CONSTANTS: */ +#define BULCHART 32 /* Bullet chart file. */ +/* the following were added although SPC doesn't have a #define */ +/* for them... */ +#define AUTOTTLCHT 95 /* Autobuild TTL CHT */ +#define AUTOBULCHT 96 /* Autobuild BUL CHT */ +#define AUTOTABCHT 97 /* Autobuild TAB CHT */ + +typedef struct TextEntry +{ + sal_uInt16 nTypeOfText; + sal_uInt16 nRowOrLineNum; + sal_uInt16 nColumnNum; + sal_uInt16 nZoneSize; // textzone attributes + sal_uInt16 nLineType; + sal_uInt16 nAttributes; + char* pText; // null terminated text +} TextEntry; + +struct DataNode +{ + sal_Int16 nBoxX1; + sal_Int16 nBoxY1; + sal_Int16 nBoxX2; + sal_Int16 nBoxY2; + sal_Int8 nZoneEnum; + DataNode() + : nBoxX1(0) + , nBoxY1(0) + , nBoxX2(0) + , nBoxY2(0) + , nZoneEnum(0) + { + } +}; + +class CGM; +class CGMImpressOutAct; +class CGMChart final +{ + friend class CGM; + friend class CGMImpressOutAct; + + sal_Int8 mnCurrentFileType; + ::std::vector< std::unique_ptr > maTextEntryList; + DataNode mDataNode[ 7 ]; + + public: + CGMChart(); + ~CGMChart(); + + void InsertTextEntry( std::unique_ptr ); + + void ResetAnnotation(); + bool IsAnnotation() const; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/class0.cxx b/filter/source/graphicfilter/icgm/class0.cxx new file mode 100644 index 000000000..a31bce5d2 --- /dev/null +++ b/filter/source/graphicfilter/icgm/class0.cxx @@ -0,0 +1,128 @@ +/* -*- 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 "bitmap.hxx" +#include "cgm.hxx" +#include "elements.hxx" +#include "outact.hxx" + + +void CGM::ImplDoClass0() +{ + switch ( mnElementID ) + { + case 0x01 : /*Begin Metafile*/ + { + ImplSetMapMode(); + mbMetaFile = true; + } + break; + case 0x02 : /*End MetaFile*/ + { + if ( mpBitmapInUse ) // process existing graphic + { + CGMBitmapDescriptor* pBmpDesc = mpBitmapInUse->GetBitmap(); + // do anything with the bitmap + mpOutAct->DrawBitmap( pBmpDesc ); + mpBitmapInUse.reset(); + } + mbIsFinished = true; + mbPictureBody = false; + mbMetaFile = false; + } + break; + case 0x03 : /*Begin Picture*/ + { + if (mbPicture || mbInDefaultReplacement) + mbStatus = false; + else + { + *pCopyOfE = *pElement; + ImplDefaultReplacement(); + ImplSetMapMode(); + mbPicture = mbFirstOutPut = true; + mbFigure = false; + mnAct4PostReset = 0; + if ( mpChart == nullptr ) // normal CGM Files determines "BeginPic" + mpOutAct->InsertPage(); // as the next slide + } + } + break; + case 0x04 : /*Begin Picture Body*/ + mbPictureBody = true; + break; + case 0x05 : /* End Picture*/ + { + if ( mbPicture ) + { + if ( mpBitmapInUse ) // process existing graphic + { + CGMBitmapDescriptor* pBmpDesc = mpBitmapInUse->GetBitmap(); + // do anything with the bitmap + mpOutAct->DrawBitmap( pBmpDesc ); + mpBitmapInUse.reset(); + } + mpOutAct->EndFigure(); // close potential figures + mpOutAct->EndGrouping(); // finish potential groups + *pElement = *pCopyOfE; + mbFigure = mbFirstOutPut = mbPicture = mbPictureBody = false; + } + else + mbStatus = false; + } + break; + case 0x06 : /*Begin Segment*/ + pElement->bSegmentCount = true; + break; + case 0x07 : /*End Segment*/ + pElement->bSegmentCount = true; + break; + case 0x08 : /*Begin Figure*/ + mbFigure = true; + mpOutAct->BeginFigure(); + break; + case 0x09 : /*End Figure*/ + mpOutAct->EndFigure(); + mbFigure = false; + break; + case 0x0d : /*Begin Protection vcl::Region */break; + case 0x0e : /*End Protection vcl::Region */break; + case 0x0f : /*Begin Compound Line */break; + case 0x10 : /*End Compound Line */break; + case 0x11 : /*Begin Compound Text Path */break; + case 0x12 : /*End Compound Text Path */break; + case 0x13 : /*Begin Tile Array */break; // NS + case 0x14 : /*End Tile Array */break; // NS + case 0xff : /*Filter Setup */break; + case 0xfe : /*Begin Block Text vcl::Region */break; + case 0xfd : /*End Block Text vcl::Region */break; + case 0xfc : /*Begin Group*/ + mpOutAct->BeginGroup(); + break; + case 0xfb : /*End Group*/ + mpOutAct->EndGroup(); + break; + case 0xfa : /*Begin Patch */break; + case 0xf9 : /*Begin Patch */break; + default: break; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/class1.cxx b/filter/source/graphicfilter/icgm/class1.cxx new file mode 100644 index 000000000..07a6fe253 --- /dev/null +++ b/filter/source/graphicfilter/icgm/class1.cxx @@ -0,0 +1,225 @@ +/* -*- 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 +#include + +#include + +#include "bundles.hxx" +#include "cgm.hxx" +#include "elements.hxx" + + +void CGM::ImplDoClass1() +{ + tools::Long nInteger, nI0, nI1; + sal_uInt32 nUInteger; + + switch ( mnElementID ) + { + case 0x01 : /*Metafile Version*/ + pElement->nMetaFileVersion = ImplGetI( pElement->nIntegerPrecision ); + break; + case 0x02 : /*Metafile Description */break; + case 0x03 : /*VDC Type*/ + { + nUInteger = ImplGetUI16(); + switch( nUInteger ) + { + case 0 : pElement->eVDCType = VDC_INTEGER; break; + case 1 : pElement->eVDCType = VDC_REAL; break; + default: mbStatus = false; break; + } + } + break; + case 0x04 : /*Integer Precision*/ + { + nInteger = ImplGetI( pElement->nIntegerPrecision ); + switch ( nInteger ) + { + case 32 : + case 24 : + case 16 : + case 8 : pElement->nIntegerPrecision = nInteger >> 3; break; + default : mbStatus = false; break; + } + } + break; + case 0x05 : /*Real Precision*/ + { + nUInteger = ImplGetUI16(); + nI0 = ImplGetI( pElement->nIntegerPrecision ); // exponent + nI1 = ImplGetI( pElement->nIntegerPrecision ); // mantissa + switch( nUInteger ) + { + case 0 : + pElement->eRealPrecision = RP_FLOAT; + switch ( nI0 ) + { + case 9 : + if ( nI1 != 23 ) + mbStatus = false; + pElement->nRealSize = 4; + break; + case 12 : + if ( nI1 != 52 ) + mbStatus =false; + pElement->nRealSize = 8; + break; + default: + mbStatus = false; + break; + } + break; + case 1 : + pElement->eRealPrecision = RP_FIXED; + if ( nI0 != nI1 ) + mbStatus = false; + if ( nI0 == 16 ) + pElement->nRealSize = 4; + else if ( nI0 == 32 ) + pElement->nRealSize = 8; + else + mbStatus = false; + break; + default : + mbStatus = false; break; + } + } + break; + case 0x06 : /*Index Precision*/ + { + nInteger = ImplGetI( pElement->nIntegerPrecision ); + switch ( nInteger ) + { + case 32 : + case 24 : + case 16 : + case 8 : pElement->nIndexPrecision = nInteger >> 3; break; + default : mbStatus = false; break; + } + } + break; + case 0x07 : /*Color Precision*/ + { + nInteger = ImplGetI( pElement->nIntegerPrecision ); + switch ( nInteger ) + { + case 32 : + case 24 : + case 16 : + case 8 : pElement->nColorPrecision = nInteger >> 3; break; + default : mbStatus = false; break; + } + } + break; + case 0x08 : /*Color Index Precision*/ + { + nInteger = ImplGetI( pElement->nIntegerPrecision ); + switch ( nInteger ) + { + case 32 : + case 24 : + case 16 : + case 8 : pElement->nColorIndexPrecision = nInteger >> 3; break; + default : mbStatus = false; break; + } + } + break; + case 0x09 : /*Maximum Colour Index*/ + { + pElement->nColorMaximumIndex = ImplGetUI( pElement->nColorIndexPrecision ); + if ( ( pElement->nColorMaximumIndex > 256 /*255*/ ) || ( pElement->nColorMaximumIndex == 0 ) ) + mbStatus = false; + } + break; + case 0x0a : /*Color Value Extent*/ + { + nI1 = 6; + } + break; + case 0x0b : /*MetaFile Element List */break; + case 0x0c : /*MetaFile Default Replacement*/ + { + if ( mnElementSize > 1 ) + { + std::unique_ptr pBuf(new sal_uInt8[ mnElementSize ]); + memcpy( pBuf.get(), mpSource, mnElementSize ); + maDefRepList.push_back( std::move(pBuf) ); + maDefRepSizeList.push_back( mnElementSize ); + } + mnParaSize = mnElementSize; + } + break; + case 0x0d : /*Font List*/ + { + while ( mnParaSize < mnElementSize ) + { + sal_uInt32 nSize = ImplGetUI(1); + + if (o3tl::make_unsigned(mpEndValidSource - (mpSource + mnParaSize)) < nSize) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + pElement->aFontList.InsertName( mpSource + mnParaSize, nSize ); + mnParaSize += nSize; + } + } + break; + case 0x0e : /*Character Set List*/ + { + while ( mnParaSize < mnElementSize ) + { + ImplGetUI16(); // skip CharSetType + sal_uInt32 nSize = ImplGetUI(1); + + if (o3tl::make_unsigned(mpEndValidSource - (mpSource + mnParaSize)) < nSize) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + pElement->aFontList.InsertCharSet( mpSource + mnParaSize, nSize ); + mnParaSize += nSize; + } + } + break; + case 0x0f : /*Character Coding Announcer*/ + { + auto nCharacterCoding = ImplGetUI16(); + if (nCharacterCoding <= CCA_EXT_8) + pElement->eCharacterCodingA = static_cast(nCharacterCoding); + else + SAL_WARN("filter.icgm", "CharacterCoding " << nCharacterCoding << " requested, but legal max is " << CCA_EXT_8); + } + break; + case 0x10 : /*Name Precision */break; // NS + case 0x11 : /*Maximum VDC Extent */break; // NS + case 0x12 : /*Segment Priority Extent */break; // NS + case 0x13 : /*Color Model */break; // NS + case 0x14 : /*Color Calibration */break; // NS + case 0x15 : /*Font Properties */break; // NS + case 0x16 : /*Glyph Mapping */break; // NS + case 0x17 : /*Symbol Library List */break; // NS + case 0xfc : /*Inquire Function Support */break; + case 0xfa : /*End Metafile Defaults Replacement */break; + case 0xf8 : /*Set Color Value Desc Extent */break; + default: break; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/class2.cxx b/filter/source/graphicfilter/icgm/class2.cxx new file mode 100644 index 000000000..8d410e475 --- /dev/null +++ b/filter/source/graphicfilter/icgm/class2.cxx @@ -0,0 +1,233 @@ +/* -*- 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 "cgm.hxx" +#include "bundles.hxx" +#include "elements.hxx" + + +void CGM::ImplDoClass2() +{ + sal_uInt32 nUInteger; + switch ( mnElementID ) + { + case 0x01 : /*Scaling Mode*/ + { + if ( mnElementSize ) // HACK (NASA.CGM) + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eScalingMode = SM_ABSTRACT; break; + case 1 : pElement->eScalingMode = SM_METRIC; break; + default : mbStatus = false; break; + } + pElement->nScalingFactor = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + ImplSetMapMode(); + } + } + break; + case 0x02 : /*Color Selection Mode*/ + { + nUInteger = ImplGetUI16(); + switch( nUInteger ) + { + case 0 : pElement->eColorSelectionMode = CSM_INDEXED; break; + case 1 : pElement->eColorSelectionMode = CSM_DIRECT; break; + default : mbStatus = false; break; + } + } + break; + case 0x03 : /*Line Width Specification Mode*/ + { + nUInteger = ImplGetUI16(); + switch( nUInteger ) + { + case 0 : pElement->eLineWidthSpecMode = SM_ABSOLUTE; break; + case 1 : pElement->eLineWidthSpecMode = SM_SCALED; break; + default : mbStatus = false; break; + } + } + break; + case 0x04 : /*Marker Size Specification Mode*/ + { + nUInteger = ImplGetUI16(); + switch( nUInteger ) + { + case 0 : pElement->eMarkerSizeSpecMode = SM_ABSOLUTE; break; + case 1 : pElement->eMarkerSizeSpecMode = SM_SCALED; break; + default : mbStatus = false; break; + } + } + break; + case 0x05 : /*Edge Width Specification Mode*/ + { + nUInteger = ImplGetUI16(); + switch( nUInteger ) + { + case 0 : pElement->eEdgeWidthSpecMode = SM_ABSOLUTE; break; + case 1 : pElement->eEdgeWidthSpecMode = SM_SCALED; break; + default : mbStatus = false; break; + } + } + break; + case 0x06 : /*VDC Extent*/ + { + ImplGetRectangleNS( pElement->aVDCExtent ); + ImplSetMapMode(); + } + break; + case 0x07 : /*Background Color*/ + pElement->nBackGroundColor = ImplGetBitmapColor( true ); + break; + case 0x08 : /*Device Viewport*/ + { + if ( pElement->eVDCType == VDC_INTEGER ) + ImplGetRectangle( pElement->aDeviceViewPort ); + ImplSetMapMode(); + } + break; + case 0x09 : /*Device Viewport Specification Mode*/ + { + nUInteger = ImplGetUI16(); + switch( nUInteger ) + { + case 0 : pElement->eDeviceViewPortMode = DVPM_FRACTION; break; + case 1 : pElement->eDeviceViewPortMode = DVPM_METRIC; break; + case 2 : pElement->eDeviceViewPortMode = DVPM_DEVICE; break; + default : mbStatus = false; break; + } + pElement->nDeviceViewPortScale = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + ImplSetMapMode(); + } + break; + case 0x0a : /*Device Viewport Mapping*/ + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eDeviceViewPortMap = DVPM_NOT_FORCED; break; + case 1 : pElement->eDeviceViewPortMap = DVPM_FORCED; break; + default : mbStatus = false; break; + } + switch( ImplGetUI16() ) + { + case 0 : pElement->eDeviceViewPortMapH = DVPMH_LEFT; break; + case 1 : pElement->eDeviceViewPortMapH = DVPMH_CENTER; break; + case 2 : pElement->eDeviceViewPortMapH = CVPMH_RIGHT; break; + default : mbStatus = false; break; + } + switch( ImplGetUI16() ) + { + case 0 : pElement->eDeviceViewPortMapV = DVPMV_BOTTOM; break; + case 1 : pElement->eDeviceViewPortMapV = DVPMV_CENTER; break; + case 2 : pElement->eDeviceViewPortMapV = DVPMV_TOP; break; + default : mbStatus = false; break; + } + ImplSetMapMode(); + } + break; + case 0x0b : /*Line Representation*/ + { + LineBundle aTempLineBundle; + aTempLineBundle.SetIndex( ImplGetI( pElement->nIndexPrecision ) ); + aTempLineBundle.eLineType = static_cast(ImplGetI( pElement->nIndexPrecision )); + aTempLineBundle.nLineWidth = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + aTempLineBundle.SetColor( ImplGetBitmapColor() ); + const bool bUpdateLineBundle = aTempLineBundle.GetIndex() == pElement->pLineBundle->GetIndex(); + CGMElements::InsertBundle( pElement->aLineList, aTempLineBundle ); + if (bUpdateLineBundle) + pElement->pLineBundle = static_cast(CGMElements::GetBundleIndex(aTempLineBundle.GetIndex(), pElement->aLineList, pElement->aLineBundle)); + } + break; + case 0x0c : /*Marker Representation*/ + { + MarkerBundle aTempMarkerBundle; + aTempMarkerBundle.SetIndex( ImplGetI( pElement->nIndexPrecision ) ); + aTempMarkerBundle.eMarkerType = static_cast(ImplGetI( pElement->nIndexPrecision )); + aTempMarkerBundle.nMarkerSize = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + aTempMarkerBundle.SetColor( ImplGetBitmapColor() ); + const bool bUpdateMarkerBundle = aTempMarkerBundle.GetIndex() == pElement->pMarkerBundle->GetIndex(); + CGMElements::InsertBundle( pElement->aMarkerList, aTempMarkerBundle ); + if (bUpdateMarkerBundle) + pElement->pMarkerBundle = static_cast(CGMElements::GetBundleIndex(aTempMarkerBundle.GetIndex(), pElement->aMarkerList, pElement->aMarkerBundle)); + } + break; + case 0x0d : /*Text Representation*/ + { + TextBundle aTempTextBundle; + aTempTextBundle.SetIndex( ImplGetI( pElement->nIndexPrecision ) ); + aTempTextBundle.nTextFontIndex = ImplGetI( pElement->nIndexPrecision ); + aTempTextBundle.eTextPrecision = static_cast(ImplGetI( pElement->nIndexPrecision )); + aTempTextBundle.nCharacterSpacing = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + aTempTextBundle.nCharacterExpansion = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + aTempTextBundle.SetColor( ImplGetBitmapColor() ); + const bool bUpdateTextBundle = aTempTextBundle.GetIndex() == pElement->pTextBundle->GetIndex(); + CGMElements::InsertBundle( pElement->aTextList, aTempTextBundle ); + if (bUpdateTextBundle) + pElement->pTextBundle = static_cast(CGMElements::GetBundleIndex(aTempTextBundle.GetIndex(), pElement->aTextList, pElement->aTextBundle)); + } + break; + case 0x0e : /*Fill Representation*/ + { + FillBundle aTempFillBundle; + aTempFillBundle.SetIndex( ImplGetI( pElement->nIndexPrecision ) ); + aTempFillBundle.eFillInteriorStyle = static_cast(ImplGetI( pElement->nIndexPrecision )); + aTempFillBundle.SetColor( ImplGetBitmapColor() ); + aTempFillBundle.nFillPatternIndex = ImplGetI( pElement->nIndexPrecision ); + aTempFillBundle.nFillHatchIndex = ImplGetI( pElement->nIndexPrecision ); + const bool bUpdateFillBundle = aTempFillBundle.GetIndex() == pElement->pFillBundle->GetIndex(); + CGMElements::InsertBundle( pElement->aFillList, aTempFillBundle ); + if (bUpdateFillBundle) + pElement->pFillBundle = static_cast(CGMElements::GetBundleIndex(aTempFillBundle.GetIndex(), pElement->aFillList, pElement->aFillBundle)); + } + break; + case 0x0f : /*Edge Representation*/ + { + EdgeBundle aTempEdgeBundle; + aTempEdgeBundle.SetIndex( ImplGetI( pElement->nIndexPrecision ) ); + aTempEdgeBundle.eEdgeType = static_cast(ImplGetI( pElement->nIndexPrecision )); + aTempEdgeBundle.nEdgeWidth = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + aTempEdgeBundle.SetColor( ImplGetBitmapColor() ); + const bool bUpdateEdgeBundle = aTempEdgeBundle.GetIndex() == pElement->pEdgeBundle->GetIndex(); + CGMElements::InsertBundle( pElement->aEdgeList, aTempEdgeBundle ); + if (bUpdateEdgeBundle) + pElement->pEdgeBundle = static_cast(CGMElements::GetBundleIndex(aTempEdgeBundle.GetIndex(), pElement->aEdgeList, pElement->aEdgeBundle)); + } + break; + case 0x10 : /*Interior Style Specification Mode */break; // NS + case 0x11 : /*Line and Edge Type Definition */break; + case 0x12 : /*Hatch Style Definition */break; // NS + case 0x13 : /*Geometric Pattern Definition */break; // NS + case 0xff : /*inquire VDC EXTENT */break; + case 0xfe : /*inquire Background Color */break; + case 0xfd : /*inquire Device Viewport */break; + case 0xfc : /*set Font Selection Mode */break; + case 0xfb : /*inquire Color Selection Mode */break; + case 0xfa : /*inquire Font Selection Mode */break; + case 0xf9 : /*set Char Height Spec Mode*/ + { + ImplGetUI16(); // -Wall is this really needed? + } + break; + case 0xf8 : /*set Background Style */break; + default: break; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/class3.cxx b/filter/source/graphicfilter/icgm/class3.cxx new file mode 100644 index 000000000..3cc25730f --- /dev/null +++ b/filter/source/graphicfilter/icgm/class3.cxx @@ -0,0 +1,134 @@ +/* -*- 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 "cgm.hxx" +#include "elements.hxx" +#include "outact.hxx" + + +void CGM::ImplDoClass3() +{ + sal_uInt32 nUInteger; + switch ( mnElementID ) + { + case 0x01 : /*VDC Integer Precision*/ + { + switch( ImplGetI( pElement->nIntegerPrecision ) ) + { + case 16 : pElement->nVDCIntegerPrecision = 2; break; + case 32 : pElement->nVDCIntegerPrecision = 4; break; + default : mbStatus = false; break; + } + } + break; + case 0x02 : /*VDC Real Precision*/ + { + nUInteger = ImplGetUI16(); + const tools::Long nI0 = ImplGetI( pElement->nIntegerPrecision ); // exponent + const tools::Long nI1 = ImplGetI( pElement->nIntegerPrecision ); // mantissa + switch( nUInteger ) + { + case 0 : + pElement->eVDCRealPrecision = RP_FLOAT; + switch ( nI0 ) + { + case 9 : + if ( nI1 != 23 ) + mbStatus = false; + pElement->nVDCRealSize = 4; + break; + case 12 : + if ( nI1 != 52 ) + mbStatus =false; + pElement->nVDCRealSize = 8; + break; + default: + mbStatus = false; + break; + } + break; + case 1 : + pElement->eVDCRealPrecision = RP_FIXED; + if ( nI0 != nI1 ) + mbStatus = false; + if ( nI0 == 16 ) + pElement->nVDCRealSize = 4; + else if ( nI0 == 32 ) + pElement->nVDCRealSize = 8; + else + mbStatus = false; + break; + default : + mbStatus = false; break; + } + } + break; + case 0x03 : /*Auxiliary Colour*/ + { + pElement->nAuxiliaryColor = ImplGetBitmapColor(); + } + break; + case 0x04 : /*Transparency*/ + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eTransparency = T_OFF; break; + case 1 : pElement->eTransparency = T_ON; break; + default : mbStatus = false; break; + } + } + break; + case 0x05 : /*Clip Rectangle*/ + ImplGetRectangle( pElement->aClipRect ); + break; + case 0x06 : /*Clip Indicator*/ + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eClipIndicator = CI_OFF; break; + case 1 : pElement->eClipIndicator = CI_ON; break; + default : mbStatus = false; break; + } + } + break; + case 0x07 : /*Line Clipping Mode */break; // NS + case 0x08 : /*Marker Clipping Mode */break; // NS + case 0x09 : /*Edge Clipping Mode */break; // NS + case 0x0a : /*New Region*/ + mpOutAct->NewRegion(); + break; + case 0x0b : /*Save Primitive Context */break; // NS + case 0x0c : /*Restore Primitive Context */break; // NS + case 0x11 : /*Protection vcl::Region Indicator */break; + case 0x12 : /*Generalized Text Path Mode */break; // NS + case 0x13 : /*Mitre Limit*/ + pElement->nMitreLimit = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + break; // NS + case 0x14 : /*Transparent Cell Color */break; // NS + case 0xfc : /*Text Path Alignment Modes */break; + case 0xfd : /*Pop Transformation Stack */break; + case 0xfe : /*Push Transformation Stack */break; + case 0xff : /*Set Patch ID */break; + default: break; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/class4.cxx b/filter/source/graphicfilter/icgm/class4.cxx new file mode 100644 index 000000000..af66ff26a --- /dev/null +++ b/filter/source/graphicfilter/icgm/class4.cxx @@ -0,0 +1,911 @@ +/* -*- 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 "bitmap.hxx" +#include "cgm.hxx" +#include "chart.hxx" +#include "elements.hxx" +#include "outact.hxx" + +#include +#include + +#include + +using namespace ::com::sun::star; + +double CGM::ImplGetOrientation( FloatPoint const & rCenter, FloatPoint const & rPoint ) +{ + double nX = rPoint.X - rCenter.X; + double nY = rPoint.Y - rCenter.Y; + + double fSqrt = std::hypot(nX, nY); + double fOrientation = fSqrt != 0.0 ? basegfx::rad2deg(acos(nX / fSqrt)) : 0.0; + if (nY > 0) + fOrientation = 360 - fOrientation; + + return fOrientation; +} + + +void CGM::ImplSwitchStartEndAngle( double& rStartAngle, double& rEndAngle ) +{ + double nTemp; + nTemp = rStartAngle; + rStartAngle = rEndAngle; + rEndAngle = nTemp; +} + + +void CGM::ImplGetVector( double* pVector ) +{ + if ( pElement->eVDCType == VDC_REAL ) + { + for ( sal_uInt32 i = 0; i < 4; i++ ) + { + pVector[ i ] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + } + } + else + { + for ( sal_uInt32 i = 0; i < 4; i++ ) + { + pVector[ i ] = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + } + } + pVector[ 0 ] *= mnVDCXmul; + pVector[ 2 ] *= mnVDCXmul; + pVector[ 1 ] *= mnVDCYmul; + pVector[ 3 ] *= mnVDCYmul; +} + + +bool CGM::ImplGetEllipse( FloatPoint& rCenter, FloatPoint& rRadius, double& rAngle ) +{ + FloatPoint aPoint1, aPoint2; + double fRot1, fRot2; + ImplGetPoint( rCenter, true ); + ImplGetPoint( aPoint1, true ); + ImplGetPoint( aPoint2, true ); + fRot1 = ImplGetOrientation( rCenter, aPoint1 ); + fRot2 = ImplGetOrientation( rCenter, aPoint2 ); + rAngle = ImplGetOrientation( rCenter, aPoint1 ); + aPoint1.X -= rCenter.X; + aPoint1.Y -= rCenter.Y; + rRadius.X = std::hypot(aPoint1.X, aPoint1.Y); + aPoint2.X -= rCenter.X; + aPoint2.Y -= rCenter.Y; + rRadius.Y = std::hypot(aPoint2.X, aPoint2.Y); + + if ( fRot1 > fRot2 ) + { + if ( ( fRot1 - fRot2 ) < 180 ) + return false; + } + else + { + if ( ( fRot2 - fRot1 ) > 180 ) + return false; + } + return true; +} + +void CGM::ImplDoClass4() +{ + if ( mbFirstOutPut ) + mpOutAct->FirstOutPut(); + + if ( mpBitmapInUse && ( mnElementID != 9 ) ) // process existed graphic + { // because there are now no pending bitmap actions + CGMBitmapDescriptor* pBmpDesc = mpBitmapInUse->GetBitmap(); + // do anything with the bitmap + mpOutAct->DrawBitmap( pBmpDesc ); + mpBitmapInUse.reset(); + } + + if ( ( mpChart == nullptr ) || mpChart->IsAnnotation() ) + { + switch ( mnElementID ) + { + case 0x01 : /*PolyLine*/ + { + sal_uInt32 nPoints = mnElementSize / ImplGetPointSize(); + tools::Polygon aPolygon( static_cast(nPoints) ); + for ( sal_uInt32 i = 0; i < nPoints; i++) + { + FloatPoint aFloatPoint; + ImplGetPoint( aFloatPoint, true ); + aPolygon.SetPoint( Point( static_cast(aFloatPoint.X), static_cast(aFloatPoint.Y) ), i ); + } + if ( mbFigure ) + mpOutAct->RegPolyLine( aPolygon ); + else + mpOutAct->DrawPolyLine( aPolygon ); + } + break; + + case 0x02 : /*Disjoint PolyLine*/ + { + sal_uInt16 nPoints = sal::static_int_cast< sal_uInt16 >( + mnElementSize / ImplGetPointSize()); + if ( ! ( nPoints & 1 ) ) + { + nPoints >>= 1; + FloatPoint aFloatPoint; + if ( mbFigure ) + { + tools::Polygon aPolygon( nPoints ); + for ( sal_uInt16 i = 0; i < nPoints; i++ ) + { + ImplGetPoint( aFloatPoint, true ); + aPolygon.SetPoint( Point( static_cast(aFloatPoint.X), static_cast(aFloatPoint.Y) ), 0 ); + } + mpOutAct->RegPolyLine( aPolygon ); + } + else + { + mpOutAct->BeginGroup(); + tools::Polygon aPolygon( sal_uInt16(2) ); + for ( sal_uInt16 i = 0; i < nPoints; i++ ) + { + ImplGetPoint( aFloatPoint, true ); + aPolygon.SetPoint( Point( static_cast(aFloatPoint.X), static_cast(aFloatPoint.Y) ), 0 ); + ImplGetPoint( aFloatPoint, true ); + aPolygon.SetPoint( Point( static_cast(aFloatPoint.X), static_cast(aFloatPoint.Y) ), 1); + mpOutAct->DrawPolyLine( aPolygon ); + } + mpOutAct->EndGroup(); + } + } + } + break; + + case 0x03 : /*PolyMarker*/ break; + case 0x04 : /*Text*/ + { + FloatPoint aFloatPoint; + + if ( mbFigure ) + mpOutAct->CloseRegion(); + + ImplGetPoint ( aFloatPoint, true ); + sal_uInt32 nType = ImplGetUI16(); + sal_uInt32 nSize = ImplGetUI( 1 ); + + if (o3tl::make_unsigned(mpEndValidSource - (mpSource + mnParaSize)) < nSize) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + OUString aStr(reinterpret_cast(mpSource) + mnParaSize, nSize, RTL_TEXTENCODING_ASCII_US); + + awt::Size aSize; + awt::Point aPoint( static_cast(aFloatPoint.X), static_cast(aFloatPoint.Y) ); + mpOutAct->DrawText(aPoint, aSize, aStr, static_cast(nType)); + mnParaSize = mnElementSize; + } + break; + + case 0x05 : /*Restricted Text*/ + { + double dx, dy; + FloatPoint aFloatPoint; + + if ( mbFigure ) + mpOutAct->CloseRegion(); + + if ( pElement->eVDCType == VDC_REAL ) + { + dx = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + dy = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + } + else + { + dx = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + dy = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + } + ImplMapDouble( dx ); + ImplMapDouble( dy ); + + ImplGetPoint ( aFloatPoint, true ); + sal_uInt32 nType = ImplGetUI16(); + sal_uInt32 nSize = ImplGetUI(1); + + if (o3tl::make_unsigned(mpEndValidSource - (mpSource + mnParaSize)) < nSize) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + OUString aStr(reinterpret_cast(mpSource) + mnParaSize, nSize, RTL_TEXTENCODING_ASCII_US); + + awt::Point aPoint( static_cast(aFloatPoint.X), static_cast(aFloatPoint.Y) ); + awt::Size aSize(static_cast(dx), static_cast(dy)); + mpOutAct->DrawText(aPoint, aSize , aStr, static_cast(nType)); + mnParaSize = mnElementSize; + } + break; + + case 0x06 : /*Append Text*/ + { + (void)ImplGetUI16(); // nType + sal_uInt32 nSize = ImplGetUI( 1 ); + + if (o3tl::make_unsigned(mpEndValidSource - (mpSource + mnParaSize)) <= nSize) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + mpSource[ mnParaSize + nSize ] = 0; + + mpOutAct->AppendText( reinterpret_cast(mpSource) + mnParaSize ); + mnParaSize = mnElementSize; + } + break; + + case 0x07 : /*Polygon*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + + sal_uInt16 nPoints = sal::static_int_cast< sal_uInt16 >( + mnElementSize / ImplGetPointSize()); + tools::Polygon aPolygon( nPoints ); + for ( sal_uInt16 i = 0; i < nPoints; i++) + { + FloatPoint aFloatPoint; + ImplGetPoint( aFloatPoint, true ); + aPolygon.SetPoint( Point ( static_cast( aFloatPoint.X ), static_cast( aFloatPoint.Y ) ), i ); + } + mpOutAct->DrawPolygon( aPolygon ); + } + break; + + case 0x08 : /*Polygon Set*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + + std::vector aPoints; + tools::PolyPolygon aPolyPolygon; + FloatPoint aFloatPoint; + + while ( mnParaSize < mnElementSize ) + { + ImplGetPoint( aFloatPoint, true ); + sal_uInt32 nEdgeFlag = ImplGetUI16(); + aPoints.push_back(Point(static_cast(aFloatPoint.X), static_cast(aFloatPoint.Y))); + if ( ( nEdgeFlag & 2 ) || ( mnParaSize == mnElementSize ) ) + { + aPolyPolygon.Insert(tools::Polygon(aPoints.size(), aPoints.data())); + aPoints.clear(); + } + } + mpOutAct->DrawPolyPolygon( aPolyPolygon ); + } + break; + + case 0x09 : /*Cell Array*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + + if ( mpBitmapInUse ) + { + std::unique_ptr xBmpDesc(mpBitmapInUse->GetNext()); + if (xBmpDesc) // we possibly get a bitmap back which does not fit to + { // to the previous -> we need to delete this one too + mpOutAct->DrawBitmap(xBmpDesc->GetBitmap()); + } + } + else + { + mpBitmapInUse.reset( new CGMBitmap( *this ) ); + } + } + break; + + case 0x0a : /*Generalized Drawing Primitive*/ + { + ImplGetI( pElement->nIntegerPrecision ); //-Wall is this needed + ImplGetUI( pElement->nIntegerPrecision ); //-Wall is this needed + mnParaSize = mnElementSize; + } + break; + + case 0x0b : /*Rectangle*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + + FloatRect aFloatRect; + ImplGetRectangle( aFloatRect, true ); + mpOutAct->DrawRectangle( aFloatRect ); + } + break; + + case 0x0c : /*Circle*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + + double fRotation = 0; + FloatPoint aCenter, aRadius; + ImplGetPoint( aCenter, true ); + if ( pElement->eVDCType == VDC_REAL ) + aRadius.X = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + else + aRadius.X = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + ImplMapDouble( aRadius.X ); + aRadius.Y = aRadius.X; + mpOutAct->DrawEllipse( aCenter, aRadius, fRotation ); + } + break; + + case 0x0d : /*Circular Arc 3 Point*/ + { + FloatPoint aStartingPoint, aIntermediatePoint, aEndingPoint; + ImplGetPoint( aStartingPoint, true ); + ImplGetPoint( aIntermediatePoint, true ); + ImplGetPoint( aEndingPoint, true ); + + double fA = aIntermediatePoint.X - aStartingPoint.X; + double fB = aIntermediatePoint.Y - aStartingPoint.Y; + double fC = aEndingPoint.X - aStartingPoint.X; + double fD = aEndingPoint.Y - aStartingPoint.Y; + + double fE = fA * ( aStartingPoint.X + aIntermediatePoint.X ) + fB * ( aStartingPoint.Y + aIntermediatePoint.Y ); + double fF = fC * ( aStartingPoint.X + aEndingPoint.X ) + fD * ( aStartingPoint.Y + aEndingPoint.Y ); + + double fG = 2.0 * ( fA * ( aEndingPoint.Y - aIntermediatePoint.Y ) - fB * ( aEndingPoint.X - aIntermediatePoint.X ) ); + + bool bUseless = fG == 0; + + FloatPoint aCenterPoint; + if (!bUseless) + { + aCenterPoint.X = ( fD * fE - fB * fF ) / fG; + aCenterPoint.Y = ( fA * fF - fC * fE ) / fG; + bUseless = useless(aCenterPoint.X) || useless(aCenterPoint.Y); + } + + if (!bUseless) + bUseless = useless(aStartingPoint.X) || useless(aStartingPoint.Y); + + if (!bUseless) + { + double fStartAngle = ImplGetOrientation( aCenterPoint, aStartingPoint ); + double fInterAngle = ImplGetOrientation( aCenterPoint, aIntermediatePoint ); + double fEndAngle = ImplGetOrientation( aCenterPoint, aEndingPoint ); + + int nSwitch = 0; + + if ( fStartAngle > fEndAngle ) + { + nSwitch ^=1; + aIntermediatePoint = aEndingPoint; + aEndingPoint = aStartingPoint; + aStartingPoint = aIntermediatePoint; + fG = fStartAngle; + fStartAngle = fEndAngle; + fEndAngle = fG; + } + if ( ! ( fInterAngle > fStartAngle ) && ( fInterAngle < fEndAngle ) ) + { + nSwitch ^=1; + aIntermediatePoint = aEndingPoint; + aEndingPoint = aStartingPoint; + aStartingPoint = aIntermediatePoint; + fG = fStartAngle; + fStartAngle = fEndAngle; + fEndAngle = fG; + } + double fRadius = std::hypot(aStartingPoint.X - aCenterPoint.X, aStartingPoint.Y - aCenterPoint.Y); + + if ( mbFigure ) + { + double fLeft = aCenterPoint.X - fRadius; + double fTop = aCenterPoint.Y - fRadius; + double fRight = fLeft + (2 * fRadius); + double fBottom = fTop + (2 * fRadius); + bUseless = useless(fLeft) || useless(fTop) || useless(2 * fRadius) || useless(fRight) || useless(fBottom); + if (!bUseless) + { + double fCenterCalc = fLeft + fRight; + bUseless = !o3tl::convertsToAtLeast(fCenterCalc, std::numeric_limits::min()) || + !o3tl::convertsToAtMost(fCenterCalc, std::numeric_limits::max()); + } + if (!bUseless) + { + double fCenterCalc = fTop + fBottom; + bUseless = !o3tl::convertsToAtLeast(fCenterCalc, std::numeric_limits::min()) || + !o3tl::convertsToAtMost(fCenterCalc, std::numeric_limits::max()); + } + if (!bUseless) + { + tools::Rectangle aBoundingBox(Point(fLeft, fTop), Size(2 * fRadius, 2 * fRadius)); + tools::Polygon aPolygon( aBoundingBox, Point( static_cast(aStartingPoint.X), static_cast(aStartingPoint.Y) ) ,Point( static_cast(aEndingPoint.X), static_cast(aEndingPoint.Y) ), PolyStyle::Arc ); + if ( nSwitch ) + mpOutAct->RegPolyLine( aPolygon, true ); + else + mpOutAct->RegPolyLine( aPolygon ); + } + } + else + { + fG = 0; + FloatPoint aRadius; + aRadius.X = aRadius.Y = fRadius; + mpOutAct->DrawEllipticalArc( aCenterPoint, aRadius, fG, 2, fStartAngle, fEndAngle ); + } + } + } + break; + + case 0x0e : /*Circular Arc 3 Point Close*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + + FloatPoint aStartingPoint, aIntermediatePoint, aEndingPoint; + ImplGetPoint( aStartingPoint ); + ImplGetPoint( aIntermediatePoint ); + ImplGetPoint( aEndingPoint ); + + double fA = aIntermediatePoint.X - aStartingPoint.X; + double fB = aIntermediatePoint.Y - aStartingPoint.Y; + double fC = aEndingPoint.X - aStartingPoint.X; + double fD = aEndingPoint.Y - aStartingPoint.Y; + + double fE = fA * ( aStartingPoint.X + aIntermediatePoint.X ) + fB * ( aStartingPoint.Y + aIntermediatePoint.Y ); + double fF = fC * ( aStartingPoint.X + aEndingPoint.X ) + fD * ( aStartingPoint.Y + aEndingPoint.Y ); + + double fG = 2.0 * ( fA * ( aEndingPoint.Y - aIntermediatePoint.Y ) - fB * ( aEndingPoint.X - aIntermediatePoint.X ) ); + + if ( fG != 0 ) + { + FloatPoint aCenterPoint; + aCenterPoint.X = ( fD * fE - fB * fF ) / fG; + aCenterPoint.Y = ( fA * fF - fC * fE ) / fG; + double fStartAngle = ImplGetOrientation( aCenterPoint, aStartingPoint ); + double fInterAngle = ImplGetOrientation( aCenterPoint, aIntermediatePoint ); + double fEndAngle = ImplGetOrientation( aCenterPoint, aEndingPoint ); + + if ( fStartAngle > fEndAngle ) + { + aIntermediatePoint = aEndingPoint; + aEndingPoint = aStartingPoint; + aStartingPoint = aIntermediatePoint; + fG = fStartAngle; + fStartAngle = fEndAngle; + fEndAngle = fG; + } + if ( ! ( fInterAngle > fStartAngle ) && ( fInterAngle < fEndAngle ) ) + { + aIntermediatePoint = aEndingPoint; + aEndingPoint = aStartingPoint; + aStartingPoint = aIntermediatePoint; + fG = fStartAngle; + fStartAngle = fEndAngle; + fEndAngle = fG; + } + FloatPoint fRadius; + fRadius.Y = fRadius.X = std::hypot(aStartingPoint.X - aCenterPoint.X, aStartingPoint.Y - aCenterPoint.Y); + + sal_uInt32 nType = ImplGetUI16(); + if ( nType == 0 ) + nType = 0; // is PIE + else + nType = 1; // is CHORD + + double fOrientation = 0; + mpOutAct->DrawEllipticalArc( aCenterPoint, fRadius, fOrientation, nType, fStartAngle, fEndAngle ); + } + } + break; + + case 0x0f : /*Circular Arc Centre*/ + { + double fStartAngle, fEndAngle, vector[ 4 ]; + FloatPoint aCenter, aRadius; + + if ( mbFigure ) + mpOutAct->CloseRegion(); + + ImplGetPoint( aCenter, true ); + ImplGetVector( &vector[ 0 ] ); + + if ( pElement->eVDCType == VDC_REAL ) + { + aRadius.X = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + } + else + { + aRadius.X = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + } + + ImplMapDouble( aRadius.X ); + aRadius.Y = aRadius.X; + + bool bUseless = useless(vector[0]) || useless(vector[1]) || useless(vector[2]) || useless(vector[3]); + if (!bUseless) + { + const double fStartSqrt = std::hypot(vector[0], vector[1]); + fStartAngle = fStartSqrt != 0.0 ? basegfx::rad2deg(acos(vector[0] / fStartSqrt)) : 0.0; + const double fEndSqrt = std::hypot(vector[2], vector[3]); + fEndAngle = fEndSqrt != 0.0 ? basegfx::rad2deg(acos(vector[ 2 ] / fEndSqrt)) : 0.0; + + if ( vector[ 1 ] > 0 ) + fStartAngle = 360 - fStartAngle; + if ( vector[ 3 ] > 0 ) + fEndAngle = 360 - fEndAngle; + + if ( mbAngReverse ) + ImplSwitchStartEndAngle( fStartAngle, fEndAngle ); + + if ( mbFigure ) + { + double fLeft = aCenter.X - aRadius.X; + double fTop = aCenter.Y - aRadius.X; + double fRight = fLeft + (2 * aRadius.X); + double fBottom = fTop + (2 * aRadius.X); + bUseless = useless(fLeft) || useless(fTop) || useless(2 * aRadius.X) || useless(fRight) || useless(fBottom); + if (!bUseless) + { + double fCenterCalc = fLeft + fRight; + bUseless = !o3tl::convertsToAtLeast(fCenterCalc, std::numeric_limits::min()) || + !o3tl::convertsToAtMost(fCenterCalc, std::numeric_limits::max()); + } + if (!bUseless) + { + double fCenterCalc = fTop + fBottom; + bUseless = !o3tl::convertsToAtLeast(fCenterCalc, std::numeric_limits::min()) || + !o3tl::convertsToAtMost(fCenterCalc, std::numeric_limits::max()); + } + if (!bUseless) + { + tools::Rectangle aBoundingBox(Point(fLeft, fTop), Size(2 * aRadius.X, 2 * aRadius.X)); + tools::Polygon aPolygon( aBoundingBox, + Point( static_cast(vector[ 0 ]), static_cast(vector[ 1 ]) ), + Point( static_cast(vector[ 2 ]), static_cast(vector[ 3 ]) ), PolyStyle::Arc ); + mpOutAct->RegPolyLine( aPolygon ); + } + } + else + { + double fOrientation = 0; + mpOutAct->DrawEllipticalArc( aCenter, aRadius, fOrientation, 2, fStartAngle, fEndAngle ); + } + } + + mnParaSize = mnElementSize; + } + break; + + case 0x10 : /*Circular Arc Centre Close*/ + { + double fOrientation, vector[ 4 ]; + FloatPoint aCenter, aRadius; + + if ( mbFigure ) + mpOutAct->CloseRegion(); + + ImplGetPoint( aCenter, true ); + ImplGetVector( &vector[ 0 ] ); + if ( pElement->eVDCType == VDC_REAL ) + { + aRadius.X = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + } + else + { + aRadius.X = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + } + ImplMapDouble( aRadius.X ); + aRadius.Y = aRadius.X; + + sal_uInt32 nType = ImplGetUI16(); + + bool bUseless = useless(vector[0]) || useless(vector[1]) || useless(vector[2]) || useless(vector[3]); + if (!bUseless) + { + const double fStartSqrt = std::hypot(vector[0], vector[1]); + double fStartAngle = fStartSqrt ? basegfx::rad2deg(acos(vector[0] / fStartSqrt)) : 0.0; + const double fEndSqrt = std::hypot(vector[2], vector[3]); + double fEndAngle = fEndSqrt ? basegfx::rad2deg(acos(vector[2] / fEndSqrt)) : 0.0; + + if ( vector[ 1 ] > 0 ) + fStartAngle = 360 - fStartAngle; + if ( vector[ 3 ] > 0 ) + fEndAngle = 360 - fEndAngle; + + if ( mbAngReverse ) + ImplSwitchStartEndAngle( fStartAngle, fEndAngle ); + + if ( nType == 0 ) + nType = 0; // is PIE + else + nType = 1; // is CHORD + fOrientation = 0; + + mpOutAct->DrawEllipticalArc( aCenter, aRadius, fOrientation, + nType, fStartAngle, fEndAngle ); + } + + mnParaSize = mnElementSize; + } + break; + + case 0x11 : /*Ellipse*/ + { + double fOrientation; + FloatPoint aCenter, aRadius; + + if ( mbFigure ) + mpOutAct->CloseRegion(); + + ImplGetEllipse( aCenter, aRadius, fOrientation ) ; + mpOutAct->DrawEllipse( aCenter, aRadius, fOrientation ) ; + } + break; + + case 0x12 : /*Elliptical Arc*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + + double fOrientation, fStartAngle, fEndAngle, vector[ 4 ]; + FloatPoint aCenter, aRadius; + + if ( mbFigure ) + mpOutAct->CloseRegion(); + + bool bDirection = ImplGetEllipse( aCenter, aRadius, fOrientation ); + ImplGetVector( &vector[ 0 ] ); + + bool bUseless = useless(vector[0]) || useless(vector[1]) || useless(vector[2]) || useless(vector[3]); + if (!bUseless) + { + double fStartSqrt = std::hypot(vector[0], vector[1]); + fStartAngle = fStartSqrt ? basegfx::rad2deg(acos(vector[0] / fStartSqrt)) : 0.0; + double fEndSqrt = std::hypot(vector[2], vector[3]); + fEndAngle = fEndSqrt ? basegfx::rad2deg(acos(vector[2] / fEndSqrt)) : 0.0; + + if ( vector[ 1 ] > 0 ) + fStartAngle = 360 - fStartAngle; + if ( vector[ 3 ] > 0 ) + fEndAngle = 360 - fEndAngle; + + if ( bDirection ) + mpOutAct->DrawEllipticalArc( aCenter, aRadius, fOrientation, + 2, fStartAngle, fEndAngle ); + else + mpOutAct->DrawEllipticalArc( aCenter, aRadius, fOrientation, + 2, fEndAngle, fStartAngle); + } + } + break; + + case 0x13 : /*Elliptical Arc Close*/ + { + double fOrientation, fStartAngle, fEndAngle, vector[ 4 ]; + FloatPoint aCenter, aRadius; + + if ( mbFigure ) + mpOutAct->CloseRegion(); + + bool bDirection = ImplGetEllipse( aCenter, aRadius, fOrientation ); + ImplGetVector( &vector[ 0 ] ); + + sal_uInt32 nType = ImplGetUI16(); + + bool bUseless = useless(vector[0]) || useless(vector[1]) || useless(vector[2]) || useless(vector[3]); + if (!bUseless) + { + double fStartSqrt = std::hypot(vector[0], vector[1]); + fStartAngle = fStartSqrt ? basegfx::rad2deg(acos(vector[0] / fStartSqrt)) : 0.0; + double fEndSqrt = std::hypot(vector[2], vector[3]); + fEndAngle = fEndSqrt ? basegfx::rad2deg(acos(vector[2] / fEndSqrt)) : 0.0; + + if ( vector[ 1 ] > 0 ) + fStartAngle = 360 - fStartAngle; + if ( vector[ 3 ] > 0 ) + fEndAngle = 360 - fEndAngle; + + if ( nType == 0 ) + nType = 0; // is PIE + else + nType = 1; // is CHORD + + if ( bDirection ) + mpOutAct->DrawEllipticalArc( aCenter, aRadius, fOrientation, + nType, fStartAngle, fEndAngle ); + else + mpOutAct->DrawEllipticalArc( aCenter, aRadius, fOrientation, + nType, fEndAngle, fStartAngle); + } + } + break; + case 0x14 : /*Circular Arc Centre Reversed*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x15 : /*Connection Edge */ // NS + { +// if ( mbFigure ) +// mpOutAct->CloseRegion(); + } + break; + case 0x16 : /*Hyperbolic Arc */ // NS + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x17 : /*Parabolic Arc */ // NS + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x18 : /*Non Uniform B-Spline */ // NS + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x19 : /*Non Uniform Rational B-Spline */ // NS + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x1a : /*Polybezier*/ + { + sal_uInt32 nOrder = ImplGetI( pElement->nIntegerPrecision ); + + sal_uInt16 nNumberOfPoints = sal::static_int_cast< sal_uInt16 >(( mnElementSize - pElement->nIntegerPrecision ) / ImplGetPointSize()); + + tools::Polygon aPolygon( nNumberOfPoints ); + + for ( sal_uInt16 i = 0; i < nNumberOfPoints; i++) + { + FloatPoint aFloatPoint; + ImplGetPoint( aFloatPoint, true ); + aPolygon.SetPoint( Point ( static_cast( aFloatPoint.X ), static_cast( aFloatPoint.Y ) ), i ); + } + if ( nOrder & 4 ) + { + for ( sal_uInt16 i = 0; i < nNumberOfPoints; i++ ) + { + if ( ( i % 3 ) == 0 ) + aPolygon.SetFlags( i, PolyFlags::Normal ); + else + aPolygon.SetFlags( i, PolyFlags::Control ); + } + } + else + { + for ( sal_uInt16 i = 0; i < nNumberOfPoints; i++ ) + { + switch ( i & 3 ) + { + case 0 : + case 3 : aPolygon.SetFlags( i, PolyFlags::Normal ); break; + default : aPolygon.SetFlags( i, PolyFlags::Control ); break; + } + } + } + if ( mbFigure ) + mpOutAct->RegPolyLine( aPolygon ); + else + mpOutAct->DrawPolybezier( aPolygon ); + mnParaSize = mnElementSize; + } + break; + + case 0x1b : /*Polysymbol */ // NS + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x1c : /*Bitonal Tile */ // NS + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x1d : /*Tile */ // NS + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0x1e : /*Insert Object*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xff : /*Polybezier*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xfe : /*Sharp Polybezier*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xfd : /*Polyspline*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xfc : /*Rounded Rectangle*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xfb : /*Begin Cell Array*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xfa : /*End Cell Array*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xf9 : /*Insert File*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xf8 : /*Block Text*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xf7 : /*Variable Width Polyline*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xf6 : /*Elliptical Arc 3 Point*/ + { + if ( mbFigure ) + mpOutAct->CloseRegion(); + } + break; + case 0xf1 : /*Hyperlink Definition */break; + default: break; + } + } + else + mnParaSize = mnElementSize; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/class5.cxx b/filter/source/graphicfilter/icgm/class5.cxx new file mode 100644 index 000000000..7cfd9911c --- /dev/null +++ b/filter/source/graphicfilter/icgm/class5.cxx @@ -0,0 +1,532 @@ +/* -*- 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 . + */ + +//#define VCL_NEED_BASETSD + +#include +#include "cgm.hxx" +#include "elements.hxx" +#include "outact.hxx" + +void CGM::ImplDoClass5() +{ + switch ( mnElementID ) + { + case 0x01 : /*Line Bundle Index*/ + pElement->pLineBundle = static_cast(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aLineList, pElement->aLineBundle )); + break; + case 0x02 : /*Line Type*/ + { + if ( pElement->nAspectSourceFlags & ASF_LINETYPE ) + pElement->pLineBundle->eLineType = static_cast(ImplGetI( pElement->nIndexPrecision )); + else + pElement->aLineBundle.eLineType = static_cast(ImplGetI( pElement->nIndexPrecision )); + } + break; + case 0x03 : /*Line Width*/ + { + double nWidth; + if ( pElement->eLineWidthSpecMode == SM_ABSOLUTE ) + { + if ( pElement->eVDCType == VDC_REAL ) + nWidth = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + else + nWidth = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + + ImplMapDouble( nWidth ); + } + else + nWidth = static_cast(ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize )) * 25; // scaling in 1/4 mm + + if ( pElement->nAspectSourceFlags & ASF_LINEWIDTH ) + pElement->pLineBundle->nLineWidth = nWidth; + else + pElement->aLineBundle.nLineWidth = nWidth; + } + break; + case 0x04 : /*Line Color*/ + { + if ( pElement->nAspectSourceFlags & ASF_LINECOLOR ) + pElement->pLineBundle->SetColor( ImplGetBitmapColor() ); + else + pElement->aLineBundle.SetColor( ImplGetBitmapColor() ); + } + break; + case 0x05 : /*Marker Bundle Index*/ + pElement->pMarkerBundle = static_cast(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aMarkerList, pElement->aMarkerBundle )); + break; + case 0x06 : /*Marker Type*/ + { + if ( pElement->nAspectSourceFlags & ASF_MARKERTYPE ) + pElement->pMarkerBundle->eMarkerType = static_cast(ImplGetI( pElement->nIndexPrecision )); + else + pElement->aMarkerBundle.eMarkerType = static_cast(ImplGetI( pElement->nIndexPrecision )); + } + break; + case 0x07 : /*Marker Size*/ + { + double nWidth; + if ( pElement->eMarkerSizeSpecMode == SM_ABSOLUTE ) + { + if ( pElement->eVDCType == VDC_REAL ) + nWidth = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + else + nWidth = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + ImplMapDouble( nWidth ); + } + else + nWidth = static_cast(ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize )) * 25; + if ( pElement->nAspectSourceFlags & ASF_MARKERSIZE ) + pElement->pMarkerBundle->nMarkerSize = nWidth; + else + pElement->aMarkerBundle.nMarkerSize = nWidth; + } + break; + case 0x08 : /*Marker Color*/ + { + if ( pElement->nAspectSourceFlags & ASF_MARKERCOLOR ) + pElement->pMarkerBundle->SetColor( ImplGetBitmapColor() ); + else + pElement->aMarkerBundle.SetColor( ImplGetBitmapColor() ); + } + break; + case 0x09 : /*Text Bundle Index*/ + pElement->pTextBundle = static_cast(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aTextList, pElement->aTextBundle )); + break; + case 0x0a : /*Text Font Index*/ + { + if ( pElement->nAspectSourceFlags & ASF_TEXTFONTINDEX ) + pElement->pTextBundle->nTextFontIndex = ImplGetI( pElement->nIndexPrecision ); + else + pElement->aTextBundle.nTextFontIndex = ImplGetI( pElement->nIndexPrecision ); + } + break; + case 0x0b : /*Text Precision*/ + { + TextBundle* pBundle; + if ( pElement->nAspectSourceFlags & ASF_TEXTPRECISION ) + pBundle = pElement->pTextBundle; + else + pBundle = &pElement->aTextBundle; + switch( ImplGetUI16() ) + { + case 0 : pBundle->eTextPrecision = TPR_STRING; break; + case 1 : pBundle->eTextPrecision = TPR_CHARACTER; break; + case 2 : pBundle->eTextPrecision = TPR_STROKE; break; + default : pBundle->eTextPrecision = TPR_UNDEFINED; break; + } + } + break; + case 0x0c : /*Character Expansion Factor*/ + { + if ( pElement->nAspectSourceFlags & ASF_CHARACTEREXPANSION ) + pElement->pTextBundle->nCharacterExpansion = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + else + pElement->aTextBundle.nCharacterExpansion = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + } + break; + case 0x0d : /*Character Spacing*/ + { + if ( pElement->nAspectSourceFlags & ASF_CHARACTERSPACING ) + pElement->pTextBundle->nCharacterSpacing = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + else + pElement->aTextBundle.nCharacterSpacing = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + } + break; + case 0x0e : /*Text Color*/ + { + if ( pElement->nAspectSourceFlags & ASF_TEXTCOLOR ) + pElement->pTextBundle->SetColor( ImplGetBitmapColor() ); + else + pElement->aTextBundle.SetColor( ImplGetBitmapColor() ); + } + break; + case 0x0f : /*Character Height*/ + { + if ( pElement->eVDCType == VDC_INTEGER ) + pElement->nCharacterHeight = ImplGetI( pElement->nVDCIntegerPrecision ); + else // ->floating points + pElement->nCharacterHeight = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + ImplMapDouble( pElement->nCharacterHeight ); + pElement->nCharacterHeight /= 18.0; + } + break; + case 0x10 : /*Character Orientation*/ + { + if ( pElement->eVDCType == VDC_INTEGER ) + { + pElement->nCharacterOrientation[0] = ImplGetI( pElement->nVDCIntegerPrecision ); + pElement->nCharacterOrientation[1] = ImplGetI( pElement->nVDCIntegerPrecision ); + pElement->nCharacterOrientation[2] = ImplGetI( pElement->nVDCIntegerPrecision ); + pElement->nCharacterOrientation[3] = ImplGetI( pElement->nVDCIntegerPrecision ); + } + else // ->floating points + { + pElement->nCharacterOrientation[0] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + pElement->nCharacterOrientation[1] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + pElement->nCharacterOrientation[2] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + pElement->nCharacterOrientation[3] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + } + } + break; + case 0x11 : /*Text Path*/ + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eTextPath = TPR_RIGHT; break; + case 1 : pElement->eTextPath = TPR_LEFT; break; + case 2 : pElement->eTextPath = TPR_UP; break; + case 3 : pElement->eTextPath = TPR_DOWN; break; + default : mbStatus = false; break; + } + } + break; + case 0x12 : /*Text Alignment*/ + { + auto nTextAlign = ImplGetUI16(); + if (nTextAlign > TextAlignmentH::TAH_CONT) + SAL_WARN("filter.icgm", "TextAlign out of range"); + else + pElement->eTextAlignmentH = static_cast(nTextAlign); + nTextAlign = ImplGetUI16(); + if (nTextAlign > TextAlignmentV::TAV_CONT) + SAL_WARN("filter.icgm", "TextAlign out of range"); + else + pElement->eTextAlignmentV = static_cast(nTextAlign); + pElement->nTextAlignmentHCont = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + pElement->nTextAlignmentVCont = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); + } + break; + case 0x13 : /*Character Set Index*/ + pElement->nCharacterSetIndex = ImplGetI( pElement->nIndexPrecision ); + break; + case 0x14 : /*Alternate Character Set Index*/ + pElement->nAlternateCharacterSetIndex = ImplGetI( pElement->nIndexPrecision ); + break; + case 0x15 : /*Fill Bundle Index*/ + pElement->pFillBundle = static_cast(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aFillList, pElement->aFillBundle )); + break; + case 0x16 : /*Fill Interior Style*/ + { + if ( pElement->nAspectSourceFlags & ASF_FILLINTERIORSTYLE ) + pElement->pFillBundle->eFillInteriorStyle = static_cast(ImplGetUI16()); + else + pElement->aFillBundle.eFillInteriorStyle = static_cast(ImplGetUI16()); + } + break; + case 0x17 : /*Fill Color*/ + { + if ( pElement->nAspectSourceFlags & ASF_FILLCOLOR ) + pElement->pFillBundle->SetColor( ImplGetBitmapColor() ); + else + pElement->aFillBundle.SetColor( ImplGetBitmapColor() ); + } + break; + case 0x18 : /*Fill Hatch Index*/ + { + if ( pElement->nAspectSourceFlags & ASF_HATCHINDEX ) + pElement->pFillBundle->nFillHatchIndex = ImplGetI( pElement->nIndexPrecision ); + else + pElement->aFillBundle.nFillHatchIndex = ImplGetI( pElement->nIndexPrecision ); + } + break; + case 0x19 : /*Fill Pattern Index*/ + { + if ( pElement->nAspectSourceFlags & ASF_PATTERNINDEX ) + pElement->pFillBundle->nFillPatternIndex = ImplGetI( pElement->nIndexPrecision ); + else + pElement->aFillBundle.nFillPatternIndex = ImplGetI( pElement->nIndexPrecision ); + } + break; + case 0x1a : /*Edge Bundle Index*/ + pElement->pEdgeBundle = static_cast(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aEdgeList, pElement->aEdgeBundle )); + break; + case 0x1b : /*Edge Type*/ + { + if ( pElement->nAspectSourceFlags & ASF_EDGETYPE ) + pElement->pEdgeBundle->eEdgeType = static_cast(ImplGetI( pElement->nIndexPrecision )); + else + pElement->aEdgeBundle.eEdgeType = static_cast(ImplGetI( pElement->nIndexPrecision )); + } + break; + case 0x1c : /*Edge Width*/ + { + double nWidth; + if ( pElement->eEdgeWidthSpecMode == SM_ABSOLUTE ) + { + if ( pElement->eVDCType == VDC_REAL ) + nWidth = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize ); + else + nWidth = static_cast(ImplGetI( pElement->nVDCIntegerPrecision )); + + ImplMapDouble( nWidth ); + } + else + nWidth = static_cast(ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize )) * 25; + if ( pElement->nAspectSourceFlags & ASF_EDGEWIDTH ) + pElement->pEdgeBundle->nEdgeWidth = nWidth; + else + pElement->aEdgeBundle.nEdgeWidth = nWidth; + } + break; + case 0x1d : /*Edge Color*/ + { + if ( pElement->nAspectSourceFlags & ASF_EDGECOLOR ) + pElement->pEdgeBundle->SetColor( ImplGetBitmapColor() ); + else + pElement->aEdgeBundle.SetColor( ImplGetBitmapColor() ); + } + break; + case 0x1e : /*Edge Visibility*/ + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eEdgeVisibility = EV_OFF; break; + case 1 : pElement->eEdgeVisibility = EV_ON; break; + default : mbStatus = false; + } + } + break; + case 0x1f : /*Fill Reference Point*/ + ImplGetPoint( pElement->aFillRefPoint ); + break; + case 0x20 : /*Pattern Table" )*/ break; + case 0x21 : /*Pattern Size" )*/ break; + case 0x22 : /*Color Table*/ + { + sal_uInt32 nColorStartIndex = ImplGetUI( pElement->nColorIndexPrecision ); + if ( ( nColorStartIndex > 255 ) || + ( ( ( mnElementSize - pElement->nColorIndexPrecision ) % ( pElement->nColorPrecision * 3 ) ) != 0 ) ) + { + mbStatus = false; + } + else + { + sal_uInt32 nColors = ( mnElementSize - pElement->nColorIndexPrecision ) / ( 3 * pElement->nColorPrecision ); + if ( nColors ) + { + sal_uInt32 nMaxColorIndex = nColorStartIndex + nColors - 1; + sal_uInt32 nIndex; + if ( nMaxColorIndex > 255 ) + { + mbStatus = false; + break; + } + if ( pElement->nLatestColorMaximumIndex < nMaxColorIndex ) + pElement->nLatestColorMaximumIndex = nMaxColorIndex; + + for ( nIndex = nColorStartIndex; nIndex <= nMaxColorIndex; nIndex++ ) + { + pElement->aLatestColorTable[ nIndex ] = ImplGetBitmapColor( true ); + } + + pElement->nColorMaximumIndex = pElement->nLatestColorMaximumIndex; + for ( nIndex = nColorStartIndex; nIndex <= nMaxColorIndex; nIndex++ ) + { + if ( !pElement->aColorTableEntryIs[ nIndex ] ) + { + pElement->aColorTableEntryIs[ nIndex ] = 1; + pElement->aColorTable[ nIndex ] = pElement->aLatestColorTable[ nIndex ]; + } + } + } + } + } + break; + case 0x23 : /*Aspect Source Flags*/ + { + int nFlags = mnElementSize >> 2; + while ( nFlags-- > 0 ) + { + sal_uInt32 nFlag = 0; + switch( ImplGetUI16() ) + { + case 0 : nFlag = ASF_LINETYPE; break; + case 1 : nFlag = ASF_LINEWIDTH; break; + case 2 : nFlag = ASF_LINECOLOR; break; + case 3 : nFlag = ASF_MARKERTYPE; break; + case 4 : nFlag = ASF_MARKERSIZE; break; + case 5 : nFlag = ASF_MARKERCOLOR; break; + case 6 : nFlag = ASF_FILLINTERIORSTYLE; break; + case 7 : nFlag = ASF_HATCHINDEX; break; + case 8 : nFlag = ASF_PATTERNINDEX; break; + case 9 : nFlag = ASF_BITMAPINDEX; break; + case 10 : nFlag = ASF_FILLCOLOR; break; + case 11 : nFlag = ASF_EDGETYPE; break; + case 12 : nFlag = ASF_EDGEWIDTH; break; + case 13 : nFlag = ASF_EDGECOLOR; break; + case 14 : nFlag = ASF_TEXTFONTINDEX; break; + case 15 : nFlag = ASF_TEXTPRECISION; break; + case 16 : nFlag = ASF_CHARACTEREXPANSION; break; + case 17 : nFlag = ASF_CHARACTERSPACING; break; + case 18 : nFlag = ASF_TEXTCOLOR; break; + default : mbStatus = false; break; + } + sal_uInt32 nASF = ImplGetUI16(); + switch ( nASF ) + { + case 0 : pElement->nAspectSourceFlags &= ~nFlag; break; // INDIVIDUAL + case 1 : pElement->nAspectSourceFlags |= nFlag; break; // BUNDLED + default : mbStatus = false; break; + } + } + } + break; + case 0x24 : /*Pick Identifier*/ break; + case 0x25 : /*Line Cap*/ + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eLineCapType = LCT_BUTT; break; + case 1 : pElement->eLineCapType = LCT_ROUND; break; + case 2 : pElement->eLineCapType = LCT_SQUARE; break; + case 3 : pElement->eLineCapType = LCT_TRIANGLE; break; + case 4 : pElement->eLineCapType = LCT_ARROW; break; + default : pElement->eLineCapType = LCT_NONE; break; + } + } + break; + case 0x26 : /*Line Join*/ + { + switch( ImplGetUI16() ) + { + case 0 : pElement->eLineJoinType = LJT_MITER; break; + case 1 : pElement->eLineJoinType = LJT_ROUND; break; + case 2 : pElement->eLineJoinType = LJT_BEVEL; break; + default : pElement->eLineJoinType = LJT_NONE; break; + } + } + break; + case 0x27 : /*Line Type Continuation*/ break; // NS + case 0x28 : /*Line Type Initial Offset*/ break; // NS + case 0x29 : /*Text Score Type*/ break; + case 0x2a : /*Restricted Text Type*/ break; + case 0x2b : /*Interpolated interior*/ break; + case 0x2c : /*Edge Cap*/ break; // NS + case 0x2d : /*Edge Join*/ break; + case 0x2e : /*Edge Type Continuation*/ break; // NS + case 0x2f : /*Edge Type Initial Offset*/ break; // NS + case 0x30 : /*Symbol Library Index*/ break; // NS + case 0x31 : /*Symbol Color*/ break; // NS + case 0x32 : /*Symbol Size*/ break; // NS + case 0x33 : /*Symbol Orientation*/ break; // NS + case 0x50 : /*Block Text vcl::Region Margins*/ break; + case 0x51 : /*Block Text vcl::Region Expansion*/ break; + case 0x52 : /*Block Text vcl::Region Anchor*/ break; + case 0x53 : /*Block Text Paragraph Horizontal Alignment*/ break; + case 0x54 : /*Block Text Paragraph Vertical Alignment*/ break; + case 0x55 : /*Block Text Line Flow*/ break; + case 0x60 : /*Block Text Paragraph Spacing*/ break; + case 0x61 : /*Block Text Paragraph Indent*/ break; + case 0x62 : /*Block Text Paragraph Tabs*/ break; + case 0x63 : /*Block Text Paragraph Bullets*/ break; + case 0x64 : /*Block Text Paragraph Bullet Level*/ break; + case 0x65 : /*Block Text Paragraph Line Horizontal Alignment*/ break; + case 0x66 : /*Block Text Paragraph Line Vertical Alignment*/ break; + case 0x67 : /*Block Text Paragragh Line Spacing*/ break; + case 0x68 : /*Block Text Paragraph Word Wrap*/ break; + case 0x70 : /*Block Text Forward Advance Distance*/ break; + case 0x71 : /*Word Spacing*/ break; + case 0x72 : /*External Leading*/ break; + case 0x7a : /*set Gradient Offset*/ + { + tools::Long nHorzOffset = ImplGetI( pElement->nIndexPrecision ); + tools::Long nVertOffset = ImplGetI( pElement->nIndexPrecision ); + (void)ImplGetUI16(); // nType + mpOutAct->SetGradientOffset( nHorzOffset, nVertOffset ); + mnAct4PostReset |= ACT4_GRADIENT_ACTION; + } + break; + case 0x7b : /*set Gradient Edge*/ + { + mnAct4PostReset |= ACT4_GRADIENT_ACTION; + } + break; + case 0x7c : /*set Gradient Angle*/ + { + mpOutAct->SetGradientAngle( ImplGetI( pElement->nIndexPrecision ) ); + mnAct4PostReset |= ACT4_GRADIENT_ACTION; + } + break; + case 0x7d : /*set Gradient Description*/ + { + ImplGetI( pElement->nIndexPrecision ); // -Wall is this needed? + sal_uInt32 nNumberOfStages = ImplGetI( pElement->nIndexPrecision ); + sal_uInt32 i, nColorFrom = 0; + sal_uInt32 nColorTo = 0xffffff; + + const size_t nRemainingSize = mpEndValidSource - (mpSource + mnParaSize); + const size_t nMaxPossibleRecords = nRemainingSize/pElement->nRealSize; + + if (nNumberOfStages > nMaxPossibleRecords) + { + mbStatus = false; + break; + } + + for ( i = 0; i < nNumberOfStages; i++ ) + { + ImplGetFloat(pElement->eRealPrecision, pElement->nRealSize); + } + + for ( i = 0; i <= nNumberOfStages; i++ ) + { + sal_uInt32 nPara = mnParaSize + 24; + if ( i == 0 ) + { + nColorTo = ImplGetBitmapColor(); + nColorFrom = nColorTo ^ 0xffffff; + } + else if ( i == 1 ) + nColorFrom = ImplGetBitmapColor(); + mnParaSize = nPara; + } + if ( nNumberOfStages > 1 ) + mpOutAct->SetGradientStyle( 0xff ); + + mpOutAct->SetGradientDescriptor( nColorFrom, nColorTo ); + mnAct4PostReset |= ACT4_GRADIENT_ACTION; + } + break; + case 0x7e : /*set Gradient Style*/ + { + sal_uInt32 nStyle = ImplGetUI16(); + (void)ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); // fRatio + mpOutAct->SetGradientStyle( nStyle ); + mnAct4PostReset |= ACT4_GRADIENT_ACTION; + } + break; + case 0xff : /*inquire Font metrics*/ break; + case 0xfe : /*inquire character widths*/ break; + case 0xfd : /*set Text Font*/ break; + case 0xfc : /*set current position*/ break; + case 0xfb : /*set current position mode*/ break; + case 0xfa : /*set character height mode*/ break; + case 0xf9 : /*set Transform matrix 2D*/ break; + case 0xf8 : /*set Transform matrix 3D*/ break; + case 0xf7 : /*pop transformation state*/ break; + case 0xf6 : /*clear transformation state*/ break; + case 0xf5 : /*set character widths*/ break; + case 0xf4 : /*set color name - for Pantone support*/ break; + default: break; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/class7.cxx b/filter/source/graphicfilter/icgm/class7.cxx new file mode 100644 index 000000000..63bce3296 --- /dev/null +++ b/filter/source/graphicfilter/icgm/class7.cxx @@ -0,0 +1,210 @@ +/* -*- 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 + +#include + +#include "cgm.hxx" +#include "chart.hxx" +#include "outact.hxx" + + +void CGM::ImplDoClass7() +{ + switch ( mnElementID ) + { + case 0x01 : /*Message */break; + case 0x02 : + { + if (mpEndValidSource - mpSource < 12) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + sal_uInt16* pTemp = reinterpret_cast(mpSource); + sal_uInt16 nOpcode = pTemp[ 4 ]; + + sal_uInt8* pAppData = mpSource + 12; + + if ( mpChart || ( nOpcode == 0 ) ) + { + switch ( nOpcode ) + { + case 0x000 : /*AppData - Beginning of File Opcodes*/ + { + if (mpEndValidSource - pAppData < 4) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + if ( mpChart == nullptr ) + mpChart.reset( new CGMChart ); + mpChart->mnCurrentFileType = pAppData[ 3 ]; + } + break; + case 0x001 : /*AppData - End of File Opcodes */break; + case 0x190 : /*AppData - FDESC */break; + case 0x192 : /*AppData - FNOTES */break; + case 0x1F4 : /*AppData - BOGENFILE */break; + case 0x1F5 : /*AppData - EOGENFILE */break; + case 0x1F8 : /*AppData - BOCHTGROUP */break; + case 0x1F9 : /*AppData - EOCHTGROUP */break; + case 0x1FC : /*AppData - BOCHTDATA */break; + case 0x1FD : /*AppData - EOCHTDATA*/ + { + // mpOutAct->DrawChart(); + } + break; + case 0x200 : /*AppData - BOSYMGROUP */break; + case 0x201 : /*AppData - EOSYMGROUP */break; + case 0x204 : /*AppData - BEGSYMBOL */break; + case 0x205 : /*AppData - ENDSYMBOL */break; + case 0x208 : /*AppData - BOSHWGROUP */break; + case 0x209 : /*AppData - EOSHWGROUP */break; + case 0x260 : /*AppData - BEGGROUP */break; + case 0x262 : /*AppData - ENDGROUP */break; + case 0x264 : /*AppData - DATANODE*/ + { + if (o3tl::make_unsigned(mpEndValidSource - pAppData) < sizeof(DataNode)) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + mpChart->mDataNode[ 0 ] = *reinterpret_cast( pAppData ); + sal_Int8 nZoneEnum = mpChart->mDataNode[ 0 ].nZoneEnum; + if (nZoneEnum > 0 && nZoneEnum <= 6) + mpChart->mDataNode[ nZoneEnum ] = *reinterpret_cast( pAppData ); + } + break; + case 0x2BE : /*AppData - SHWSLIDEREC*/ + { + if (mpEndValidSource - pAppData < 17) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + if ( pAppData[ 16 ] == 0 ) // a blank template ? + { + if ( pAppData[ 2 ] == 46 ) + { + // this starts the document -> maybe we could insert a new document + } + else if ( pAppData[ 2 ] & 0x80 ) + { + // this is a template + } + else + { + mpOutAct->InsertPage(); + } + } + mpChart->ResetAnnotation(); + } + break; + case 0x2C0 : /*AppData - SHWKEYTABLE */break; + case 0x2C2 : /*AppData - SHWBUTTONTAB */break; + case 0x2C4 : /*AppData - SHWGLOBAL */break; + case 0x2C6 : /*AppData - SHWTITLE */break; + case 0x2CA : /*AppData - SHWAPP */break; + case 0x320 : /*AppData - TEXT*/ + { + if (mpEndValidSource - pAppData < 9) + throw css::uno::Exception("attempt to read past end of input", nullptr); + + std::unique_ptr pTextEntry(new TextEntry); + pTextEntry->nTypeOfText = *reinterpret_cast( pAppData ); + pTextEntry->nRowOrLineNum = *reinterpret_cast( pAppData + 2 ); + pTextEntry->nColumnNum = *reinterpret_cast( pAppData + 4 ); + sal_uInt16 nAttributes = *reinterpret_cast( pAppData + 6 ); + pTextEntry->nZoneSize = nAttributes & 0xff; + pTextEntry->nLineType = ( nAttributes >> 8 ) & 0xf; + nAttributes >>= 12; + pTextEntry->nAttributes = nAttributes; + pAppData += 8; + auto nMaxLen = mpEndValidSource - pAppData; + sal_uInt32 nLen = strnlen(reinterpret_cast(pAppData), nMaxLen); + pTextEntry->pText = new char[nLen + 1]; + memcpy( pTextEntry->pText, pAppData, nLen ); + pTextEntry->pText[nLen] = 0; + pAppData += nLen; + + mpChart->InsertTextEntry( std::move(pTextEntry) ); + } + break; + case 0x321 : /*AppData - IOC_TABS */break; + case 0x322 : /*AppData - CHARTZONE*/ + break; + case 0x324 : /*AppData - TITLEZONE */break; + case 0x328 : /*AppData - FOOTNOTEZONE */break; + case 0x32A : /*AppData - LEGENDZONE */break; + case 0x330 : /*AppData - PAGEORIENTDIM*/ + break; + case 0x334 : /*AppData - CHTZONEOPTN*/ + break; + case 0x336 : /*AppData - CHTINTL*/ + break; + case 0x338 : /*AppData - CHTLINESPC */break; + case 0x384 : /*AppData - ORGGRIDSTATE */break; + case 0x386 : /*AppData - ORGSCRSTATE */break; + case 0x388 : /*AppData - ORGTREESTATE */break; + case 0x38A : /*AppData - ORGTEXTOPTN */break; + case 0x38E : /*AppData - ORGBOXOPTN */break; + case 0x390 : /*AppData - ORGBOXDIM */break; + case 0x392 : /*AppData - ORGBOX */break; + case 0x3EA : /*AppData - TTLTEXTOPTN */break; + case 0x3EE : /*AppData - TTLAUTOBUILD */break; + case 0x44E : /*AppData - BULTEXTOPTN */break; + case 0x452 : /*AppData - BULLETOPTN*/ + break; + case 0x454 : /*AppData - BULLETLINES*/break; + case 0x456 : /*AppData - BULAUTOBUILD */break; + case 0x4B2 : /*AppData - TBLTEXTOPTN */break; + case 0x4B6 : /*AppData - TBLOPTN */break; + case 0x4B8 : /*AppData - TBLCOLOPTN */break; + case 0x4BA : /*AppData - TBLLEGENDOPTN */break; + case 0x4BC : /*AppData - TBLRANGEOPTN */break; + case 0x4BE : /*AppData - TBLROWOPTN */break; + case 0x4C0 : /*AppData - TBLAUTOBUILD */break; + case 0x518 : /*AppData - PIECHARTOPTN */break; + case 0x51A : /*AppData - PIELEGENDOPTN */break; + case 0x51C : /*AppData - PIETEXTOPTN */break; + case 0x51E : /*AppData - PIEOPTN */break; + case 0x520 : /*AppData - PIEPCTLABOPTN */break; + case 0x522 : /*AppData - PIEVALLABOPTN */break; + case 0x524 : /*AppData - PIESLICE */break; + case 0x57A : /*AppData - XYAXISOPTN */break; + case 0x57C : /*AppData - XYGRIDOPTN */break; + case 0x57D : /*AppData - XYGRIDSHOWFILL */break; + case 0x57E : /*AppData - XYSERIESOPTN */break; + case 0x580 : /*AppData - XYSTYLEOPTN */break; + case 0x582 : /*AppData - XYTABLEOPTN */break; + case 0x584 : /*AppData - XYTEXTOPTN */break; + case 0x586 : /*AppData - XYDATAOPTN */break; + case 0x58A : /*AppData - XYLEGENDOPN */break; + case 0x58C : /*AppData - XYCALCULATION */break; + case 0x58E : /*AppData - XYXVALUE */break; + case 0x590 : /*AppData - XYYVALUE */break; + case 0x592 : /*AppData - XYXEXTVALUE */break; + case 0x618 : /*AppData - IOC_CHTCOLRTAB */break; + case 0x619 : /*AppData - IOC_CHTFONTTAB */break; + case 0x1fff : /*AppData - 0x1fff */break; + default : /*UNKNOWN Application Data */break; + } + } + mnParaSize = mnElementSize; + break; + } + default: break; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/classx.cxx b/filter/source/graphicfilter/icgm/classx.cxx new file mode 100644 index 000000000..2b624f63b --- /dev/null +++ b/filter/source/graphicfilter/icgm/classx.cxx @@ -0,0 +1,249 @@ +/* -*- 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 "cgm.hxx" +#include "elements.hxx" +#include "outact.hxx" + + +void CGM::ImplSetUnderlineMode() +{ + sal_uInt32 nMode = ImplGetUI16(); + switch ( nMode ) + { + case 1 : pElement->eUnderlineMode = UM_LOW; break; + case 2 : pElement->eUnderlineMode = UM_HIGH; break; + case 4 : pElement->eUnderlineMode = UM_STRIKEOUT; break; + case 8 : pElement->eUnderlineMode = UM_OVERSCORE; break; + default: pElement->eUnderlineMode = UM_OFF; break; + } + pElement->nUnderlineColor = ImplGetBitmapColor(); +} + +void CGM::ImplDoClass6() +{ + switch ( mnElementID ) + { + case 0x01 : /*Escape*/ + { + tools::Long nIdentifier = ImplGetI( pElement->nIntegerPrecision ); + switch ( nIdentifier ) + { + case 0 : /*inquire function support */break; + case -1 : /*set underline mode*/ + { + ImplSetUnderlineMode(); + } + break; + case -2 : /*set script mode */break; + case -3 : /*set shadow mode */break; + case -6 : /*inquire origin offset */break; + case -8 : /*set media size */break; + case -10 : /*set character mode */break; + case -14 : /*resolution mode */break; + case -17 : /*line cap */break; + case -18 : /*line join */break; + case -19 : /*edge join */break; + case -30 : /*media type */break; + case -31 : /*number of copies */break; + case -32 : /*orientation */break; + case -33 : /*device color representation */break; + case -34 : /*device font list */break; + case -35 : /*color reversal mode */break; + case -36 : /*line cap attributes */break; + case -37 : /*begin effect */break; + case -38 : /*end effect */break; + case -39 : /*begin effect definition */break; + case -40 : /*end effect definition */break; + case -41 : /*end style definition */break; + case -42 : /*begin eps data */break; + case -43 : /*eps data */break; + case -44 : /*end eps data */break; + case -45 : /*set background style */break; + case -46 : /*set eps mode */break; + case -47 : /*fill mode */break; + case -48 : /*begin symbol */break; + case -49 : /*end symbol */break; + case -50 : /*begin layer */break; + case -51 : /*end layer */break; + case -52 : /*layer visibility */break; + case -53 : /*inquire foreign data */break; + case -54 : /*set text offset */break; + case -55 : /*begin group */break; + case -56 : /*end group */break; + case -100 : /*begin patch */break; + case -101 : /*end patch */break; + case -102 : /*begin block text region */break; + case -103 : /*end block text region */break; + case -120 : /*region margins */break; + case -121 : /*region expansions */break; + case -122 : /*region anchor */break; + case -123 : /*paragraph horizontal align */break; + case -124 : /*paragraph vertical align */break; + case -125 : /*region line flow */break; + case -130 : /*paragraph spacing */break; + case -131 : /*paragraph indentation */break; + case -132 : /*paragraph tabs */break; + case -133 : /*paragraph bullet */break; + case -134 : /*paragraph bullet level */break; + case -135 : /*line horizontal align */break; + case -136 : /*line vertical align */break; + case -137 : /*line spacing */break; + case -138 : /*word wrap */break; + case -150 : /*forward advance distance */break; + case -151 : /*word spacing */break; + case -152 : /*external leading */break; + case -160 : /*set gradient offset */break; + case -161 : /*set gradient edge */break; + case -162 : /*set gradient angle */break; + case -163 : /*set gradient description */break; + case -164 : /*set gradient style */break; + case -165 : /*set background style */break; + case -170 : /*geometric pattern draw style */break; + case -190 : /*set character width */break; + case -191 : /*hyperlink definitions */break; + case -192 : /*set color name for pantone */break; + case -32746 : /*set text font */break; + case -32747 : /*font selection mode */break; + case -32752 : /*connecting edge */break; + case -32753 : /*set drawing mode */break; + case -32754 : /*inquire clip rectangle */break; + case -32755 : /*protection region indicator */break; + case -32756 : /*end protection region */break; + case -32757 : /*begin protection region */break; + case -32758 : /*geometric pattern definition */break; + case -32759 : /*hatch style definition */break; + case -32760 : /*close figure */break; + case -32761 : /*end figure*/ + { + mpOutAct->EndFigure(); + mbFigure = false; + } + break; + case -32762 : /*begin figure*/ + { + mbFigure = true; + mpOutAct->BeginFigure(); + } + break; + case -32763 : /*pop transformation */break; + case -32764 : /*push transformation */break; + case -32765 : /*copy segment */break; + case -32766 : /*endseg */break; + case -32767 : /*begin segment */break; + default : break; + } + mnParaSize = mnElementSize; + } + break; + case 0x02 : /*Get Escape */break; + case 0x11 : /*Set Underline Mode*/ + { + ImplSetUnderlineMode(); + } + break; + case 0x12 : /*Set Script Mode */break; + case 0x13 : /*Set Shadow Mode */break; + case 0x18 : /*Set Media Size */break; + case 0x20 : /*Set Character Mode */break; + case 0x24 : /*Resolution Mode */break; + case 0x27 : /*Line Cap */break; + case 0x28 : /*Line Join */break; + case 0x29 : /*Edge Join */break; + case 0x40 : /*Media Type */break; + case 0x41 : /*Number of Copies */break; + case 0x42 : /*Origin */break; + case 0x45 : /*Color Reversal Mode */break; + case 0x46 : /*Line Cap Attributes */break; + case 0x49 : /*Begin Effect Definition */break; + case 0x50 : /*End Effect Definition */break; + case 0x51 : /*Line End Style Attributes */break; + case 0x52 : /*Begin Data */break; + case 0x53 : /*Data */break; + case 0x54 : /*End Data */break; + case 0x55 : /*Set Background Style */break; + case 0x56 : /*Set EPS Mode */break; + case 0x57 : /*Fill Mode */break; + case 0x58 : /*Begin Symbol */break; + case 0x59 : /*End Symbol */break; + case 0x60 : /*Begin Layer */break; + case 0x61 : /*End Layer */break; + case 0x62 : /*Layer Visibility */break; + case 0x64 : /*Set Text Offset */break; + case 0xFF : /*Inquire Function Support */break; + case 0xFE : /*Inquire Origin */break; + case 0xFD : /*Inquire Foreign Data Mode */break; + case 0xFC : /*Inquire Text Extent */break; + case 0xFB : /*Inquire DPI */break; + default: break; + } +}; + + +void CGM::ImplDoClass8() +{ + switch ( mnElementID ) + { + case 0x01 : /*Copy Segment */break; // NS + case 0x02 : /*Inheritance Filter */break; // NS + case 0x03 : /*Clip Inheritance */break; // NS + case 0x04 : /*Segment Transformation */break; + case 0x05 : /*Segment Highlighting */break; // NS + case 0x06 : /*Segment Display Priority */break; // NS + case 0x07 : /*Segment Pick Priority */break; // NS + case 0xfe : /*INQ Current Position */break; + case 0xff : /*INQ Inserted Object Extent */break; + default: break; // NS + } +}; + + +void CGM::ImplDoClass9() +{ + switch ( mnElementID ) + { + case 0x01 : /*Pixel Array */break; // NS + case 0x02 : /*Create Bitmap */break; // NS + case 0x03 : /*Delete Bitmap */break; // NS + case 0x04 : /*Select Drawing Bitmap */break; // NS + case 0x05 : /*Display Bitmap */break; // NS + case 0x06 : /*Drawing Mode */break; + case 0x07 : /*Mapped Bitmap ForeGround Color */break; // NS + case 0x08 : /*Fill Bitmap */break; // NS + case 0x09 : /*Two Operand BitBlt */break; // NS + case 0x0a : /*Three Operand BitBlt */break; // NS + default: break; + } +}; + + +void CGM::ImplDoClass15() +{ + switch ( mnElementID ) + { + case 0x01 : /*Inquire Error Stack */break; + case 0x02 : /*Pop Error Stack */break; + case 0x03 : /*Empty Error Stack */break; + default: break; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/elements.cxx b/filter/source/graphicfilter/icgm/elements.cxx new file mode 100644 index 000000000..9a0221066 --- /dev/null +++ b/filter/source/graphicfilter/icgm/elements.cxx @@ -0,0 +1,336 @@ +/* -*- 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 "elements.hxx" + +#include + +CGMElements::CGMElements() +{ + Init(); +}; + + +CGMElements::~CGMElements() +{ +} + + +CGMElements& CGMElements::operator=( const CGMElements& rSource ) +{ + if (this == &rSource) + return *this; + + sal_uInt32 nIndex; + + nVDCIntegerPrecision = rSource.nVDCIntegerPrecision; + nIntegerPrecision = rSource.nIntegerPrecision; + eRealPrecision = rSource.eRealPrecision; + nRealSize = rSource.nRealSize; + nIndexPrecision = rSource.nIndexPrecision; + nColorPrecision = rSource.nColorPrecision; + nColorIndexPrecision = rSource.nColorIndexPrecision; + + nMetaFileVersion = rSource.nMetaFileVersion; + eScalingMode = rSource.eScalingMode; + nScalingFactor = rSource.nScalingFactor; + eVDCType = rSource.eVDCType; + eVDCRealPrecision = rSource.eVDCRealPrecision; + nVDCRealSize = rSource.nVDCRealSize; + aVDCExtent = rSource.aVDCExtent; + aVDCExtentMaximum = rSource.aVDCExtentMaximum; + eDeviceViewPortMode = rSource.eDeviceViewPortMode; + nDeviceViewPortScale = rSource.nDeviceViewPortScale; + eDeviceViewPortMap = rSource.eDeviceViewPortMap; + eDeviceViewPortMapH = rSource.eDeviceViewPortMapH; + eDeviceViewPortMapV = rSource.eDeviceViewPortMapV; + aDeviceViewPort = rSource.aDeviceViewPort; + nMitreLimit = rSource.nMitreLimit; + eClipIndicator = rSource.eClipIndicator; + aClipRect = rSource.aClipRect; + eColorSelectionMode = rSource.eColorSelectionMode; + nColorMaximumIndex = rSource.nColorMaximumIndex; + nLatestColorMaximumIndex = rSource.nLatestColorMaximumIndex; + + for ( nIndex = 1; nIndex < 256; nIndex++ ) // do not overwrite the background color + { + aColorTableEntryIs[ nIndex ] = rSource.aColorTableEntryIs[ nIndex ]; + aColorTable[ nIndex ] = rSource.aColorTable[ nIndex ]; + aLatestColorTable[ nIndex ] = rSource.aColorTable[ nIndex ]; + } + + for ( nIndex = 0; nIndex < 8; nIndex++ ) + { + nColorValueExtent[ nIndex ] = rSource.nColorValueExtent[ nIndex ]; + } + nAspectSourceFlags = rSource.nAspectSourceFlags; + + CopyAllBundles( rSource.aLineList, aLineList ); + aLineBundle = rSource.aLineBundle; + pLineBundle = static_cast(GetBundle( aLineList, rSource.pLineBundle->GetIndex() )); + eLineWidthSpecMode = rSource.eLineWidthSpecMode; + eLineCapType = rSource.eLineCapType; + eLineJoinType = rSource.eLineJoinType; + + CopyAllBundles( rSource.aMarkerList, aMarkerList ); + aMarkerBundle = rSource.aMarkerBundle; + pMarkerBundle = static_cast(GetBundle( aMarkerList, rSource.pMarkerBundle->GetIndex() )); + eMarkerSizeSpecMode = rSource.eMarkerSizeSpecMode; + + CopyAllBundles( rSource.aEdgeList, aEdgeList ); + aEdgeBundle = rSource.aEdgeBundle; + pEdgeBundle = static_cast(GetBundle( aEdgeList, rSource.pEdgeBundle->GetIndex() )); + eEdgeVisibility = rSource.eEdgeVisibility; + eEdgeWidthSpecMode = rSource.eEdgeWidthSpecMode; + + CopyAllBundles( rSource.aTextList, aTextList ); + aTextBundle = rSource.aTextBundle; + pTextBundle = static_cast(GetBundle( aTextList, rSource.pTextBundle->GetIndex() )); + nCharacterHeight = rSource.nCharacterHeight; + nCharacterOrientation[ 0 ] = rSource.nCharacterOrientation[ 0 ]; + nCharacterOrientation[ 1 ] = rSource.nCharacterOrientation[ 1 ]; + nCharacterOrientation[ 2 ] = rSource.nCharacterOrientation[ 2 ]; + nCharacterOrientation[ 3 ] = rSource.nCharacterOrientation[ 3 ]; + eUnderlineMode = rSource.eUnderlineMode; + nUnderlineColor = rSource.nUnderlineColor; + eTextPath = rSource.eTextPath; + eTextAlignmentH = rSource.eTextAlignmentH; + eTextAlignmentV = rSource.eTextAlignmentV; + nTextAlignmentHCont = rSource.nTextAlignmentHCont; + nTextAlignmentVCont = rSource.nTextAlignmentVCont; + nCharacterSetIndex = rSource.nCharacterSetIndex; + nAlternateCharacterSetIndex = rSource.nAlternateCharacterSetIndex; + aFontList = rSource.aFontList; + eCharacterCodingA = rSource.eCharacterCodingA; + + CopyAllBundles( rSource.aFillList, aFillList ); + aFillBundle = rSource.aFillBundle; + pFillBundle = static_cast(GetBundle( aFillList, rSource.pFillBundle->GetIndex() )); + aFillRefPoint = rSource.aFillRefPoint; + eTransparency = rSource.eTransparency; + nAuxiliaryColor = rSource.nAuxiliaryColor; + + maHatchMap = rSource.maHatchMap; + bSegmentCount = rSource.bSegmentCount; + return *this; +} + + +void CGMElements::Init() +{ + + nIntegerPrecision = nIndexPrecision = 2; + nRealSize = nVDCRealSize = 4; + nColorIndexPrecision = 1; + nColorPrecision = 1; + nVDCIntegerPrecision = 2; + eRealPrecision = eVDCRealPrecision = RP_FIXED; //RP_FLOAT; + + nMetaFileVersion = 1; + eScalingMode = SM_ABSTRACT; + eVDCType = VDC_INTEGER; + aVDCExtent.Left = aVDCExtent.Bottom = 0; +// aVDCExtent.Right = aVDCExtent.Top = 32767; + aVDCExtent.Right = aVDCExtent.Top = 1.0; + aVDCExtentMaximum.Left = aVDCExtentMaximum.Bottom = 0; +// aVDCExtentMaximum.Right = aVDCExtentMaximum.Top = 32767; + aVDCExtentMaximum.Right = aVDCExtentMaximum.Top = 1.0; + + eDeviceViewPortMode = DVPM_FRACTION; + nDeviceViewPortScale = 1; + eDeviceViewPortMap = DVPM_FORCED; + eDeviceViewPortMapH = DVPMH_LEFT; + eDeviceViewPortMapV = DVPMV_BOTTOM; + aDeviceViewPort.Left = 0; + aDeviceViewPort.Top = 1; + aDeviceViewPort.Right = 0; + aDeviceViewPort.Bottom = 1; + + nMitreLimit = 32767; + eClipIndicator = CI_ON; + aClipRect = aVDCExtent; + + eColorSelectionMode = CSM_INDEXED; + nColorMaximumIndex = 63; + int i; + for ( i = 0; i < 256; aColorTableEntryIs[ i++ ] = 0 ) ; + aColorTable[ 0 ] = 0; + for ( i = 1; i < 256; aColorTable[ i++ ] = 0xffffff ) ; + nLatestColorMaximumIndex = 63; + aLatestColorTable[ 0 ] = 0; + for ( i = 1; i < 256; aLatestColorTable[ i++ ] = 0xffffff ) ; + nColorValueExtent[ 0 ] = nColorValueExtent[ 1 ] = nColorValueExtent[ 2 ] = 0; + nColorValueExtent[ 3 ] = nColorValueExtent[ 4 ] = nColorValueExtent[ 5 ] = 255; + + nAspectSourceFlags = 0; // all flags are individual + + eLineWidthSpecMode = SM_SCALED; // line parameter + eLineCapType = LCT_NONE; + eLineJoinType = LJT_NONE; + pLineBundle = &aLineBundle; // line bundle parameter + aLineBundle.SetIndex( 1 ); + aLineBundle.eLineType = LT_SOLID; + aLineBundle.nLineWidth = 1; + aLineBundle.SetColor( 0xffffff ); + InsertBundle( aLineList, aLineBundle ); + + eMarkerSizeSpecMode = SM_SCALED; // marker parameter + pMarkerBundle = &aMarkerBundle; // marker bundle parameter + aMarkerBundle.SetIndex( 1 ); + aMarkerBundle.eMarkerType = MT_STAR; + aMarkerBundle.nMarkerSize = 1; + aMarkerBundle.SetColor( 0xffffff ); + InsertBundle( aMarkerList, aMarkerBundle ); + + eEdgeVisibility = EV_OFF; // edge parameter + eEdgeWidthSpecMode = SM_SCALED; + pEdgeBundle = &aEdgeBundle; // edge bundle parameter + aEdgeBundle.SetIndex( 1 ); + aEdgeBundle.eEdgeType = ET_SOLID; + aEdgeBundle.nEdgeWidth = 1; + aEdgeBundle.SetColor( 0xffffff ); + InsertBundle( aEdgeList, aEdgeBundle ); + + nCharacterHeight = 327; // text parameter + nCharacterOrientation[0] = 0; + nCharacterOrientation[1] = 1; + nCharacterOrientation[2] = 1; + nCharacterOrientation[3] = 0; + eUnderlineMode = UM_OFF; + nUnderlineColor = 0xffffff; + eTextPath = TPR_RIGHT; + eTextAlignmentH = TAH_NORMAL; + eTextAlignmentV = TAV_NORMAL; + nCharacterSetIndex = nAlternateCharacterSetIndex = 1; + eCharacterCodingA = CCA_BASIC_7; + pTextBundle = &aTextBundle; // text bundle parameter + aTextBundle.SetIndex( 1 ); + aTextBundle.nTextFontIndex = 1; + aTextBundle.eTextPrecision = TPR_STRING; + aTextBundle.nCharacterExpansion = 1; + aTextBundle.nCharacterSpacing = 0; + aTextBundle.SetColor( 0xffffff ); + InsertBundle( aTextList, aTextBundle ); + + pFillBundle = &aFillBundle; // fill bundle parameter + aFillBundle.SetIndex( 1 ); + aFillBundle.eFillInteriorStyle = FIS_HOLLOW; + aFillBundle.nFillHatchIndex = 1; + aFillBundle.nFillPatternIndex = 1; + aFillBundle.SetColor( 0xffffff ); + InsertBundle( aFillList, aFillBundle ); + + ImplInsertHatch( 0, 0, 0, 0 ); + ImplInsertHatch( 1, 0, 125, 0 ); + ImplInsertHatch( 2, 0, 125, 900 ); + ImplInsertHatch( 3, 0, 125, 450 ); + ImplInsertHatch( 4, 0, 125, 1350 ); + ImplInsertHatch( 5, 1, 125, 0 ); + ImplInsertHatch( 6, 1, 125, 450 ); + ImplInsertHatch( -1, 0, 75, 0 ); + ImplInsertHatch( -2, 0, 75, 900 ); + ImplInsertHatch( -3, 0, 75, 450 ); + ImplInsertHatch( -4, 0, 75, 1350 ); + ImplInsertHatch( -5, 1, 75, 0 ); + ImplInsertHatch( -6, 1, 75, 450 ); + ImplInsertHatch( -7, 2, 125, 0 ); + ImplInsertHatch( -8, 2, 125, 900 ); + ImplInsertHatch( -9, 2, 125, 450 ); + ImplInsertHatch( -10, 2, 125, 1350 ); + ImplInsertHatch( -11, 0, 40, 0 ); + ImplInsertHatch( -12, 0, 40, 900 ); + ImplInsertHatch( -13, 0, 40, 450 ); + ImplInsertHatch( -14, 0, 40, 1350 ); + ImplInsertHatch( -15, 1, 40, 0 ); + ImplInsertHatch( -16, 1, 40, 900 ); + ImplInsertHatch( -21, 0, 250, 0 ); + ImplInsertHatch( -22, 0, 250, 900 ); + ImplInsertHatch( -23, 0, 250, 450 ); + ImplInsertHatch( -24, 0, 250, 1350 ); + ImplInsertHatch( -25, 1, 250, 0 ); + ImplInsertHatch( -26, 1, 250, 450 ); + + eTransparency = T_ON; + + nBackGroundColor = nAuxiliaryColor = 0; + + bSegmentCount = false; + + nScalingFactor = 1.0; + nTextAlignmentVCont = nTextAlignmentHCont = 0.0; +} + + +void CGMElements::ImplInsertHatch( sal_Int32 nKey, int nStyle, tools::Long nDistance, tools::Long nAngle ) +{ + HatchEntry& rEntry = maHatchMap[nKey]; + rEntry.HatchStyle = nStyle; + rEntry.HatchDistance = nDistance; + rEntry.HatchAngle = nAngle; +} + + +void CGMElements::CopyAllBundles( const BundleList& rSource, BundleList& rDest ) +{ + rDest.clear(); + + for (auto & pPtr : rSource) + { + rDest.push_back( pPtr->Clone() ); + } +}; + + +Bundle* CGMElements::GetBundleIndex( tools::Long nIndex, BundleList& rList, Bundle& rBundle ) +{ + rBundle.SetIndex( nIndex ); + Bundle* pBundle = GetBundle( rList, nIndex ); + if ( !pBundle ) + pBundle = InsertBundle( rList, rBundle ); + return pBundle; +} + + +Bundle* CGMElements::GetBundle( BundleList& rList, tools::Long nIndex ) +{ + for (auto const & i : rList) { + if ( i->GetIndex() == nIndex ) { + return i.get(); + } + } + return nullptr; +} + + +Bundle* CGMElements::InsertBundle( BundleList& rList, Bundle& rBundle ) +{ + Bundle* pBundle = GetBundle( rList, rBundle.GetIndex() ); + if ( pBundle ) + { + auto it = std::find_if(rList.begin(), rList.end(), + [&pBundle](const std::unique_ptr& rxBundle) { return rxBundle.get() == pBundle; }); + if (it != rList.end()) + rList.erase( it ); + } + rList.push_back( rBundle.Clone() ); + return rList.back().get(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/elements.hxx b/filter/source/graphicfilter/icgm/elements.hxx new file mode 100644 index 000000000..3f4bd710a --- /dev/null +++ b/filter/source/graphicfilter/icgm/elements.hxx @@ -0,0 +1,136 @@ +/* -*- 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 . + */ +#pragma once + +#include "bundles.hxx" +#include "cgmtypes.hxx" +#include +#include + +#define nBackGroundColor aColorTable[ 0 ] + +typedef ::std::vector< std::unique_ptr > BundleList; + +class CGMElements +{ + void ImplInsertHatch( sal_Int32 Key, int Style, tools::Long Distance, tools::Long Angle ); + public: + tools::Long nMetaFileVersion; + + sal_uInt32 nIntegerPrecision; // maybe 1, 2, 4 Bytes + sal_uInt32 nIndexPrecision; // " " " + RealPrecision eRealPrecision; + sal_uInt32 nRealSize; // maybe 4 or 8 bytes + sal_uInt32 nColorPrecision; // " " " + sal_uInt32 nColorIndexPrecision;// " " " + + ScalingMode eScalingMode; + double nScalingFactor; + + VDCType eVDCType; // Integer / Real + sal_uInt32 nVDCIntegerPrecision; + RealPrecision eVDCRealPrecision; + sal_uInt32 nVDCRealSize; + FloatRect aVDCExtent; + FloatRect aVDCExtentMaximum; + + DeviceViewPortMode eDeviceViewPortMode; + double nDeviceViewPortScale; + DeviceViewPortMap eDeviceViewPortMap; + DeviceViewPortMapH eDeviceViewPortMapH; + DeviceViewPortMapV eDeviceViewPortMapV; + FloatRect aDeviceViewPort; + + double nMitreLimit; + + ClipIndicator eClipIndicator; + FloatRect aClipRect; + + ColorSelectionMode eColorSelectionMode; + sal_uInt32 nColorMaximumIndex; // default 63 + sal_uInt32 nLatestColorMaximumIndex; // default 63 + sal_Int8 aColorTableEntryIs[ 256 ]; + sal_uInt32 aColorTable[ 256 ]; + sal_uInt32 aLatestColorTable[ 256 ]; + sal_uInt32 nColorValueExtent[ 8 ]; // RGB, CMYK + + // ASPECT SOURCE FLAGS + sal_uInt32 nAspectSourceFlags; // bit = 0 -> INDIVIDUAL + // 1 -> BUNDLED + + LineBundle* pLineBundle; // Pointer to the current LineBundleIndex + LineBundle aLineBundle; + BundleList aLineList; + SpecMode eLineWidthSpecMode; + LineCapType eLineCapType; + LineJoinType eLineJoinType; + + MarkerBundle* pMarkerBundle; // Pointer to the current MarkerBundleIndex + MarkerBundle aMarkerBundle; + BundleList aMarkerList; + SpecMode eMarkerSizeSpecMode; + + EdgeBundle* pEdgeBundle; // Pointer to the current EdgeBundleIndex + EdgeBundle aEdgeBundle; + BundleList aEdgeList; + EdgeVisibility eEdgeVisibility; + SpecMode eEdgeWidthSpecMode; + + TextBundle* pTextBundle; // Pointer to the current TextBundleIndex + TextBundle aTextBundle; + BundleList aTextList; + double nCharacterHeight; + double nCharacterOrientation[ 4 ]; + UnderlineMode eUnderlineMode; + sal_uInt32 nUnderlineColor; + TextPath eTextPath; + TextAlignmentH eTextAlignmentH; + TextAlignmentV eTextAlignmentV; + double nTextAlignmentHCont; + double nTextAlignmentVCont; + tools::Long nCharacterSetIndex; + tools::Long nAlternateCharacterSetIndex; + CharacterCodingA eCharacterCodingA; + CGMFList aFontList; + + FillBundle* pFillBundle; // Pointer to the current EdgeBundleIndex + FillBundle aFillBundle; + BundleList aFillList; + FloatPoint aFillRefPoint; + ::std::map + maHatchMap; + + Transparency eTransparency; + + sal_uInt32 nAuxiliaryColor; + + // Delimiter Counts -> which will be increased by each 'begin' operation + // and decreased by each 'end' operation + bool bSegmentCount; + explicit CGMElements(); + ~CGMElements(); + CGMElements& operator=( const CGMElements& ); + void Init(); + static Bundle* GetBundleIndex( tools::Long nIndex, BundleList&, Bundle& ); + static Bundle* GetBundle( BundleList& rList, tools::Long nIndex ); + static Bundle* InsertBundle( BundleList&, Bundle& ); + static void CopyAllBundles( const BundleList& Source, BundleList& Dest ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/graphicfilter/icgm/outact.hxx b/filter/source/graphicfilter/icgm/outact.hxx new file mode 100644 index 000000000..b06fffda8 --- /dev/null +++ b/filter/source/graphicfilter/icgm/outact.hxx @@ -0,0 +1,108 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + +#define CGM_OUTACT_MAX_GROUP_LEVEL 64 + +#include "cgm.hxx" +#include +#include +#include + +class CGM; +class CGMBitmapDescriptor; + +class CGMImpressOutAct +{ + sal_uInt16 mnCurrentPage; // defaulted to zero + + sal_uInt32 mnGroupActCount; // grouping + sal_uInt32 mnGroupLevel; + std::array + maGroupLevel; + + std::vector maFlags; + std::vector maPoints; + tools::PolyPolygon maPolyPolygon; + std::unique_ptr + mpGradient; + + CGM* mpCGM; + + css::uno::Reference< css::drawing::XDrawPages > maXDrawPages; + css::uno::Reference< css::drawing::XDrawPage > maXDrawPage; + + css::uno::Reference< css::lang::XMultiServiceFactory > maXMultiServiceFactory; + css::uno::Reference< css::drawing::XShape > maXShape; + + css::uno::Reference< css::beans::XPropertySet > maXPropSet; + css::uno::Reference< css::drawing::XShapes > maXShapes; + std::vector> maLockedNewXShapes; + + sal_uInt32 nFinalTextCount; + + bool ImplCreateShape( const OUString& rType ); + bool ImplInitPage(); + void ImplSetOrientation( FloatPoint const & RefPoint, double Orientation ); + void ImplSetLineBundle(); + void ImplSetFillBundle(); + void ImplSetTextBundle( const css::uno::Reference< css::beans::XPropertySet > & ); +public: + CGMImpressOutAct( CGM&, const css::uno::Reference< css::frame::XModel > & ); + ~CGMImpressOutAct(); + void InsertPage(); + void BeginGroup(); + void EndGroup(); + void EndGrouping(); + void DrawRectangle( FloatRect const & ); + void DrawEllipse( FloatPoint const & center, FloatPoint const &, double& Orientation ); + void DrawEllipticalArc( FloatPoint const & center, FloatPoint const & size, double& orientation, + sal_uInt32 etype, double& startangle, double& endangle ); + void DrawBitmap( CGMBitmapDescriptor* ); + void DrawPolygon( tools::Polygon& ); + void DrawPolyLine( tools::Polygon& ); + void DrawPolybezier( tools::Polygon& ); + void DrawPolyPolygon( tools::PolyPolygon const & ); + void DrawText(css::awt::Point const & TextRectPos, css::awt::Size const & TextRectSize, const OUString& rString, FinalFlag); + void AppendText( const char* String ); + + void FirstOutPut() { mpCGM->mbFirstOutPut = false; } ; + void BeginFigure(); + void CloseRegion(); + void NewRegion(); + void EndFigure(); + void RegPolyLine( tools::Polygon const &, bool bReverse = false ); + void SetGradientOffset( tools::Long nHorzOfs, tools::Long nVertOfs ); + void SetGradientAngle( tools::Long nAngle ); + void SetGradientDescriptor( sal_uInt32 nColorFrom, sal_uInt32 nColorTo ); + void SetGradientStyle( sal_uInt32 nStyle ); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/countryid.cxx b/filter/source/msfilter/countryid.cxx new file mode 100644 index 000000000..9ad504ab3 --- /dev/null +++ b/filter/source/msfilter/countryid.cxx @@ -0,0 +1,319 @@ +/* -*- 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 + +#include +#include + + +namespace msfilter { + +// Mapping table ============================================================== + +namespace { + + +/** Table entry for Windows country ID <-> language type conversion. + + The first member is the Windows country ID, as defined in the header. + + The second member contains the corresponding language type for each country + ID. This must be a full language, not only the primary language type. + + The last bool flag defines, if the sub language type should be evaluated to + find the country ID from a language. If not set, all languages map to the + country which contain the given primary language type. + + Example: The language entry (COUNTRY_USA,LANGUAGE_ENGLISH_US,false) maps + the country ID for USA to the language LANGUAGE_ENGLISH_US. The clear sub + language flag causes all english languages LANGUAGE_ENGLISH_*** to map to + this country ID by default. To map the special case LANGUAGE_ENGLISH_EIRE + to the country ID COUNTRY_IRELAND, the sub language flag must be set in the + respective table entry, here (COUNTRY_IRELAND,LANGUAGE_ENGLISH_EIRE,true). + */ +struct CountryEntry +{ + CountryId meCountry; /// Windows country ID. + LanguageType meLanguage; /// Corresponding language type. + bool mbUseSubLang; /// false = Primary only, true = Primary and sub language. +}; + + +/** Table for Windows country ID <-> language type conversion. + + To map the same language to different country IDs, some of the entries + should contain a set sub language flag (see description of CountryEntry). + All table entries with a set flag take priority over the entry with the + same primary language, but cleared sub language flag, regardless of the + position in the table. + + To map different languages to the same country ID, several entries with the + same country ID may be inserted. In this case the conversion to a language + is done with the first found entry (starting from top) containing the given + country ID. + + For now all entries are sorted by country ID, but this is not required. + */ +const CountryEntry pTable[] = +{ + { COUNTRY_USA, LANGUAGE_ENGLISH_US, false }, + { COUNTRY_DOMINICAN_REPUBLIC, LANGUAGE_SPANISH_DOMINICAN_REPUBLIC, true }, + { COUNTRY_JAMAICA, LANGUAGE_ENGLISH_JAMAICA, true }, + { COUNTRY_PUERTO_RICO, LANGUAGE_SPANISH_PUERTO_RICO, true }, + { COUNTRY_TRINIDAD_Y_TOBAGO, LANGUAGE_ENGLISH_TRINIDAD, true }, + { COUNTRY_CANADA, LANGUAGE_ENGLISH_CAN, true }, + { COUNTRY_CANADA, LANGUAGE_FRENCH_CANADIAN, true }, + { COUNTRY_RUSSIA, LANGUAGE_RUSSIAN, false }, + { COUNTRY_KAZAKHSTAN, LANGUAGE_KAZAKH, false }, + { COUNTRY_TATARSTAN, LANGUAGE_TATAR, false }, + { COUNTRY_EGYPT, LANGUAGE_ARABIC_EGYPT, true }, + { COUNTRY_SOUTH_AFRICA, LANGUAGE_AFRIKAANS, false }, + { COUNTRY_SOUTH_AFRICA, LANGUAGE_ENGLISH_SAFRICA, true }, + { COUNTRY_SOUTH_AFRICA, LANGUAGE_TSONGA, false }, + { COUNTRY_SOUTH_AFRICA, LANGUAGE_VENDA, false }, + { COUNTRY_SOUTH_AFRICA, LANGUAGE_XHOSA, false }, + { COUNTRY_SOUTH_AFRICA, LANGUAGE_ZULU, false }, + { COUNTRY_GREECE, LANGUAGE_GREEK, false }, + { COUNTRY_NETHERLANDS, LANGUAGE_DUTCH, false }, + { COUNTRY_NETHERLANDS, LANGUAGE_FRISIAN_NETHERLANDS, false }, + { COUNTRY_BELGIUM, LANGUAGE_DUTCH_BELGIAN, true }, + { COUNTRY_BELGIUM, LANGUAGE_FRENCH_BELGIAN, true }, + { COUNTRY_FRANCE, LANGUAGE_FRENCH, false }, + { COUNTRY_SPAIN, LANGUAGE_SPANISH_MODERN, false }, + { COUNTRY_SPAIN, LANGUAGE_SPANISH_DATED, false }, + { COUNTRY_SPAIN, LANGUAGE_CATALAN, false }, + { COUNTRY_SPAIN, LANGUAGE_BASQUE, false }, + { COUNTRY_SPAIN, LANGUAGE_GALICIAN, false }, + { COUNTRY_HUNGARY, LANGUAGE_HUNGARIAN, false }, + { COUNTRY_ITALY, LANGUAGE_ITALIAN, false }, + { COUNTRY_ROMANIA, LANGUAGE_ROMANIAN, false }, + { COUNTRY_SWITZERLAND, LANGUAGE_GERMAN_SWISS, true }, + { COUNTRY_SWITZERLAND, LANGUAGE_FRENCH_SWISS, true }, + { COUNTRY_SWITZERLAND, LANGUAGE_ITALIAN_SWISS, true }, + { COUNTRY_SWITZERLAND, LANGUAGE_RHAETO_ROMAN, false }, + { COUNTRY_AUSTRIA, LANGUAGE_GERMAN_AUSTRIAN, true }, + { COUNTRY_UNITED_KINGDOM, LANGUAGE_ENGLISH_UK, true }, + { COUNTRY_UNITED_KINGDOM, LANGUAGE_GAELIC_SCOTLAND, true }, + { COUNTRY_UNITED_KINGDOM, LANGUAGE_WELSH, false }, + { COUNTRY_DENMARK, LANGUAGE_DANISH, false }, + { COUNTRY_SWEDEN, LANGUAGE_SWEDISH, false }, + { COUNTRY_SWEDEN, LANGUAGE_SAMI_LAPPISH, false }, + { COUNTRY_NORWAY, LANGUAGE_NORWEGIAN_BOKMAL, false }, + { COUNTRY_POLAND, LANGUAGE_POLISH, false }, + { COUNTRY_GERMANY, LANGUAGE_GERMAN, false }, + { COUNTRY_GERMANY, LANGUAGE_SORBIAN, false }, + { COUNTRY_PERU, LANGUAGE_SPANISH_PERU, true }, + { COUNTRY_MEXICO, LANGUAGE_SPANISH_MEXICAN, true }, + { COUNTRY_ARGENTINA, LANGUAGE_SPANISH_ARGENTINA, true }, + { COUNTRY_BRAZIL, LANGUAGE_PORTUGUESE_BRAZILIAN, true }, + { COUNTRY_CHILE, LANGUAGE_SPANISH_CHILE, true }, + { COUNTRY_COLOMBIA, LANGUAGE_SPANISH_COLOMBIA, true }, + { COUNTRY_VENEZUELA, LANGUAGE_SPANISH_VENEZUELA, true }, + { COUNTRY_MALAYSIA, LANGUAGE_MALAY_MALAYSIA, false }, + { COUNTRY_AUSTRALIA, LANGUAGE_ENGLISH_AUS, true }, + { COUNTRY_INDONESIA, LANGUAGE_INDONESIAN, false }, + { COUNTRY_PHILIPPINES, LANGUAGE_ENGLISH_PHILIPPINES, true }, + { COUNTRY_NEW_ZEALAND, LANGUAGE_MAORI_NEW_ZEALAND, false }, + { COUNTRY_NEW_ZEALAND, LANGUAGE_ENGLISH_NZ, true }, + { COUNTRY_SINGAPORE, LANGUAGE_CHINESE_SINGAPORE, true }, + { COUNTRY_THAILAND, LANGUAGE_THAI, false }, + { COUNTRY_JAPAN, LANGUAGE_JAPANESE, false }, + { COUNTRY_SOUTH_KOREA, LANGUAGE_KOREAN, false }, + { COUNTRY_VIET_NAM, LANGUAGE_VIETNAMESE, false }, + { COUNTRY_PR_CHINA, LANGUAGE_CHINESE_SIMPLIFIED, false }, + { COUNTRY_TIBET, LANGUAGE_TIBETAN, false }, + { COUNTRY_TURKEY, LANGUAGE_TURKISH, false }, + { COUNTRY_INDIA, LANGUAGE_HINDI, false }, + { COUNTRY_INDIA, LANGUAGE_URDU_INDIA, true }, + { COUNTRY_INDIA, LANGUAGE_PUNJABI, false }, + { COUNTRY_INDIA, LANGUAGE_GUJARATI, false }, + { COUNTRY_INDIA, LANGUAGE_ODIA, false }, + { COUNTRY_INDIA, LANGUAGE_TAMIL, false }, + { COUNTRY_INDIA, LANGUAGE_TELUGU, false }, + { COUNTRY_INDIA, LANGUAGE_KANNADA, false }, + { COUNTRY_INDIA, LANGUAGE_MALAYALAM, false }, + { COUNTRY_INDIA, LANGUAGE_ASSAMESE, false }, + { COUNTRY_INDIA, LANGUAGE_MARATHI, false }, + { COUNTRY_INDIA, LANGUAGE_SANSKRIT, false }, + { COUNTRY_INDIA, LANGUAGE_KONKANI, false }, + { COUNTRY_INDIA, LANGUAGE_MANIPURI, false }, + { COUNTRY_INDIA, LANGUAGE_SINDHI, false }, + { COUNTRY_INDIA, LANGUAGE_KASHMIRI, false }, + { COUNTRY_PAKISTAN, LANGUAGE_URDU_PAKISTAN, false }, + { COUNTRY_MYANMAR, LANGUAGE_BURMESE, false }, + { COUNTRY_MOROCCO, LANGUAGE_ARABIC_MOROCCO, true }, + { COUNTRY_ALGERIA, LANGUAGE_ARABIC_ALGERIA, true }, + { COUNTRY_TUNISIA, LANGUAGE_ARABIC_TUNISIA, true }, + { COUNTRY_LIBYA, LANGUAGE_ARABIC_LIBYA, true }, + { COUNTRY_SENEGAL, LANGUAGE_FRENCH_SENEGAL, true }, + { COUNTRY_MALI, LANGUAGE_FRENCH_MALI, true }, + { COUNTRY_COTE_D_IVOIRE, LANGUAGE_FRENCH_COTE_D_IVOIRE, true }, + { COUNTRY_CAMEROON, LANGUAGE_FRENCH_CAMEROON, true }, + { COUNTRY_ZAIRE, LANGUAGE_FRENCH_ZAIRE, true }, + { COUNTRY_RWANDA, LANGUAGE_KINYARWANDA_RWANDA, false }, + { COUNTRY_KENYA, LANGUAGE_SWAHILI, false }, + { COUNTRY_REUNION, LANGUAGE_FRENCH_REUNION, true }, + { COUNTRY_ZIMBABWE, LANGUAGE_ENGLISH_ZIMBABWE, true }, + { COUNTRY_LESOTHO, LANGUAGE_SESOTHO, false }, + { COUNTRY_BOTSWANA, LANGUAGE_TSWANA, false }, + { COUNTRY_FAEROE_ISLANDS, LANGUAGE_FAEROESE, false }, + { COUNTRY_PORTUGAL, LANGUAGE_PORTUGUESE, false }, + { COUNTRY_LUXEMBOURG, LANGUAGE_GERMAN_LUXEMBOURG, true }, + { COUNTRY_LUXEMBOURG, LANGUAGE_FRENCH_LUXEMBOURG, true }, + { COUNTRY_IRELAND, LANGUAGE_ENGLISH_EIRE, true }, + { COUNTRY_IRELAND, LANGUAGE_GAELIC_IRELAND, true }, + { COUNTRY_ICELAND, LANGUAGE_ICELANDIC, false }, + { COUNTRY_ALBANIA, LANGUAGE_ALBANIAN, false }, + { COUNTRY_MALTA, LANGUAGE_MALTESE, false }, + { COUNTRY_FINLAND, LANGUAGE_FINNISH, false }, + { COUNTRY_FINLAND, LANGUAGE_SWEDISH_FINLAND, true }, + { COUNTRY_BULGARIA, LANGUAGE_BULGARIAN, false }, + { COUNTRY_LITHUANIA, LANGUAGE_LITHUANIAN, false }, + { COUNTRY_LATVIA, LANGUAGE_LATVIAN, false }, + { COUNTRY_ESTONIA, LANGUAGE_ESTONIAN, false }, + { COUNTRY_MOLDOVA, LANGUAGE_ROMANIAN_MOLDOVA, true }, + { COUNTRY_MOLDOVA, LANGUAGE_RUSSIAN_MOLDOVA, true }, + { COUNTRY_ARMENIA, LANGUAGE_ARMENIAN, false }, + { COUNTRY_BELARUS, LANGUAGE_BELARUSIAN, false }, + { COUNTRY_MONACO, LANGUAGE_FRENCH_MONACO, true }, + { COUNTRY_UKRAINE, LANGUAGE_UKRAINIAN, false }, + { COUNTRY_SERBIA, LANGUAGE_SERBIAN_LATIN_SAM, false }, + { COUNTRY_CROATIA, LANGUAGE_CROATIAN, true }, // sub type of LANGUAGE_SERBIAN + { COUNTRY_SLOVENIA, LANGUAGE_SLOVENIAN, false }, + { COUNTRY_MACEDONIA, LANGUAGE_MACEDONIAN, false }, + { COUNTRY_CZECH, LANGUAGE_CZECH, false }, + { COUNTRY_SLOVAK, LANGUAGE_SLOVAK, false }, + { COUNTRY_LIECHTENSTEIN, LANGUAGE_GERMAN_LIECHTENSTEIN, true }, + { COUNTRY_BELIZE, LANGUAGE_ENGLISH_BELIZE, true }, + { COUNTRY_GUATEMALA, LANGUAGE_SPANISH_GUATEMALA, true }, + { COUNTRY_EL_SALVADOR, LANGUAGE_SPANISH_EL_SALVADOR, true }, + { COUNTRY_HONDURAS, LANGUAGE_SPANISH_HONDURAS, true }, + { COUNTRY_NICARAGUA, LANGUAGE_SPANISH_NICARAGUA, true }, + { COUNTRY_COSTA_RICA, LANGUAGE_SPANISH_COSTARICA, true }, + { COUNTRY_PANAMA, LANGUAGE_SPANISH_PANAMA, true }, + { COUNTRY_BOLIVIA, LANGUAGE_SPANISH_BOLIVIA, true }, + { COUNTRY_ECUADOR, LANGUAGE_SPANISH_ECUADOR, true }, + { COUNTRY_PARAGUAY, LANGUAGE_SPANISH_PARAGUAY, true }, + { COUNTRY_URUGUAY, LANGUAGE_SPANISH_URUGUAY, true }, + { COUNTRY_BRUNEI_DARUSSALAM, LANGUAGE_MALAY_BRUNEI_DARUSSALAM, true }, + { COUNTRY_HONG_KONG, LANGUAGE_CHINESE_HONGKONG, true }, + { COUNTRY_MACAU, LANGUAGE_CHINESE_MACAU, true }, + { COUNTRY_CAMBODIA, LANGUAGE_KHMER, false }, + { COUNTRY_LAOS, LANGUAGE_LAO, false }, + { COUNTRY_BANGLADESH, LANGUAGE_BENGALI, false }, + { COUNTRY_TAIWAN, LANGUAGE_CHINESE_TRADITIONAL, true }, + { COUNTRY_MALDIVES, LANGUAGE_DHIVEHI, false }, + { COUNTRY_LEBANON, LANGUAGE_ARABIC_LEBANON, true }, + { COUNTRY_JORDAN, LANGUAGE_ARABIC_JORDAN, true }, + { COUNTRY_SYRIA, LANGUAGE_ARABIC_SYRIA, true }, + { COUNTRY_IRAQ, LANGUAGE_ARABIC_IRAQ, true }, + { COUNTRY_KUWAIT, LANGUAGE_ARABIC_KUWAIT, true }, + { COUNTRY_SAUDI_ARABIA, LANGUAGE_ARABIC_SAUDI_ARABIA, true }, + { COUNTRY_YEMEN, LANGUAGE_ARABIC_YEMEN, true }, + { COUNTRY_OMAN, LANGUAGE_ARABIC_OMAN, true }, + { COUNTRY_UAE, LANGUAGE_ARABIC_UAE, true }, + { COUNTRY_ISRAEL, LANGUAGE_HEBREW, false }, + { COUNTRY_BAHRAIN, LANGUAGE_ARABIC_BAHRAIN, true }, + { COUNTRY_QATAR, LANGUAGE_ARABIC_QATAR, true }, + { COUNTRY_MONGOLIA, LANGUAGE_MONGOLIAN_CYRILLIC_MONGOLIA, false }, + { COUNTRY_NEPAL, LANGUAGE_NEPALI, false }, + { COUNTRY_IRAN, LANGUAGE_FARSI, false }, + { COUNTRY_TAJIKISTAN, LANGUAGE_TAJIK, false }, + { COUNTRY_TURKMENISTAN, LANGUAGE_TURKMEN, false }, + { COUNTRY_AZERBAIJAN, LANGUAGE_AZERI_LATIN, false }, + { COUNTRY_GEORGIA, LANGUAGE_GEORGIAN, false }, + { COUNTRY_KYRGYZSTAN, LANGUAGE_KIRGHIZ, false }, + { COUNTRY_UZBEKISTAN, LANGUAGE_UZBEK_LATIN, false } +}; + +const CountryEntry * const pEnd = pTable + SAL_N_ELEMENTS( pTable ); + +/** Predicate comparing a country ID with the member of a CountryEntry. */ +struct CountryEntryPred_Country +{ + CountryId meCountry; + + explicit CountryEntryPred_Country( CountryId eCountry ) : + meCountry( eCountry ) {} + + bool operator()( const CountryEntry& rCmp ) const + { return rCmp.meCountry == meCountry; } +}; + +/** Predicate comparing a language type with the member of a CountryEntry. + + Compares by primary language only, if the passed CountryEntry allows it + (the member mbUseSubLang is cleared), otherwise by full language type. */ +struct CountryEntryPred_Language +{ + LanguageType meLanguage; + + explicit CountryEntryPred_Language( LanguageType eLanguage ) : + meLanguage( eLanguage ) {} + + bool operator()( const CountryEntry& rCmp ) const; +}; + +bool CountryEntryPred_Language::operator()( const CountryEntry& rCmp ) const +{ + // rCmp.mbUseSubLang==true -> compare full language type + // rCmp.mbUseSubLang==false -> compare primary language only + return rCmp.mbUseSubLang ? (meLanguage == rCmp.meLanguage) : + (primary(meLanguage) == primary(rCmp.meLanguage)); +} + +} // namespace + +// Country ID <-> Language type conversion ==================================== + +CountryId ConvertLanguageToCountry( LanguageType eLanguage ) +{ + // country of a found primary language type + CountryId ePrimCountry = COUNTRY_DONTKNOW; + + // find an exact match and a primary-language-only match, in one pass + const CountryEntry* pEntry = pTable; + do + { + pEntry = std::find_if( pEntry, pEnd, CountryEntryPred_Language( eLanguage ) ); + if( pEntry != pEnd ) + { + if( pEntry->mbUseSubLang ) + return pEntry->meCountry; // exact match found -> return + if( ePrimCountry == COUNTRY_DONTKNOW ) + ePrimCountry = pEntry->meCountry; + ++pEntry; // one entry forward for next find_if() call + } + } + while( pEntry != pEnd ); + + return ePrimCountry; +} + +LanguageType ConvertCountryToLanguage( CountryId eCountry ) +{ + // just find the first occurrence of eCountry and return the language type + const CountryEntry* pEntry = std::find_if( pTable, pEnd, CountryEntryPred_Country( eCountry ) ); + return (pEntry != pEnd) ? pEntry->meLanguage : LANGUAGE_DONTKNOW; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/dffpropset.cxx b/filter/source/msfilter/dffpropset.cxx new file mode 100644 index 000000000..e6ef672b0 --- /dev/null +++ b/filter/source/msfilter/dffpropset.cxx @@ -0,0 +1,1360 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +const DffPropSetEntry mso_PropSetDefaults[] = { + +// 0 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, + +// 64 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0 }, // DFF_Prop_LockAgainstGrouping + +// 128 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x0010 }, // DFF_Prop_FitTextToShape + +// 192 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0 }, // DFF_Prop_gtextFStrikethrough + +//256 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0 }, // DFF_Prop_pictureActive + +// 320 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x0039 }, // DFF_Prop_fFillOK + +// 384 +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0xffffff }, // DFF_Prop_fillColor +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x001c }, // DFF_Prop_fNoFillHitTest + +// 448 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x001e }, // DFF_Prop_fNoLineDrawDash + +// 512 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0 }, // DFF_Prop_fshadowObscured + +// 576 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0 }, // DFF_Prop_fPerspective + +// 640 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x0001 }, // DFF_Prop_fc3DLightFace + +// 704 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x0016 }, // DFF_Prop_fc3DFillHarsh + +// 768 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0 }, // DFF_Prop_fBackground + +// 832 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x0010 }, // DFF_Prop_fCalloutLengthSpecified + +// 896 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { true, false, false, true }, 0, 0x0001 }, // DFF_Prop_fPrint + +// 960 +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 }, +{ { false, false, false, false }, 0, 0 } + +}; + +DffPropSet::DffPropSet() +{ + mpPropSetEntries = reinterpret_cast< DffPropSetEntry* >( new sal_uInt8[ 1024 * sizeof( DffPropSetEntry ) ] ); +} + +DffPropSet::~DffPropSet() +{ + delete[] reinterpret_cast< sal_uInt8* >( mpPropSetEntries ); +} + +void DffPropSet::ReadPropSet( SvStream& rIn, bool bSetUninitializedOnly ) +{ + DffRecordHeader aHd; + ReadDffRecordHeader( rIn, aHd ); + + if ( !bSetUninitializedOnly ) + { + InitializePropSet( aHd.nRecType ); + maOffsets.clear(); + } + + sal_uInt32 nPropCount = aHd.nRecInstance; + + sal_uInt32 nComplexDataFilePos = rIn.Tell() + ( nPropCount * 6 ); + + const size_t nMaxPossibleRecords = rIn.remainingSize() / (sizeof(sal_uInt16) + sizeof(sal_uInt32)); + if (nPropCount > nMaxPossibleRecords) + { + SAL_WARN("filter.ms", "Parsing error: " << nMaxPossibleRecords << + " max possible entries, but " << nPropCount << " claimed, truncating"); + nPropCount = nMaxPossibleRecords; + } + + for (sal_uInt32 nPropNum = 0; nPropNum < nPropCount; ++nPropNum) + { + sal_uInt16 nTmp(0); + sal_uInt32 nContent(0); + rIn.ReadUInt16( nTmp ) + .ReadUInt32( nContent ); + + sal_uInt32 nRecType = nTmp & 0x3fff; + + if ( nRecType > 0x3ff ) + break; + if ( ( nRecType & 0x3f ) == 0x3f ) + { + if ( bSetUninitializedOnly ) + { + sal_uInt32 nCurrentFlags = mpPropSetEntries[ nRecType ].nContent; + sal_uInt32 nMergeFlags = nContent; + + nMergeFlags &= ( nMergeFlags >> 16 ) | 0xffff0000; // clearing low word + nMergeFlags &= ( ( nCurrentFlags & 0xffff0000 ) // remove already hard set + | ( nCurrentFlags >> 16 ) ) ^ 0xffffffff; // attributes from mergeflags + nCurrentFlags &= ( ( nMergeFlags & 0xffff0000 ) // apply zero master bits + | ( nMergeFlags >> 16 ) ) ^ 0xffffffff; + nCurrentFlags |= static_cast(nMergeFlags); // apply filled master bits + mpPropSetEntries[ nRecType ].nContent = nCurrentFlags; + mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr |= static_cast< sal_uInt16 >( nContent >> 16 ); + } + else + { + // clear flags that have to be cleared + mpPropSetEntries[ nRecType ].nContent &= ( ( nContent >> 16 ) ^ 0xffffffff ); + // set flags that have to be set + mpPropSetEntries[ nRecType ].nContent |= nContent; + mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr = static_cast< sal_uInt16 >( nContent >> 16 ); + } + } + else + { + bool bSetProperty = !bSetUninitializedOnly || ( !IsProperty( nRecType ) || !IsHardAttribute( nRecType ) ); + + DffPropFlags aPropFlag = { true, false, false, false }; + if ( nTmp & 0x4000 ) + aPropFlag.bBlip = true; + if ( nTmp & 0x8000 ) + aPropFlag.bComplex = true; + if ( aPropFlag.bComplex && nContent && ( nComplexDataFilePos < aHd.GetRecEndFilePos() ) ) + { + // normally nContent is the complete size of the complex property, + // but this is not always true for IMsoArrays ( what the hell is a IMsoArray ? ) + + // I love special treatments :-( + if ( ( nRecType == DFF_Prop_pVertices ) || ( nRecType == DFF_Prop_pSegmentInfo ) + || ( nRecType == DFF_Prop_fillShadeColors ) || ( nRecType == DFF_Prop_lineDashStyle ) + || ( nRecType == DFF_Prop_pWrapPolygonVertices ) || ( nRecType == DFF_Prop_connectorPoints ) + || ( nRecType == DFF_Prop_Handles ) || ( nRecType == DFF_Prop_pFormulas ) + || ( nRecType == DFF_Prop_textRectangles ) ) + { + // now check if the current content size is possible, or 6 bytes too small + sal_uInt32 nOldPos = rIn.Tell(); + + sal_Int16 nNumElem(0), nNumElemReserved(0), nSize(0); + if (checkSeek(rIn, nComplexDataFilePos)) + rIn.ReadInt16(nNumElem).ReadInt16(nNumElemReserved).ReadInt16(nSize); + if (nNumElemReserved >= nNumElem) + { + // the size of these array elements is nowhere defined, + // what if the size is negative ? + // ok, we will make it positive and shift it. + // for -16 this works + if ( nSize < 0 ) + nSize = ( -nSize ) >> 2; + sal_uInt32 nDataSize = static_cast( nSize * nNumElem ); + + // sometimes the content size is 6 bytes too small (array header information is missing ) + if ( nDataSize == nContent ) + nContent += 6; + + // check if array fits into the PropertyContainer + if ( ( nComplexDataFilePos + nContent ) > aHd.GetRecEndFilePos() ) + nContent = 0; + } + else + nContent = 0; + rIn.Seek( nOldPos ); + } + if ( nContent ) + { + if ( bSetProperty ) + { + mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr = static_cast< sal_uInt16 >( maOffsets.size() ); + maOffsets.push_back( nComplexDataFilePos ); // insert the filepos of this property; + } + nComplexDataFilePos += nContent; // store filepos, that is used for the next complex property + } + else // a complex property needs content + aPropFlag.bSet = false; // otherwise something is wrong + } + if ( bSetProperty ) + { + // tdf#130262: ignore negative values for distances (maybe this list needs to be extended) + // LO does not allow negative values but [MS-ODRAW] does not forbid them + if ( nRecType == DFF_Prop_dxWrapDistLeft || nRecType == DFF_Prop_dxWrapDistRight + || nRecType == DFF_Prop_dyWrapDistTop || nRecType == DFF_Prop_dyWrapDistBottom ) + { + if ( static_cast(nContent) < 0 ) + { + break; + } + } + + mpPropSetEntries[ nRecType ].nContent = nContent; + mpPropSetEntries[ nRecType ].aFlags = aPropFlag; + } + } + } + aHd.SeekToEndOfRecord( rIn ); +} + +SvStream& ReadDffPropSet( SvStream& rIn, DffPropSet& rRec ) +{ + rRec.ReadPropSet( rIn, false ); + return rIn; +} + +SvStream& operator|=( SvStream& rIn, DffPropSet& rRec ) +{ + rRec.ReadPropSet( rIn, true ); + return rIn; +} + +void DffPropSet::InitializePropSet( sal_uInt16 nPropSetType ) const +{ + /* + cmc: + " Boolean properties are grouped in bitfields by property set; note that + the Boolean properties in each property set are contiguous. They are saved + under the property ID of the last Boolean property in the set, and are + placed in the value field in reverse order starting with the last property + in the low bit. " + + e.g. + + fEditedWrap + fBehindDocument + fOnDblClickNotify + fIsButton + fOneD + fHidden + fPrint + + are all part of a group and all are by default false except for fPrint, + which equates to a default bit sequence for the group of 0000001 -> 0x1 + + If at a later stage word sets fBehindDocument away from the default it + will be done by having a property named fPrint whose bitsequence will have + the fBehindDocument bit set. e.g. a DFF_Prop_fPrint with value 0x200020 + has set bit 6 on so as to enable fBehindDocument (as well as disabling + everything else) + */ + if ( nPropSetType == DFF_msofbtOPT ) + { + memcpy( mpPropSetEntries, mso_PropSetDefaults, 0x400 * sizeof( DffPropSetEntry ) ); + } + else + { + memset( mpPropSetEntries, 0, 0x400 * sizeof( DffPropSetEntry ) ); + } +} + +bool DffPropSet::IsHardAttribute( sal_uInt32 nId ) const +{ + bool bRetValue = true; + nId &= 0x3ff; + if ( ( nId & 0x3f ) >= 48 ) // is this a flag id + bRetValue = (mpPropSetEntries[nId | 0x3f].nComplexIndexOrFlagsHAttr + & (1 << (0xf - (nId & 0xf)))) != 0; + else + bRetValue = !mpPropSetEntries[ nId ].aFlags.bSoftAttr; + return bRetValue; +}; + +sal_uInt32 DffPropSet::GetPropertyValue( sal_uInt32 nId, sal_uInt32 nDefault ) const +{ + nId &= 0x3ff; + return ( mpPropSetEntries[ nId ].aFlags.bSet ) ? mpPropSetEntries[ nId ].nContent : nDefault; +}; + +bool DffPropSet::GetPropertyBool( sal_uInt32 nId ) const +{ + sal_uInt32 nBaseId = nId | 31; // base ID to get the sal_uInt32 property value + sal_uInt32 nMask = 1 << (nBaseId - nId); // bit mask of the boolean property + + sal_uInt32 nPropValue = GetPropertyValue( nBaseId, 0 ); + return (nPropValue & nMask) != 0; +} + +OUString DffPropSet::GetPropertyString( sal_uInt32 nId, SvStream& rStrm ) const +{ + sal_uInt64 const nOldPos = rStrm.Tell(); + OUStringBuffer aBuffer; + sal_uInt32 nBufferSize = GetPropertyValue( nId, 0 ); + if( (nBufferSize > 0) && SeekToContent( nId, rStrm ) ) + { + sal_Int32 nStrLen = static_cast< sal_Int32 >( nBufferSize / 2 ); + //clip initial size of buffer to something sane in case of silly length + //strings. If there really is a silly amount of data available it still + //works out ok of course + aBuffer.ensureCapacity(std::min(nStrLen,static_cast(8192))); + for( sal_Int32 nCharIdx = 0; nCharIdx < nStrLen; ++nCharIdx ) + { + sal_uInt16 nChar = 0; + rStrm.ReadUInt16( nChar ); + if( nChar > 0 ) + aBuffer.append( static_cast< sal_Unicode >( nChar ) ); + else + break; + } + } + rStrm.Seek( nOldPos ); + return aBuffer.makeStringAndClear(); +} + +bool DffPropSet::SeekToContent( sal_uInt32 nRecType, SvStream& rStrm ) const +{ + nRecType &= 0x3ff; + if ( mpPropSetEntries[ nRecType ].aFlags.bSet ) + { + if ( mpPropSetEntries[ nRecType ].aFlags.bComplex ) + { + sal_uInt16 nIndex = mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr; + if ( nIndex < maOffsets.size() ) + { + return checkSeek(rStrm, maOffsets[nIndex]); + } + } + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/dffrecordheader.cxx b/filter/source/msfilter/dffrecordheader.cxx new file mode 100644 index 000000000..c94bec53b --- /dev/null +++ b/filter/source/msfilter/dffrecordheader.cxx @@ -0,0 +1,43 @@ +/* -*- 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 + +bool ReadDffRecordHeader(SvStream& rIn, DffRecordHeader& rRec) +{ + rRec.nFilePos = rIn.Tell(); + sal_uInt16 nTmp(0); + rIn.ReadUInt16(nTmp); + rRec.nImpVerInst = nTmp; + rRec.nRecVer = sal::static_int_cast(nTmp & 0x000F); + rRec.nRecInstance = nTmp >> 4; + rRec.nRecType = 0; + rIn.ReadUInt16(rRec.nRecType); + rRec.nRecLen = 0; + rIn.ReadUInt32(rRec.nRecLen); + + // preserving overflow, optimally we would check + // the record size against the parent header + if (rRec.nRecLen > (SAL_MAX_UINT32 - rRec.nFilePos)) + rIn.SetError(SVSTREAM_FILEFORMAT_ERROR); + + return rIn.good(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx new file mode 100644 index 000000000..5f84a0df7 --- /dev/null +++ b/filter/source/msfilter/escherex.cxx @@ -0,0 +1,5295 @@ +/* -*- 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 "eschesdo.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace css; + +EscherExContainer::EscherExContainer( SvStream& rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance ) : + rStrm ( rSt ) +{ + rStrm.WriteUInt32( ( 0xf | ( nInstance << 4 ) ) | ( nRecType << 16 ) ).WriteUInt32( 0 ); + nContPos = rStrm.Tell(); +} +EscherExContainer::~EscherExContainer() +{ + sal_uInt32 nPos = rStrm.Tell(); + sal_uInt32 nSize= nPos - nContPos; + if ( nSize ) + { + rStrm.Seek( nContPos - 4 ); + rStrm.WriteUInt32( nSize ); + rStrm.Seek( nPos ); + } +} + +EscherExAtom::EscherExAtom( SvStream& rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance, const sal_uInt8 nVersion ) : + rStrm ( rSt ) +{ + rStrm.WriteUInt32( ( nVersion | ( nInstance << 4 ) ) | ( nRecType << 16 ) ).WriteUInt32( 0 ); + nContPos = rStrm.Tell(); +} +EscherExAtom::~EscherExAtom() +{ + sal_uInt32 nPos = rStrm.Tell(); + sal_uInt32 nSize= nPos - nContPos; + if ( nSize ) + { + rStrm.Seek( nContPos - 4 ); + rStrm.WriteUInt32( nSize ); + rStrm.Seek( nPos ); + } +} + +EscherExClientRecord_Base::~EscherExClientRecord_Base() +{ +} + +EscherExClientAnchor_Base::~EscherExClientAnchor_Base() +{ +} + +EscherPropertyContainer::EscherPropertyContainer( + EscherGraphicProvider * pGraphProv, SvStream * pPiOutStrm, + tools::Rectangle * pBoundRect): + pGraphicProvider(pGraphProv), + pPicOutStrm(pPiOutStrm), + pShapeBoundRect(pBoundRect), + nCountCount(0), + nCountSize(0), + bHasComplexData(false) +{ + pSortStruct.reserve(64); +} + +EscherPropertyContainer::EscherPropertyContainer() + : EscherPropertyContainer(nullptr, nullptr, nullptr) +{} + +EscherPropertyContainer::EscherPropertyContainer( + EscherGraphicProvider& rGraphProv, + SvStream* pPiOutStrm, + tools::Rectangle& rBoundRect ) : + EscherPropertyContainer(&rGraphProv, pPiOutStrm, &rBoundRect) +{} + +EscherPropertyContainer::~EscherPropertyContainer() +{ +}; + +void EscherPropertyContainer::AddOpt( + sal_uInt16 nPropID, + bool bBlib, + sal_uInt32 nSizeReduction, + SvMemoryStream& rStream) +{ + sal_uInt8 const* pBuf(static_cast(rStream.GetData())); + const sal_uInt64 nSize(rStream.GetSize()); + std::vector aBuf; + aBuf.reserve(nSize); + + for(sal_uInt64 a(0); a < nSize; a++) + { + aBuf.push_back(*pBuf++); + } + + sal_uInt32 nPropValue(static_cast(nSize)); + + if(0 != nSizeReduction && nPropValue > nSizeReduction) + { + nPropValue -= nSizeReduction; + } + + AddOpt(nPropID, bBlib, nPropValue, aBuf); +} + +void EscherPropertyContainer::AddOpt( + sal_uInt16 nPropID, + sal_uInt32 nPropValue, + bool bBlib) +{ + AddOpt(nPropID, bBlib, nPropValue, std::vector()); +} + +void EscherPropertyContainer::AddOpt( + sal_uInt16 nPropID, + const OUString& rString) +{ + std::vector aBuf; + aBuf.reserve(rString.getLength() * 2 + 2); + + for(sal_Int32 i(0); i < rString.getLength(); i++) + { + const sal_Unicode nUnicode(rString[i]); + aBuf.push_back(static_cast(nUnicode)); + aBuf.push_back(static_cast(nUnicode >> 8)); + } + + aBuf.push_back(0); + aBuf.push_back(0); + + AddOpt(nPropID, true, aBuf.size(), aBuf); +} + +void EscherPropertyContainer::AddOpt( + sal_uInt16 nPropID, + bool bBlib, + sal_uInt32 nPropValue, + const std::vector& rProp) +{ + if ( bBlib ) // bBlib is only valid when fComplex = 0 + nPropID |= 0x4000; + if ( !rProp.empty() ) + nPropID |= 0x8000; // fComplex = sal_True; + + for( size_t i = 0; i < pSortStruct.size(); i++ ) + { + if ( ( pSortStruct[ i ].nPropId &~0xc000 ) == ( nPropID &~0xc000 ) ) // check, whether the Property only gets replaced + { + pSortStruct[ i ].nPropId = nPropID; + if ( !pSortStruct[ i ].nProp.empty() ) + { + nCountSize -= pSortStruct[ i ].nProp.size(); + } + pSortStruct[ i ].nProp = rProp; + pSortStruct[ i ].nPropValue = nPropValue; + if ( !rProp.empty() ) + nCountSize += rProp.size(); + return; + } + } + nCountCount++; + nCountSize += 6; + pSortStruct.emplace_back(); + pSortStruct.back().nPropId = nPropID; // insert property + pSortStruct.back().nProp = rProp; + pSortStruct.back().nPropValue = nPropValue; + + if ( !rProp.empty() ) + { + nCountSize += rProp.size(); + bHasComplexData = true; + } +} + +bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId, sal_uInt32& rPropValue ) const +{ + EscherPropSortStruct aPropStruct; + + if ( GetOpt( nPropId, aPropStruct ) ) + { + rPropValue = aPropStruct.nPropValue; + return true; + } + return false; +} + +bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId, EscherPropSortStruct& rPropValue ) const +{ + for( size_t i = 0; i < pSortStruct.size(); i++ ) + { + if ( ( pSortStruct[ i ].nPropId &~0xc000 ) == ( nPropId &~0xc000 ) ) + { + rPropValue = pSortStruct[ i ]; + return true; + } + } + return false; +} + +const EscherProperties & EscherPropertyContainer::GetOpts() const +{ + return pSortStruct; +} + +extern "C" { + +static int EscherPropSortFunc( const void* p1, const void* p2 ) +{ + sal_Int16 nID1 = static_cast(p1)->nPropId &~0xc000; + sal_Int16 nID2 = static_cast(p2)->nPropId &~0xc000; + + if( nID1 < nID2 ) + return -1; + else if( nID1 > nID2 ) + return 1; + else + return 0; +} + +} + +void EscherPropertyContainer::Commit( SvStream& rSt, sal_uInt16 nVersion, sal_uInt16 nRecType ) +{ + rSt.WriteUInt16( ( nCountCount << 4 ) | ( nVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nCountSize ); + if ( pSortStruct.empty() ) + return; + + qsort( pSortStruct.data(), pSortStruct.size(), sizeof( EscherPropSortStruct ), EscherPropSortFunc ); + + for ( size_t i = 0; i < pSortStruct.size(); i++ ) + { + sal_uInt32 nPropValue = pSortStruct[ i ].nPropValue; + sal_uInt16 nPropId = pSortStruct[ i ].nPropId; + + rSt.WriteUInt16( nPropId ) + .WriteUInt32( nPropValue ); + } + if ( bHasComplexData ) + { + for ( size_t i = 0; i < pSortStruct.size(); i++ ) + { + if ( !pSortStruct[ i ].nProp.empty() ) + rSt.WriteBytes( + pSortStruct[i].nProp.data(), + pSortStruct[i].nProp.size()); + } + } +} + +bool EscherPropertyContainer::IsFontWork() const +{ + sal_uInt32 nTextPathFlags = 0; + GetOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags ); + return ( nTextPathFlags & 0x4000 ) != 0; +} + +sal_uInt32 EscherPropertyContainer::ImplGetColor( const sal_uInt32 nSOColor, bool bSwap ) +{ + if ( bSwap ) + { + sal_uInt32 nColor = nSOColor & 0xff00; // green + nColor |= static_cast(nSOColor) << 16; // red + nColor |= static_cast( nSOColor >> 16 ); // blue + return nColor; + } + else + return nSOColor & 0xffffff; +} + +sal_uInt32 EscherPropertyContainer::GetGradientColor( + const awt::Gradient* pGradient, + sal_uInt32 nStartColor ) +{ + sal_uInt32 nIntensity = 100; + Color aColor; + + if ( pGradient ) + { + if ( nStartColor & 1 ) + { + nIntensity = pGradient->StartIntensity; + aColor = Color(ColorTransparency, pGradient->StartColor); + } + else + { + nIntensity = pGradient->EndIntensity; + aColor = Color(ColorTransparency, pGradient->EndColor); + } + } + sal_uInt32 nRed = ( aColor.GetRed() * nIntensity ) / 100; + sal_uInt32 nGreen = ( ( aColor.GetGreen() * nIntensity ) / 100 ) << 8; + sal_uInt32 nBlue = ( ( aColor.GetBlue() * nIntensity ) / 100 ) << 16; + return nRed | nGreen | nBlue; +} + +void EscherPropertyContainer::CreateGradientProperties( + const awt::Gradient & rGradient ) +{ + sal_uInt32 nFillType = ESCHER_FillShadeScale; + sal_uInt32 nAngle = 0; + sal_uInt32 nFillFocus = 0; + sal_uInt32 nFillLR = 0; + sal_uInt32 nFillTB = 0; + sal_uInt32 nFirstColor = 0; + bool bWriteFillTo = false; + + switch ( rGradient.Style ) + { + case awt::GradientStyle_LINEAR : + case awt::GradientStyle_AXIAL : + { + nFillType = ESCHER_FillShadeScale; + nAngle = (rGradient.Angle * 0x10000) / 10; + nFillFocus = (sal::static_int_cast(rGradient.Style) == + sal::static_int_cast(GradientStyle::Linear)) ? 0 : 50; + } + break; + case awt::GradientStyle_RADIAL : + case awt::GradientStyle_ELLIPTICAL : + case awt::GradientStyle_SQUARE : + case awt::GradientStyle_RECT : + { + nFillLR = (rGradient.XOffset * 0x10000) / 100; + nFillTB = (rGradient.YOffset * 0x10000) / 100; + if ( ((nFillLR > 0) && (nFillLR < 0x10000)) || ((nFillTB > 0) && (nFillTB < 0x10000)) ) + nFillType = ESCHER_FillShadeShape; + else + nFillType = ESCHER_FillShadeCenter; + nFirstColor = 1; + bWriteFillTo = true; + } + break; + case awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE : break; + } + AddOpt( ESCHER_Prop_fillType, nFillType ); + AddOpt( ESCHER_Prop_fillAngle, nAngle ); + AddOpt( ESCHER_Prop_fillColor, GetGradientColor( &rGradient, nFirstColor ) ); + AddOpt( ESCHER_Prop_fillBackColor, GetGradientColor( &rGradient, nFirstColor ^ 1 ) ); + AddOpt( ESCHER_Prop_fillFocus, nFillFocus ); + if ( bWriteFillTo ) + { + AddOpt( ESCHER_Prop_fillToLeft, nFillLR ); + AddOpt( ESCHER_Prop_fillToTop, nFillTB ); + AddOpt( ESCHER_Prop_fillToRight, nFillLR ); + AddOpt( ESCHER_Prop_fillToBottom, nFillTB ); + } +} + +void EscherPropertyContainer::CreateGradientProperties( + const uno::Reference & rXPropSet , bool bTransparentGradient) +{ + uno::Any aAny; + awt::Gradient const * pGradient = nullptr; + + sal_uInt32 nFillType = ESCHER_FillShadeScale; + sal_Int32 nAngle = 0; + sal_uInt32 nFillFocus = 0; + sal_uInt32 nFillLR = 0; + sal_uInt32 nFillTB = 0; + sal_uInt32 nFirstColor = 0;// like the control var nChgColors in import logic + bool bWriteFillTo = false; + + // Transparency gradient: Means the third setting in transparency page is set + if (bTransparentGradient && EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "FillTransparenceGradient" ) ) + { + pGradient = o3tl::doAccess(aAny); + + uno::Any aAnyTemp; + if ( EscherPropertyValueHelper::GetPropertyValue( + aAnyTemp, rXPropSet, "FillStyle" ) ) + { + drawing::FillStyle eFS; + if ( ! ( aAnyTemp >>= eFS ) ) + eFS = drawing::FillStyle_SOLID; + // solid and transparency + if ( eFS == drawing::FillStyle_SOLID) + { + if ( EscherPropertyValueHelper::GetPropertyValue( + aAnyTemp, rXPropSet, "FillColor" ) ) + { + const_cast(pGradient)->StartColor = ImplGetColor( *o3tl::doAccess(aAnyTemp), false ); + const_cast(pGradient)->EndColor = ImplGetColor( *o3tl::doAccess(aAnyTemp), false ); + } + } + // gradient and transparency. + else if( eFS == drawing::FillStyle_GRADIENT ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "FillGradient" ) ) + pGradient = o3tl::doAccess(aAny); + } + } + + } + // Not transparency gradient + else if ( EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "FillGradient" ) ) + { + pGradient = o3tl::doAccess(aAny); + } + + if ( pGradient ) + { + switch ( pGradient->Style ) + { + case awt::GradientStyle_LINEAR : + case awt::GradientStyle_AXIAL : + { + nFillType = ESCHER_FillShadeScale; + nAngle = pGradient->Angle; + while ( nAngle > 0 ) nAngle -= 3600; + while ( nAngle <= -3600 ) nAngle += 3600; + // Value of the real number = Integral + (Fractional / 65536.0) + nAngle = ( nAngle * 0x10000) / 10; + + nFillFocus = (pGradient->Style == awt::GradientStyle_LINEAR) ? + ( pGradient->XOffset + pGradient->YOffset )/2 : -50; + if( !nFillFocus ) + nFirstColor=nFirstColor ^ 1; + if ( !nAngle ) + nFirstColor=nFirstColor ^ 1; + } + break; + case awt::GradientStyle_RADIAL : + case awt::GradientStyle_ELLIPTICAL : + case awt::GradientStyle_SQUARE : + case awt::GradientStyle_RECT : + { + // according to the import logic and rect type fill** value + nFillLR = (pGradient->XOffset * 0x10000) / 100; + nFillTB = (pGradient->YOffset * 0x10000) / 100; + if ( ((nFillLR > 0) && (nFillLR < 0x10000)) || ((nFillTB > 0) && (nFillTB < 0x10000)) ) + nFillType = ESCHER_FillShadeShape; + else + nFillType = ESCHER_FillShadeCenter; + nFirstColor = 1; + bWriteFillTo = true; + } + break; + default: break; + } + } + + AddOpt( ESCHER_Prop_fillType, nFillType ); + AddOpt( ESCHER_Prop_fillAngle, nAngle ); + AddOpt( ESCHER_Prop_fillColor, GetGradientColor( pGradient, nFirstColor ) ); + AddOpt( ESCHER_Prop_fillBackColor, GetGradientColor( pGradient, nFirstColor ^ 1 ) ); + AddOpt( ESCHER_Prop_fillFocus, nFillFocus ); + if ( bWriteFillTo ) + { + // according to rect type fillTo** value + if(nFillLR) + { + AddOpt( ESCHER_Prop_fillToLeft, nFillLR ); + AddOpt( ESCHER_Prop_fillToRight, nFillLR ); + } + if(nFillTB) + { + AddOpt( ESCHER_Prop_fillToTop, nFillTB ); + AddOpt( ESCHER_Prop_fillToBottom, nFillTB ); + } + } + + // Transparency gradient + if (bTransparentGradient && EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "FillTransparenceGradient" ) ) + { + pGradient = o3tl::doAccess(aAny); + if ( pGradient ) + { + sal_uInt32 nBlue = GetGradientColor( pGradient, nFirstColor ) >> 16; + AddOpt( ESCHER_Prop_fillOpacity,( ( 100 - ( nBlue * 100 / 255 ) ) << 16 ) / 100 ); + nBlue = GetGradientColor( pGradient, nFirstColor ^ 1 ) >>16 ; + AddOpt( ESCHER_Prop_fillBackOpacity,( ( 100 - ( nBlue * 100 / 255 ) ) << 16 )/ 100 ); + } + } +} + +void EscherPropertyContainer::CreateFillProperties( + const uno::Reference & rXPropSet, + bool bEdge , const uno::Reference & rXShape ) +{ + if ( rXShape.is() ) + { + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rXShape); + if ( pObj ) + { + const SfxItemSet& aAttr( pObj->GetMergedItemSet() ); + // transparency with gradient. Means the third setting in transparency page is set + bool bTransparentGradient = ( aAttr.GetItemState( XATTR_FILLFLOATTRANSPARENCE ) == SfxItemState::SET ) && + aAttr.Get( XATTR_FILLFLOATTRANSPARENCE ).IsEnabled(); + CreateFillProperties( rXPropSet, bEdge, bTransparentGradient ); + } + } +} + +void EscherPropertyContainer::CreateFillProperties( + const uno::Reference & rXPropSet, + bool bEdge , bool bTransparentGradient) + +{ + uno::Any aAny; + AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone ); + AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle ); + static const OUStringLiteral aPropName( u"FillStyle" ); + + if ( EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, aPropName ) ) + { + drawing::FillStyle eFS; + if ( ! ( aAny >>= eFS ) ) + eFS = drawing::FillStyle_SOLID; + sal_uInt32 nFillBackColor = 0; + switch( eFS ) + { + case drawing::FillStyle_GRADIENT : + { + CreateGradientProperties( rXPropSet , bTransparentGradient ); + AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 ); + } + break; + + case drawing::FillStyle_BITMAP : + { + CreateGraphicProperties(rXPropSet, "FillBitmap", true); + AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 ); + AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor ); + } + break; + case drawing::FillStyle_HATCH : + { + CreateGraphicProperties( rXPropSet, "FillHatch", true ); + } + break; + case drawing::FillStyle_SOLID : + default: + { + if ( bTransparentGradient ) + CreateGradientProperties( rXPropSet , bTransparentGradient ); + else + { + beans::PropertyState ePropState = EscherPropertyValueHelper::GetPropertyState( + rXPropSet, aPropName ); + if ( ePropState == beans::PropertyState_DIRECT_VALUE ) + AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid ); + + if ( EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "FillColor" ) ) + { + sal_uInt32 nFillColor = ImplGetColor( *o3tl::doAccess(aAny) ); + nFillBackColor = nFillColor ^ 0xffffff; + AddOpt( ESCHER_Prop_fillColor, nFillColor ); + } + AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100010 ); + AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor ); + } + break; + } + case drawing::FillStyle_NONE : + AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); + break; + } + if ( eFS != drawing::FillStyle_NONE ) + { + sal_uInt16 nTransparency = ( EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "FillTransparence", true ) ) + ? *o3tl::doAccess(aAny) : 0; + if ( nTransparency ) + AddOpt( ESCHER_Prop_fillOpacity, ( ( 100 - nTransparency ) << 16 ) / 100 ); + } + } + CreateLineProperties( rXPropSet, bEdge ); +} + +void EscherPropertyContainer::CreateTextProperties( + const uno::Reference< beans::XPropertySet > & rXPropSet, sal_uInt32 nTextId, + const bool bIsCustomShape, const bool bIsTextFrame ) +{ + uno::Any aAny; + text::WritingMode eWM( text::WritingMode_LR_TB ); + drawing::TextVerticalAdjust eVA( drawing::TextVerticalAdjust_TOP ); + drawing::TextHorizontalAdjust eHA( drawing::TextHorizontalAdjust_LEFT ); + + sal_Int32 nLeft ( 0 ); + sal_Int32 nTop ( 0 ); + sal_Int32 nRight ( 0 ); + sal_Int32 nBottom ( 0 ); + + // used with normal shapes: + bool bAutoGrowWidth ( false ); + const bool bAutoGrowHeight ( false ); //#ii63936 not setting autogrowheight, because minframeheight would be ignored + // used with ashapes: + bool bWordWrap ( false ); + bool bAutoGrowSize ( false ); + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWritingMode", true ) ) + aAny >>= eWM; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextVerticalAdjust", true ) ) + aAny >>= eVA; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextHorizontalAdjust", true ) ) + aAny >>= eHA; + if ( bIsCustomShape ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWordWrap" ) ) + aAny >>= bWordWrap; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", true ) ) + aAny >>= bAutoGrowSize; + } + else if ( bIsTextFrame ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowWidth", true ) ) + aAny >>= bAutoGrowWidth; + +// i63936 not setting autogrowheight, because otherwise +// the minframeheight of the text will be ignored +// +// if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", sal_True ) ) +// aAny >>= bAutoGrowHeight; + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextLeftDistance" ) ) + aAny >>= nLeft; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextUpperDistance" ) ) + aAny >>= nTop; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextRightDistance" ) ) + aAny >>= nRight; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextLowerDistance" ) ) + aAny >>= nBottom; + + ESCHER_AnchorText eAnchor = ESCHER_AnchorTop; + ESCHER_WrapMode eWrapMode = ESCHER_WrapSquare; + sal_uInt32 nTextAttr = 0x40004; // rotate text with shape + + if ( eWM == text::WritingMode_TB_RL ) + { // vertical writing + switch ( eHA ) + { + case drawing::TextHorizontalAdjust_LEFT : + eAnchor = ESCHER_AnchorBottom; + break; + case drawing::TextHorizontalAdjust_CENTER : + eAnchor = ESCHER_AnchorMiddle; + break; + default : + case drawing::TextHorizontalAdjust_BLOCK : + case drawing::TextHorizontalAdjust_RIGHT : + eAnchor = ESCHER_AnchorTop; + break; + } + if ( eVA == drawing::TextVerticalAdjust_CENTER ) + { + switch ( eAnchor ) + { + case ESCHER_AnchorMiddle : + eAnchor = ESCHER_AnchorMiddleCentered; + break; + case ESCHER_AnchorBottom : + eAnchor = ESCHER_AnchorBottomCentered; + break; + default : + case ESCHER_AnchorTop : + eAnchor = ESCHER_AnchorTopCentered; + break; + } + } + if ( bIsCustomShape ) + { + if ( bWordWrap ) + eWrapMode = ESCHER_WrapSquare; + else + eWrapMode = ESCHER_WrapNone; + if ( bAutoGrowSize ) + nTextAttr |= 0x20002; + } + else + { + if ( bAutoGrowHeight ) + eWrapMode = ESCHER_WrapNone; + if ( bAutoGrowWidth ) + nTextAttr |= 0x20002; + } + + AddOpt( ESCHER_Prop_txflTextFlow, ESCHER_txflTtoBA ); // rotate text within shape by 90 + } + else + { // normal from left to right + switch ( eVA ) + { + case drawing::TextVerticalAdjust_CENTER : + eAnchor = ESCHER_AnchorMiddle; + break; + + case drawing::TextVerticalAdjust_BOTTOM : + eAnchor = ESCHER_AnchorBottom; + break; + + default : + case drawing::TextVerticalAdjust_TOP : + eAnchor = ESCHER_AnchorTop; + break; + } + if ( eHA == drawing::TextHorizontalAdjust_CENTER ) + { + switch( eAnchor ) + { + case ESCHER_AnchorMiddle : + eAnchor = ESCHER_AnchorMiddleCentered; + break; + case ESCHER_AnchorBottom : + eAnchor = ESCHER_AnchorBottomCentered; + break; + case ESCHER_AnchorTop : + eAnchor = ESCHER_AnchorTopCentered; + break; + default: break; + } + } + if ( bIsCustomShape ) + { + if ( bWordWrap ) + eWrapMode = ESCHER_WrapSquare; + else + eWrapMode = ESCHER_WrapNone; + if ( bAutoGrowSize ) + nTextAttr |= 0x20002; + } + else + { + if ( bAutoGrowWidth ) + eWrapMode = ESCHER_WrapNone; + if ( bAutoGrowHeight ) + nTextAttr |= 0x20002; + } + } + AddOpt( ESCHER_Prop_dxTextLeft, nLeft * 360 ); + AddOpt( ESCHER_Prop_dxTextRight, nRight * 360 ); + AddOpt( ESCHER_Prop_dyTextTop, nTop * 360 ); + AddOpt( ESCHER_Prop_dyTextBottom, nBottom * 360 ); + + AddOpt( ESCHER_Prop_WrapText, eWrapMode ); + AddOpt( ESCHER_Prop_AnchorText, eAnchor ); + AddOpt( ESCHER_Prop_FitTextToShape, nTextAttr ); + + if ( nTextId ) + AddOpt( ESCHER_Prop_lTxid, nTextId ); + + // n#404221: In case of rotation we need to write the txtflTextFlow + // attribute too. + // fdo#58204: not custom shapes (TODO: other cases when it doesn't work?) + if (!bIsTextFrame || bIsCustomShape) + return; + + sal_uInt16 nAngle = EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "RotateAngle", true ) ? + static_cast( ( *o3tl::doAccess(aAny) ) + 5 ) / 10 : 0; + if (nAngle==900) + { + AddOpt( ESCHER_Prop_txflTextFlow, ESCHER_txflBtoT ); + } + if (nAngle==2700) + { + AddOpt( ESCHER_Prop_txflTextFlow, ESCHER_txflTtoBA ); + } +} + +bool EscherPropertyContainer::GetLineArrow( const bool bLineStart, + const uno::Reference & rXPropSet, + ESCHER_LineEnd& reLineEnd, sal_Int32& rnArrowLength, sal_Int32& rnArrowWidth ) +{ + const OUString sLine ( bLineStart ? OUString("LineStart") : OUString("LineEnd") ); + const OUString sLineName ( bLineStart ? OUString("LineStartName") : OUString("LineEndName") ); + + bool bIsArrow = false; + + uno::Any aAny; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, sLine ) ) + { + tools::PolyPolygon aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aAny ) ); + if ( aPolyPoly.Count() && aPolyPoly[ 0 ].GetSize() ) + { + bIsArrow = true; + + reLineEnd = ESCHER_LineArrowEnd; + rnArrowLength = 1; + rnArrowWidth = 1; + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, sLineName ) ) + { + OUString aArrowStartName = *o3tl::doAccess(aAny); + sal_uInt16 nWhich = bLineStart ? sal_uInt16(XATTR_LINESTART) : sal_uInt16(XATTR_LINEEND); + + // remove extra space separated number + sal_Int32 nPos = aArrowStartName.lastIndexOf(' '); + if (nPos > -1 && aArrowStartName.lastIndexOf(' ', nPos) > -1) + aArrowStartName = aArrowStartName.copy(0, nPos); + + OUString aApiName = SvxUnogetApiNameForItem(nWhich, aArrowStartName); + bool bIsMapped = true; + if ( !aApiName.isEmpty() ) + { + + // TODO: calculate the best option for ArrowLength and ArrowWidth + if ( aApiName == "Arrow concave" ) + reLineEnd = ESCHER_LineArrowStealthEnd; + else if ( aApiName == "Square 45" ) + reLineEnd = ESCHER_LineArrowDiamondEnd; + else if ( aApiName == "Small Arrow" ) + reLineEnd = ESCHER_LineArrowEnd; + else if ( aApiName == "Dimension Lines" ) + { + rnArrowLength = 0; + rnArrowWidth = 2; + reLineEnd = ESCHER_LineArrowOvalEnd; + } + else if ( aApiName == "Double Arrow" ) + reLineEnd = ESCHER_LineArrowEnd; + else if ( aApiName == "Rounded short Arrow" ) + reLineEnd = ESCHER_LineArrowEnd; + else if ( aApiName == "Symmetric Arrow" ) + reLineEnd = ESCHER_LineArrowEnd; + else if ( aApiName == "Line Arrow" ) + reLineEnd = ESCHER_LineArrowOpenEnd; + else if ( aApiName == "Rounded large Arrow" ) + reLineEnd = ESCHER_LineArrowEnd; + else if ( aApiName == "Circle" ) + reLineEnd = ESCHER_LineArrowOvalEnd; + else if ( aApiName == "Square" ) + reLineEnd = ESCHER_LineArrowDiamondEnd; + else if ( aApiName == "Arrow" ) + reLineEnd = ESCHER_LineArrowEnd; + else + bIsMapped = false; + + } + if ( !bIsMapped && comphelper::string::getTokenCount(aArrowStartName, ' ') == 2 ) + { + sal_Int32 nIdx{ 0 }; + std::u16string_view aArrowName( o3tl::getToken(aArrowStartName, 0, ' ', nIdx ) ); + if ( aArrowName == u"msArrowEnd" ) + reLineEnd = ESCHER_LineArrowEnd; + else if ( aArrowName == u"msArrowOpenEnd" ) + reLineEnd = ESCHER_LineArrowOpenEnd; + else if ( aArrowName == u"msArrowStealthEnd" ) + reLineEnd = ESCHER_LineArrowStealthEnd; + else if ( aArrowName == u"msArrowDiamondEnd" ) + reLineEnd = ESCHER_LineArrowDiamondEnd; + else if ( aArrowName == u"msArrowOvalEnd" ) + reLineEnd = ESCHER_LineArrowOvalEnd; + else + nIdx = -1; + + // now we have the arrow, and try to determine the arrow size; + if ( nIdx>0 ) + { + std::u16string_view aArrowSize = o3tl::getToken(aArrowStartName, 0, ' ', nIdx ); + sal_Int32 nArrowSize = o3tl::toInt32(aArrowSize); + rnArrowWidth = ( nArrowSize - 1 ) / 3; + rnArrowLength = nArrowSize - ( rnArrowWidth * 3 ) - 1; + } + } + } + } + } + return bIsArrow; +} + +void EscherPropertyContainer::CreateLineProperties( + const uno::Reference & rXPropSet, bool bEdge ) +{ + uno::Any aAny; + sal_uInt32 nLineFlags = 0x80008; + + ESCHER_LineEnd eLineEnd; + sal_Int32 nArrowLength; + sal_Int32 nArrowWidth; + + bool bSwapLineEnds = false; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "CircleKind", true ) ) + { + drawing::CircleKind eCircleKind; + if ( aAny >>= eCircleKind ) + { + if ( eCircleKind == drawing::CircleKind_ARC ) + bSwapLineEnds = true; + } + } + if ( GetLineArrow( !bSwapLineEnds, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) ) + { + AddOpt( ESCHER_Prop_lineStartArrowLength, nArrowLength ); + AddOpt( ESCHER_Prop_lineStartArrowWidth, nArrowWidth ); + AddOpt( ESCHER_Prop_lineStartArrowhead, eLineEnd ); + nLineFlags |= 0x100010; + } + if ( GetLineArrow( bSwapLineEnds, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) ) + { + AddOpt( ESCHER_Prop_lineEndArrowLength, nArrowLength ); + AddOpt( ESCHER_Prop_lineEndArrowWidth, nArrowWidth ); + AddOpt( ESCHER_Prop_lineEndArrowhead, eLineEnd ); + nLineFlags |= 0x100010; + } + + // support LineCaps + if(EscherPropertyValueHelper::GetPropertyValue(aAny, rXPropSet, "LineCap")) + { + drawing::LineCap aLineCap(drawing::LineCap_BUTT); + + if(aAny >>= aLineCap) + { + switch (aLineCap) + { + default: /* drawing::LineCap_BUTT */ + { + AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapFlat); + break; + } + case drawing::LineCap_ROUND: + { + AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapRound); + break; + } + case drawing::LineCap_SQUARE: + { + AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapSquare); + break; + } + } + } + } + + sal_uInt32 nLineWidth = ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineWidth" ) ) + ? *o3tl::doAccess(aAny) : 0; + if ( nLineWidth > 1 ) + AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 ); // 100TH MM -> PT , 1PT = 12700 EMU + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineStyle" ) ) + { + drawing::LineStyle eLS; + if ( aAny >>= eLS ) + { + switch ( eLS ) + { + case drawing::LineStyle_NONE : + AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); // 80000 + break; + + case drawing::LineStyle_DASH : + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineDash" ) ) + { + ESCHER_LineDashing eDash = ESCHER_LineSolid; + auto pLineDash = o3tl::doAccess(aAny); + switch ( pLineDash->Style ) + { + case drawing::DashStyle_ROUND : + case drawing::DashStyle_ROUNDRELATIVE : + AddOpt( ESCHER_Prop_lineEndCapStyle, 0 ); // set Style Round + break; + default : break; + } + // Try to detect exact prstDash styles. Use a similar method as in oox export. + // Map it to a roughly fitting prstDash in other cases. + bool bIsConverted = false; + bool bIsRelative = pLineDash->Style == drawing::DashStyle_RECTRELATIVE + || pLineDash->Style == drawing::DashStyle_ROUNDRELATIVE; + sal_Int16 nDashes = pLineDash->Dashes; + sal_Int16 nDots = pLineDash->Dots; + sal_Int32 nDashLen = pLineDash->DashLen; + sal_Int32 nDotLen = pLineDash->DotLen; + sal_Int32 nDistance = pLineDash->Distance; + + // Caution! The names are misleading. "dot" is always the first dash and "dash" + // the second one, regardless of the actual length. All prstDash + // definitions start with the longer dash and have exact one longer dash. + // Preset line style definitions for binary format are the same as for OOXML. + if (bIsRelative && nDots == 1) + { + // I'm not sure that LO always uses 100%, because in case of absolute values, LO + // sets length to 0 but treats it as 100%, if the attribute is missing in ODF. + // So to be sure set 100% explicitly in case of relative too. + if (nDashes > 0 && nDashLen == 0) + nDashLen = 100; + if (nDotLen == 0) + nDotLen = 100; + bIsConverted = true; + if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 300) + eDash = ESCHER_LineDotGEL; + else if (nDotLen == 400 && nDashes == 0 && nDashLen == 0 && nDistance == 300) + eDash = ESCHER_LineDashGEL; + else if (nDotLen == 400 && nDashes == 1 && nDashLen == 100 && nDistance == 300) + eDash = ESCHER_LineDashDotGEL; + else if (nDotLen == 800 && nDashes == 0 && nDashLen == 0 && nDistance == 300) + eDash = ESCHER_LineLongDashGEL; + else if (nDotLen == 800 && nDashes == 1 && nDashLen == 100 && nDistance == 300) + eDash = ESCHER_LineLongDashDotGEL; + else if (nDotLen == 800 && nDashes == 2 && nDashLen == 100 && nDistance == 300) + eDash = ESCHER_LineLongDashDotDotGEL; + else if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 100) + eDash = ESCHER_LineDotSys; + else if (nDotLen == 300 && nDashes == 0 && nDashLen == 0 && nDistance == 100) + eDash = ESCHER_LineDashSys; + else if (nDotLen == 300 && nDashes == 1 && nDashLen == 100 && nDistance == 100) + eDash = ESCHER_LineDashDotSys; + else if (nDotLen == 300 && nDashes == 2 && nDashLen == 100 && nDistance == 100) + eDash = ESCHER_LineDashDotDotSys; + else + bIsConverted = false; + } + + if (!bIsConverted) + { // Map the style roughly to preset line styles. + if (((!(pLineDash->Dots)) || (!(pLineDash->Dashes))) + || (pLineDash->DotLen == pLineDash->DashLen)) + { + sal_Int32 nLen = pLineDash->DotLen; + if (pLineDash->Dashes) + nLen = pLineDash->DashLen; + if (nLen >= nDistance) + eDash = ESCHER_LineLongDashGEL; + else if (pLineDash->Dots) + eDash = ESCHER_LineDotSys; + else + eDash = ESCHER_LineDashGEL; + } + else // X Y + { + if (pLineDash->Dots != pLineDash->Dashes) + { + if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance)) + eDash = ESCHER_LineLongDashDotDotGEL; + else + eDash = ESCHER_LineDashDotDotSys; + } + else // X Y Y + { + if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance)) + eDash = ESCHER_LineLongDashDotGEL; + else + eDash = ESCHER_LineDashDotGEL; + } + } + } + AddOpt( ESCHER_Prop_lineDashing, eDash ); + } + } + [[fallthrough]]; + case drawing::LineStyle_SOLID : + default: + { + AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ); + } + break; + } + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineColor" ) ) + { + sal_uInt32 nLineColor = ImplGetColor( *o3tl::doAccess(aAny) ); + AddOpt( ESCHER_Prop_lineColor, nLineColor ); + AddOpt( ESCHER_Prop_lineBackColor, nLineColor ^ 0xffffff ); + } + } + + ESCHER_LineJoin eLineJoin = ESCHER_LineJoinMiter; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineJoint", true ) ) + { + drawing::LineJoint eLJ; + if ( aAny >>= eLJ ) + { + switch ( eLJ ) + { + case drawing::LineJoint_NONE : + case drawing::LineJoint_BEVEL : + eLineJoin = ESCHER_LineJoinBevel; + break; + default: + case drawing::LineJoint_MIDDLE : + case drawing::LineJoint_MITER : + eLineJoin = ESCHER_LineJoinMiter; + break; + case drawing::LineJoint_ROUND : + eLineJoin = ESCHER_LineJoinRound; + break; + } + } + } + AddOpt( ESCHER_Prop_lineJoinStyle, eLineJoin ); + + if ( EscherPropertyValueHelper::GetPropertyValue( + aAny, rXPropSet, "LineTransparence", true ) ) + { + sal_Int16 nTransparency = 0; + if ( aAny >>= nTransparency ) + AddOpt( ESCHER_Prop_lineOpacity, ( ( 100 - nTransparency ) << 16 ) / 100 ); + } + + + if ( !bEdge ) + { + AddOpt( ESCHER_Prop_fFillOK, 0x1001 ); + AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); + } +} + +static Size lcl_SizeToEmu(Size aPrefSize, const MapMode& aPrefMapMode) +{ + Size aRetSize; + if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel) + aRetSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); + else + aRetSize = OutputDevice::LogicToLogic(aPrefSize, aPrefMapMode, MapMode(MapUnit::Map100thMM)); + return aRetSize; +} + +void EscherPropertyContainer::ImplCreateGraphicAttributes( const uno::Reference & rXPropSet, + sal_uInt32 nBlibId, bool bCreateCroppingAttributes ) +{ + uno::Any aAny; + + sal_uInt32 nPicFlags = 0; + drawing::ColorMode eColorMode( drawing::ColorMode_STANDARD ); + sal_Int16 nLuminance = 0; + sal_Int32 nContrast = 0; + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "GraphicColorMode" ) ) + aAny >>= eColorMode; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustLuminance" ) ) + aAny >>= nLuminance; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustContrast" ) ) + { + sal_Int16 nC = sal_Int16(); + aAny >>= nC; + nContrast = nC; + } + + if ( eColorMode == drawing::ColorMode_WATERMARK ) + { + eColorMode = drawing::ColorMode_STANDARD; + nLuminance += 70; + if ( nLuminance > 100 ) + nLuminance = 100; + nContrast -= 70; + if ( nContrast < -100 ) + nContrast = -100; + } + if ( eColorMode == drawing::ColorMode_GREYS ) + nPicFlags |= 0x40004; + else if ( eColorMode == drawing::ColorMode_MONO ) + nPicFlags |= 0x60006; + + if ( nContrast ) + { + nContrast += 100; + if ( nContrast == 100) + nContrast = 0x10000; + else if ( nContrast < 100 ) + { + nContrast *= 0x10000; + nContrast /= 100; + } + else if ( nContrast < 200 ) + nContrast = ( 100 * 0x10000 ) / ( 200 - nContrast ); + else + nContrast = 0x7fffffff; + AddOpt( ESCHER_Prop_pictureContrast, nContrast ); + } + if ( nLuminance ) + AddOpt( ESCHER_Prop_pictureBrightness, nLuminance * 327 ); + if ( nPicFlags ) + AddOpt( ESCHER_Prop_pictureActive, nPicFlags ); + + if ( !(bCreateCroppingAttributes && pGraphicProvider) ) + return; + + Size aPrefSize; + MapMode aPrefMapMode; + if ( !pGraphicProvider->GetPrefSize( nBlibId, aPrefSize, aPrefMapMode ) ) + return; + + Size aCropSize(lcl_SizeToEmu(aPrefSize, aPrefMapMode)); + if ( !(aCropSize.Width() && aCropSize.Height()) ) + return; + + if ( !EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "GraphicCrop" ) ) + return; + + text::GraphicCrop aGraphCrop; + if ( !(aAny >>= aGraphCrop) ) + return; + + if ( aGraphCrop.Left ) + { + sal_uInt32 nLeft = ( aGraphCrop.Left * 65536 ) / aCropSize.Width(); + AddOpt( ESCHER_Prop_cropFromLeft, nLeft ); + } + if ( aGraphCrop.Top ) + { + sal_uInt32 nTop = ( aGraphCrop.Top * 65536 ) / aCropSize.Height(); + AddOpt( ESCHER_Prop_cropFromTop, nTop ); + } + if ( aGraphCrop.Right ) + { + sal_uInt32 nRight = ( aGraphCrop.Right * 65536 ) / aCropSize.Width(); + AddOpt( ESCHER_Prop_cropFromRight, nRight ); + } + if ( aGraphCrop.Bottom ) + { + sal_uInt32 nBottom = ( aGraphCrop.Bottom * 65536 ) / aCropSize.Height(); + AddOpt( ESCHER_Prop_cropFromBottom, nBottom ); + } +} + +void EscherPropertyContainer::CreateShapeProperties( const uno::Reference & rXShape ) +{ + uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY ); + if ( !aXPropSet.is() ) + return; + + bool bVisible = false; + bool bPrintable = false; + uno::Any aAny; + sal_uInt32 nShapeAttr = 0; + if (EscherPropertyValueHelper::GetPropertyValue(aAny, aXPropSet, "Visible", true) && (aAny >>= bVisible)) + { + if ( !bVisible ) + nShapeAttr |= 0x20002; // set fHidden = true + } + // This property (fPrint) isn't used in Excel anymore, leaving it for legacy reasons + // one change, based on XLSX: hidden implies not printed, let's not export the fPrint property in that case + if (bVisible && EscherPropertyValueHelper::GetPropertyValue(aAny, aXPropSet, "Printable", true) && (aAny >>= bPrintable)) + { + if ( !bPrintable ) + nShapeAttr |= 0x10000; // set fPrint = false; + } + if ( nShapeAttr ) + AddOpt( ESCHER_Prop_fPrint, nShapeAttr ); +} + +bool EscherPropertyContainer::CreateOLEGraphicProperties(const uno::Reference & rXShape) +{ + bool bRetValue = false; + + if ( rXShape.is() ) + { + SdrObject* pObject = SdrObject::getSdrObjectFromXShape(rXShape); // SJ: leaving unoapi, because currently there is + if (auto pOle2Obj = dynamic_cast(pObject)) // no access to the native graphic object + { + const Graphic* pGraphic = pOle2Obj->GetGraphic(); + if (pGraphic) + { + Graphic aGraphic(*pGraphic); + GraphicObject aGraphicObject(aGraphic); + bRetValue = CreateGraphicProperties(rXShape, aGraphicObject); + } + } + } + return bRetValue; +} + +bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference & rXShape, const GraphicObject& rGraphicObj) +{ + bool bRetValue = false; + OString aUniqueId(rGraphicObj.GetUniqueID()); + if ( !aUniqueId.isEmpty() ) + { + AddOpt( ESCHER_Prop_fillType, ESCHER_FillPicture ); + uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY ); + + if ( pGraphicProvider && pPicOutStrm && pShapeBoundRect && aXPropSet.is() ) + { + uno::Any aAny; + std::unique_ptr pVisArea; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "VisibleArea" ) ) + { + pVisArea.reset(new awt::Rectangle); + aAny >>= *pVisArea; + } + sal_uInt32 nBlibId = pGraphicProvider->GetBlibID( *pPicOutStrm, rGraphicObj, pVisArea.get() ); + if ( nBlibId ) + { + AddOpt( ESCHER_Prop_pib, nBlibId, true ); + ImplCreateGraphicAttributes( aXPropSet, nBlibId, false ); + bRetValue = true; + } + } + } + return bRetValue; +} + +bool EscherPropertyContainer::CreateMediaGraphicProperties(const uno::Reference & rXShape) +{ + bool bRetValue = false; + if ( rXShape.is() ) + { + SdrObject* pSdrObject(SdrObject::getSdrObjectFromXShape(rXShape)); // SJ: leaving unoapi, because currently there is + if (auto pSdrMediaObj = dynamic_cast(pSdrObject)) // no access to the native graphic object + { + GraphicObject aGraphicObject(pSdrMediaObj->getSnapshot()); + bRetValue = CreateGraphicProperties(rXShape, aGraphicObject); + } + } + return bRetValue; +} + +bool EscherPropertyContainer::ImplCreateEmbeddedBmp(GraphicObject const & rGraphicObject) +{ + if (rGraphicObject.GetType() != GraphicType::NONE) + { + EscherGraphicProvider aProvider; + SvMemoryStream aMemStrm; + + if (aProvider.GetBlibID( aMemStrm, rGraphicObject)) + { + AddOpt(ESCHER_Prop_fillBlip, true, 0, aMemStrm); + return true; + } + } + return false; +} + +void EscherPropertyContainer::CreateEmbeddedBitmapProperties( + uno::Reference const & rxBitmap, drawing::BitmapMode eBitmapMode ) +{ + uno::Reference xGraphic(rxBitmap, uno::UNO_QUERY); + if (!xGraphic.is()) + return; + const Graphic aGraphic(xGraphic); + if (aGraphic.IsNone()) + return; + const GraphicObject aGraphicObject(aGraphic); + if (aGraphicObject.GetType() == GraphicType::NONE) + return; + if (ImplCreateEmbeddedBmp(aGraphicObject)) + { + // bitmap mode property + bool bRepeat = eBitmapMode == drawing::BitmapMode_REPEAT; + AddOpt( ESCHER_Prop_fillType, bRepeat ? ESCHER_FillTexture : ESCHER_FillPicture ); + } +} + +namespace { + +Graphic lclDrawHatch( const drawing::Hatch& rHatch, const Color& rBackColor, bool bFillBackground, const tools::Rectangle& rRect ) +{ + // #i121183# For hatch, do no longer create a bitmap with the fixed size of 28x28 pixels. Also + // do not create a bitmap in page size, that would explode file sizes (and have no good quality). + // Better use a MetaFile graphic in page size; thus we have good quality due to vector format and + // no bit file sizes. + ScopedVclPtrInstance< VirtualDevice > pVDev; + GDIMetaFile aMtf; + + pVDev->SetOutputSizePixel(Size(2, 2)); + pVDev->EnableOutput(false); + pVDev->SetMapMode(MapMode(MapUnit::Map100thMM)); + aMtf.Clear(); + aMtf.Record(pVDev); + pVDev->SetLineColor(); + pVDev->SetFillColor(bFillBackground ? rBackColor : COL_TRANSPARENT); + pVDev->DrawRect(rRect); + pVDev->DrawHatch(tools::PolyPolygon(rRect), Hatch(static_cast(rHatch.Style), Color(ColorTransparency, rHatch.Color), rHatch.Distance, + Degree10(rHatch.Angle))); + aMtf.Stop(); + aMtf.WindStart(); + aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + aMtf.SetPrefSize(rRect.GetSize()); + + return Graphic(aMtf); +} + +} // namespace + +void EscherPropertyContainer::CreateEmbeddedHatchProperties(const drawing::Hatch& rHatch, const Color& rBackColor, bool bFillBackground ) +{ + const tools::Rectangle aRect(pShapeBoundRect ? *pShapeBoundRect : tools::Rectangle(Point(0,0), Size(28000, 21000))); + Graphic aGraphic(lclDrawHatch(rHatch, rBackColor, bFillBackground, aRect)); + GraphicObject aGraphicObject(aGraphic); + + if (ImplCreateEmbeddedBmp(aGraphicObject)) + AddOpt( ESCHER_Prop_fillType, ESCHER_FillTexture ); +} + +bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference & rXPropSet, + const OUString& rSource, + const bool bCreateFillBitmap, + const bool bCreateCroppingAttributes, + const bool bFillBitmapModeAllowed, + const bool bOOxmlExport ) +{ + bool bRetValue = false; + bool bCreateFillStyles = false; + + std::unique_ptr pGraphicAttr; + uno::Reference xGraphic; + + uno::Any aAny; + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, rSource ) ) + { + bool bMirrored = false; + bool bRotate = true; + bool bIsGraphicMtf = false; + sal_Int16 nTransparency(0); + sal_Int16 nRed(0); + sal_Int16 nGreen(0); + sal_Int16 nBlue(0); + double fGamma(1.0); + drawing::BitmapMode eBitmapMode(drawing::BitmapMode_NO_REPEAT); + OUString aGraphicUrl; + + sal_uInt16 nAngle = 0; + if ( rSource == "MetaFile" ) + { + auto & aSeq = *o3tl::doAccess>(aAny); + const sal_Int8* pArray = aSeq.getConstArray(); + sal_uInt32 nArrayLength = aSeq.getLength(); + + // the metafile is already rotated + bRotate = false; + + if (pArray && nArrayLength) + { + Graphic aGraphic; + SvMemoryStream aStream(const_cast(pArray), nArrayLength, StreamMode::READ); + ErrCode nErrCode = GraphicConverter::Import(aStream, aGraphic, ConvertDataFormat::WMF); + if ( nErrCode == ERRCODE_NONE ) + { + xGraphic = aGraphic.GetXGraphic(); + bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile; + } + } + } + else if (rSource == "Bitmap" || rSource == "FillBitmap") + { + auto xBitmap = aAny.get>(); + if (xBitmap.is()) + { + xGraphic.set(xBitmap, uno::UNO_QUERY); + Graphic aGraphic(xGraphic); + bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile; + } + } + else if ( rSource == "Graphic" ) + { + xGraphic = aAny.get>(); + bCreateFillStyles = true; + } + else if ( rSource == "FillHatch" ) + { + drawing::Hatch aHatch; + if ( aAny >>= aHatch ) + { + Color aBackColor; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillColor" ) ) + { + aBackColor = Color(ColorTransparency, ImplGetColor( *o3tl::doAccess(aAny), false )); + } + bool bFillBackground = false; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBackground", true ) ) + { + aAny >>= bFillBackground; + } + + const tools::Rectangle aRect(Point(0, 0), pShapeBoundRect ? pShapeBoundRect->GetSize() : Size(28000, 21000)); + Graphic aGraphic(lclDrawHatch(aHatch, aBackColor, bFillBackground, aRect)); + xGraphic = aGraphic.GetXGraphic(); + eBitmapMode = drawing::BitmapMode_REPEAT; + bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile; + } + } + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "IsMirrored", true ) ) + aAny >>= bMirrored; + + // #121074# transparency of graphic is not supported in MS formats, get and apply it + // in the GetTransformedGraphic call in GetBlibID + if(EscherPropertyValueHelper::GetPropertyValue(aAny, rXPropSet, "Transparency")) + { + aAny >>= nTransparency; + } + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustRed" ) ) + { + aAny >>= nRed; + } + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustGreen" ) ) + { + aAny >>= nGreen; + } + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustBlue" ) ) + { + aAny >>= nBlue; + } + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "Gamma" ) ) + { + aAny >>= fGamma; + } + + if ( bCreateFillBitmap && bFillBitmapModeAllowed ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapMode", true ) ) + aAny >>= eBitmapMode; + } + else + { + nAngle = bRotate && EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "RotateAngle", true ) + ? static_cast( ( *o3tl::doAccess(aAny) ) + 5 ) / 10 + : 0; + } + + if (xGraphic.is()) + { + Graphic aGraphic(xGraphic); + aGraphicUrl = aGraphic.getOriginURL(); + } + + if (!aGraphicUrl.isEmpty()) + { + bool bConverted = false; + + // externally, linked graphic? convert to embedded + // one, if transformations are needed. this is because + // everything < msoxp cannot even handle rotated + // bitmaps. + // And check whether the graphic link target is + // actually supported by mso. + INetURLObject aTmp( aGraphicUrl ); + GraphicDescriptor aDescriptor(aTmp); + (void)aDescriptor.Detect(); + const GraphicFileFormat nFormat = aDescriptor.GetFileFormat(); + + // can MSO handle it? + if ( bMirrored || nAngle || nTransparency || nRed || nGreen || nBlue || (1.0 != fGamma) || + (nFormat != GraphicFileFormat::BMP && + nFormat != GraphicFileFormat::GIF && + nFormat != GraphicFileFormat::JPG && + nFormat != GraphicFileFormat::PNG && + nFormat != GraphicFileFormat::TIF && + nFormat != GraphicFileFormat::PCT && + nFormat != GraphicFileFormat::WMF && + nFormat != GraphicFileFormat::EMF) ) + { + std::unique_ptr pIn(::utl::UcbStreamHelper::CreateStream( + aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ )); + if ( pIn ) + { + Graphic aGraphic; + ErrCode nErrCode = GraphicConverter::Import( *pIn, aGraphic ); + + if ( nErrCode == ERRCODE_NONE ) + { + xGraphic = aGraphic.GetXGraphic(); + bConverted = true; + } + // else: simply keep the graphic link + } + } + + if (!bConverted && pGraphicProvider ) + { + const OUString& rBaseURI( pGraphicProvider->GetBaseURI() ); + INetURLObject aBaseURI( rBaseURI ); + if( aBaseURI.GetProtocol() == aTmp.GetProtocol() ) + { + OUString aRelUrl( INetURLObject::GetRelURL( rBaseURI, aGraphicUrl ) ); + if ( !aRelUrl.isEmpty() ) + aGraphicUrl = aRelUrl; + } + } + } + + if (!aGraphicUrl.isEmpty() || xGraphic.is()) + { + if(bMirrored || nTransparency || nRed || nGreen || nBlue || (1.0 != fGamma)) + { + pGraphicAttr.reset(new GraphicAttr); + + if(bMirrored) + { + pGraphicAttr->SetMirrorFlags(BmpMirrorFlags::Horizontal); + } + + if(nTransparency) + { + pGraphicAttr->SetAlpha(255 - (nTransparency * 255) / 100); + } + + if(nRed) + { + pGraphicAttr->SetChannelR(nRed); + } + + if(nGreen) + { + pGraphicAttr->SetChannelG(nGreen); + } + + if(nBlue) + { + pGraphicAttr->SetChannelB(nBlue); + } + + if(1.0 != fGamma) + { + pGraphicAttr->SetGamma(fGamma); + } + } + + if(nAngle && bIsGraphicMtf) + { + AddOpt( ESCHER_Prop_Rotation, ( ( (static_cast(nAngle) << 16 ) / 10 ) + 0x8000 ) &~ 0xffff ); + } + + if ( eBitmapMode == drawing::BitmapMode_REPEAT ) + { + sal_Int32 nSizeX = 0,nSizeY = 0,nOffsetX = 0,nOffsetY = 0,nPosOffsetX = 0,nPosOffsetY = 0; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapSizeX", true ) ) + { + aAny >>= nSizeX; + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapSizeY", true ) ) + { + aAny >>= nSizeY; + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapOffsetX", true ) ) + { + aAny >>= nOffsetX; + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapOffsetY", true ) ) + { + aAny >>= nOffsetY; + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapPositionOffsetX", true ) ) + { + aAny >>= nPosOffsetX; + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapPositionOffsetY", true ) ) + { + aAny >>= nPosOffsetY; + } + if(nSizeX == -100 && nSizeY == -100 && nOffsetX == 0 && nOffsetY == 0 && nPosOffsetX == 0 && nPosOffsetY == 0) + AddOpt( ESCHER_Prop_fillType, ESCHER_FillPicture ); + else + AddOpt( ESCHER_Prop_fillType, ESCHER_FillTexture ); + } + else + AddOpt( ESCHER_Prop_fillType, ESCHER_FillPicture ); + + if (xGraphic.is()) + { + Graphic aGraphic(xGraphic); + if (!aGraphic.getOriginURL().isEmpty()) + { + AddOpt(ESCHER_Prop_pibName, aGraphicUrl); + sal_uInt32 nPibFlags = 0; + GetOpt(ESCHER_Prop_pibFlags, nPibFlags); + AddOpt(ESCHER_Prop_pibFlags, ESCHER_BlipFlagLinkToFile | ESCHER_BlipFlagFile | ESCHER_BlipFlagDoNotSave | nPibFlags); + } + else if (pGraphicProvider && pPicOutStrm && pShapeBoundRect) // write out embedded graphic + { + GraphicObject aGraphicObject(aGraphic); + const sal_uInt32 nBlibId(pGraphicProvider->GetBlibID(*pPicOutStrm, aGraphicObject, nullptr, pGraphicAttr.get())); + + if(nBlibId) + { + if(bCreateFillBitmap) + { + AddOpt(ESCHER_Prop_fillBlip, nBlibId, true); + } + else + { + AddOpt( ESCHER_Prop_pib, nBlibId, true ); + ImplCreateGraphicAttributes( rXPropSet, nBlibId, bCreateCroppingAttributes ); + } + + bRetValue = true; + } + } + else + { + EscherGraphicProvider aProvider; + SvMemoryStream aMemStrm; + GraphicObject aGraphicObject(aGraphic); + + if (aProvider.GetBlibID(aMemStrm, aGraphicObject, nullptr, pGraphicAttr.get(), bOOxmlExport)) + { + AddOpt(ESCHER_Prop_fillBlip, true, 0, aMemStrm); + bRetValue = true; + } + } + } + } + } + pGraphicAttr.reset(); + if ( bCreateFillStyles ) + CreateFillProperties( rXPropSet, true ); + + return bRetValue; +} + +tools::PolyPolygon EscherPropertyContainer::GetPolyPolygon( const uno::Reference< drawing::XShape > & rXShape ) +{ + tools::PolyPolygon aRetPolyPoly; + uno::Reference< beans::XPropertySet > aXPropSet; + uno::Any aAny( rXShape->queryInterface( + cppu::UnoType::get())); + + if ( aAny >>= aXPropSet ) + { + bool bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygonBezier", true ); + if ( !bHasProperty ) + bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygon", true ); + if ( !bHasProperty ) + bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "Polygon", true ); + if ( bHasProperty ) + aRetPolyPoly = GetPolyPolygon( aAny ); + } + return aRetPolyPoly; +} + +// adapting to basegfx::B2DPolyPolygon now, has no sense to do corrections in the +// old tools::PolyPolygon creation code. Convert to that at return time +tools::PolyPolygon EscherPropertyContainer::GetPolyPolygon( const uno::Any& rAny ) +{ + basegfx::B2DPolyPolygon aRetval; + + if(auto pBCC = o3tl::tryAccess(rAny)) + { + aRetval = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pBCC); + } + else if(auto pCC = o3tl::tryAccess(rAny)) + { + aRetval = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pCC); + } + else if(auto pC = o3tl::tryAccess(rAny)) + { + aRetval.append(basegfx::utils::UnoPointSequenceToB2DPolygon(*pC)); + } + + basegfx::B2DPolyPolygon aRetval2; + + for(sal_uInt32 a(0); a < aRetval.count(); a++) + { + if(0 != aRetval.getB2DPolygon(a).count()) + { + aRetval2.append(aRetval.getB2DPolygon(a)); + } + } + + return tools::PolyPolygon(aRetval2); +} + +bool EscherPropertyContainer::CreatePolygonProperties( + const uno::Reference & rXPropSet, + sal_uInt32 nFlags, + bool bBezier, + awt::Rectangle& rGeoRect, + tools::Polygon const * pPolygon ) +{ + tools::PolyPolygon aPolyPolygon; + + if(nullptr != pPolygon) + { + aPolyPolygon.Insert(*pPolygon); + } + else + { + uno::Any aAny; + + if(EscherPropertyValueHelper::GetPropertyValue( + aAny, + rXPropSet, + bBezier ? OUString("PolyPolygonBezier") : OUString("PolyPolygon"), + true)) + { + aPolyPolygon = GetPolyPolygon(aAny); + } + else + { + return false; + } + } + + if(0 == aPolyPolygon.Count()) + { + return false; + } + + if(0 != (nFlags & ESCHER_CREATEPOLYGON_LINE)) + { + if((1 == aPolyPolygon.Count()) && (2 == aPolyPolygon[0].GetSize())) + { + const tools::Polygon& rPoly(aPolyPolygon[0]); + + rGeoRect = awt::Rectangle( + rPoly[0].X(), + rPoly[0].Y(), + rPoly[1].X() - rPoly[0].X(), + rPoly[1].Y() - rPoly[0].Y()); + + return true; + } + + return false; + } + + const tools::Rectangle aRect(aPolyPolygon.GetBoundRect()); + + rGeoRect = awt::Rectangle( + aRect.Left(), + aRect.Top(), + aRect.GetWidth(), + aRect.GetHeight()); + + const sal_uInt16 nPolyCount(aPolyPolygon.Count()); + sal_uInt32 nTotalPoints(0); + + std::vector< sal_uInt8 > aVertices + { + 0, 0, 0, 0, + static_cast(0xf0), + static_cast(0xff) + }; + + std::vector< sal_uInt8 > aSegments + { + 0, 0, 0, 0, + static_cast(2), + static_cast(0) + }; + + for(sal_uInt16 j(0); j < nPolyCount; ++j) + { + const tools::Polygon aPolygon(aPolyPolygon[j]); + const sal_uInt16 nPoints(aPolygon.GetSize()); + + if(0 == nPoints) + { + continue; + } + + // Polygon start + aSegments.push_back(static_cast(0x0)); + aSegments.push_back(static_cast(0x40)); + + sal_uInt16 nSegmentIgnoreCounter(0); + + // write points from polygon to buffer + for(sal_uInt16 i(0); i < nPoints; ++i) + { + Point aPoint(aPolygon[i]); + + aPoint.AdjustX(-(rGeoRect.X)); + aPoint.AdjustY(-(rGeoRect.Y)); + + aVertices.push_back(static_cast(aPoint.X())); + aVertices.push_back(static_cast(aPoint.X() >> 8)); + aVertices.push_back(static_cast(aPoint.Y())); + aVertices.push_back(static_cast(aPoint.Y() >> 8)); + + nTotalPoints++; + + if(0 != nSegmentIgnoreCounter) + { + nSegmentIgnoreCounter--; + } + else + { + aSegments.push_back(static_cast(0)); + + if(bBezier) + { + aSegments.push_back(static_cast(0xb3)); + } + else + { + aSegments.push_back(static_cast(0xac)); + } + + if(i + 1 == nPoints) + { + if(nPolyCount > 1) + { + // end of polygon + aSegments.push_back(static_cast(1)); + aSegments.push_back(static_cast(0x60)); + } + } + else + { + aSegments.push_back(static_cast(1)); + + if(PolyFlags::Control == aPolygon.GetFlags(i + 1)) + { + aSegments.push_back(static_cast(0x20)); + nSegmentIgnoreCounter = 2; + } + else + { + aSegments.push_back(static_cast(0)); + } + } + } + } + } + + if(0 == nTotalPoints || aSegments.size() < 6 || aVertices.size() < 6) + return false; + + // Little endian + aVertices[0] = static_cast(nTotalPoints); + aVertices[1] = static_cast(nTotalPoints >> 8); + aVertices[2] = static_cast(nTotalPoints); + aVertices[3] = static_cast(nTotalPoints >> 8); + + aSegments.push_back(static_cast(0)); + aSegments.push_back(static_cast(0x80)); + + const sal_uInt32 nSegmentBufSize(aSegments.size() - 6); + aSegments[0] = static_cast(nSegmentBufSize >> 1); + aSegments[1] = static_cast(nSegmentBufSize >> 9); + aSegments[2] = static_cast(nSegmentBufSize >> 1); + aSegments[3] = static_cast(nSegmentBufSize >> 9); + + AddOpt( + ESCHER_Prop_geoRight, + rGeoRect.Width); + AddOpt( + ESCHER_Prop_geoBottom, + rGeoRect.Height); + AddOpt( + ESCHER_Prop_shapePath, + ESCHER_ShapeComplex); + AddOpt( + ESCHER_Prop_pVertices, + true, + aVertices.size() - 6, + aVertices); + AddOpt( + ESCHER_Prop_pSegmentInfo, + true, + aSegments.size(), + aSegments); + + return true; +} + + +/* +in MS,the connector including 9 types : +"straightConnector1", +"bentConnector2","bentConnector3","bentConnector4","bentConnector5" +"curvedConnector2","curvedConnector3","curvedConnector4","curvedConnector5" +in AOO,including 4 types:"standard","lines","line","curve" +when save as MS file, the connector must be convert to corresponding type. +"line" and "lines" <-> "straightConnector1" +"standard" <-> "bentConnector2-5" +"curve" <-> "curvedConnector2-5" +*/ +static sal_Int32 lcl_GetAdjustValueCount( const XPolygon& rPoly ) +{ + int nRet = 0; + switch ( rPoly.GetSize() ) + { + case 2 : + case 3: + nRet = 0; + break; + case 4: + nRet = 1; + break; + case 5: + nRet = 2; + break; + default: + if ( rPoly.GetSize()>=6 ) + nRet = 3; + break; + } + return nRet; +} + +// Adjust value decide the position which connector should turn a corner +static sal_Int32 lcl_GetConnectorAdjustValue ( const XPolygon& rPoly, sal_uInt16 nIndex ) +{ + sal_uInt16 k = rPoly.GetSize(); + OSL_ASSERT ( k >= ( 3 + nIndex ) ); + + Point aPt; + Point aStart = rPoly[0]; + Point aEnd = rPoly[k-1]; + if ( aEnd.Y() == aStart.Y() ) + aEnd.setY( aStart.Y() +4 ); + if ( aEnd.X() == aStart.X() ) + aEnd.setX( aStart.X() +4 ); + + bool bVertical = ( rPoly[1].X()-aStart.X() ) == 0 ; + // vertical and horizon alternate + if ( nIndex%2 == 1 ) bVertical = !bVertical; + aPt = rPoly[ nIndex + 1]; + + sal_Int32 nAdjustValue; + if ( bVertical ) + nAdjustValue = ( aPt.Y()-aStart.Y())* 21600 /(aEnd.Y()-aStart.Y()); + else + nAdjustValue = ( aPt.X()-aStart.X() )* 21600 /(aEnd.X()-aStart.X()); + + return nAdjustValue; +} + + +static void lcl_Rotate(Degree100 nAngle, Point center, Point& pt) +{ + nAngle = NormAngle36000(nAngle); + + int cs, sn; + switch (nAngle.get()) + { + case 0: + cs =1; + sn =0; + break; + case 9000: + cs =0; + sn =1; + break; + case 18000: + cs = -1; + sn = 0; + break; + case 27000: + cs = 0; + sn = -1; + break; + default: + return; + } + sal_Int32 x0 =pt.X()-center.X(); + sal_Int32 y0 =pt.Y()-center.Y(); + pt.setX(center.X()+ x0*cs-y0*sn ); + pt.setY(center.Y()+ y0*cs+x0*sn ); +} +/* + FlipV defines that the shape will be flipped vertically about the center of its bounding box. +Generally, draw the connector from top to bottom, from left to right when meet the adjust value, +but when (X1>X2 or Y1>Y2),the draw director must be reverse, FlipV or FlipH should be set to true. +*/ +static bool lcl_GetAngle(tools::Polygon &rPoly, ShapeFlag& rShapeFlags,sal_Int32& nAngle ) +{ + Point aStart = rPoly[0]; + Point aEnd = rPoly[rPoly.GetSize()-1]; + nAngle = ( rPoly[1].X() == aStart.X() ) ? 9000: 0 ; + Point p1(aStart.X(),aStart.Y()); + Point p2(aEnd.X(),aEnd.Y()); + if ( nAngle ) + { + Point center((aEnd.X()+aStart.X())>>1,(aEnd.Y()+aStart.Y())>>1); + lcl_Rotate(Degree100(-nAngle), center,p1); + lcl_Rotate(Degree100(-nAngle), center,p2); + } + if ( p1.X() > p2.X() ) + { + if ( nAngle ) + rShapeFlags |= ShapeFlag::FlipV; + else + rShapeFlags |= ShapeFlag::FlipH; + + } + if ( p1.Y() > p2.Y() ) + { + if ( nAngle ) + rShapeFlags |= ShapeFlag::FlipH; + else + rShapeFlags |= ShapeFlag::FlipV; + } + + if ( (rShapeFlags&ShapeFlag::FlipH) && (rShapeFlags&ShapeFlag::FlipV) ) + { + rShapeFlags &= ~ShapeFlag( ShapeFlag::FlipH | ShapeFlag::FlipV ); + nAngle +=18000; + } + + if ( nAngle ) + { + // Set angle properties + nAngle *= 655; + nAngle += 0x8000; + nAngle &=~0xffff; // round nAngle to whole number of degrees + return true; + } + return false; +} +bool EscherPropertyContainer::CreateConnectorProperties( + const uno::Reference & rXShape, + EscherSolverContainer& rSolverContainer, awt::Rectangle& rGeoRect, + sal_uInt16& rShapeType, ShapeFlag& rShapeFlags ) +{ + bool bRetValue = false; + rShapeType = 0; + rShapeFlags = ShapeFlag::NONE; + + if ( rXShape.is() ) + { + uno::Reference aXPropSet; + uno::Reference aShapeA, aShapeB; + uno::Any aAny( rXShape->queryInterface( cppu::UnoType::get())); + if ( aAny >>= aXPropSet ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeKind", true ) ) + { + drawing::ConnectorType eCt; + aAny >>= eCt; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeStartPoint" ) ) + { + awt::Point aStartPoint = *o3tl::doAccess(aAny); + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeEndPoint" ) ) + { + awt::Point aEndPoint = *o3tl::doAccess(aAny); + + rShapeFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Connector; + rGeoRect = awt::Rectangle( aStartPoint.X, aStartPoint.Y, + ( aEndPoint.X - aStartPoint.X ) + 1, ( aEndPoint.Y - aStartPoint.Y ) + 1 ); + // set standard's FLIP in below code + if ( eCt != drawing::ConnectorType_STANDARD) + { + if ( rGeoRect.Height < 0 ) // justify + { + rShapeFlags |= ShapeFlag::FlipV; + rGeoRect.Y = aEndPoint.Y; + rGeoRect.Height = -rGeoRect.Height; + } + if ( rGeoRect.Width < 0 ) + { + rShapeFlags |= ShapeFlag::FlipH; + rGeoRect.X = aEndPoint.X; + rGeoRect.Width = -rGeoRect.Width; + } + } + sal_uInt32 nAdjustValue1, nAdjustValue2; + nAdjustValue1 = nAdjustValue2 = 0x2a30; + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeStartConnection" ) ) + aAny >>= aShapeA; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeEndConnection" ) ) + aAny >>= aShapeB; + rSolverContainer.AddConnector( rXShape, aStartPoint, aShapeA, aEndPoint, aShapeB ); + switch ( eCt ) + { + case drawing::ConnectorType_CURVE : + { + rShapeType = ESCHER_ShpInst_CurvedConnector3; + AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleCurved ); + AddOpt( ESCHER_Prop_adjustValue, nAdjustValue1 ); + AddOpt( ESCHER_Prop_adjust2Value, -static_cast(nAdjustValue2) ); + } + break; + + case drawing::ConnectorType_STANDARD :// Connector 2->5 + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygonBezier" ) ) + { + tools::PolyPolygon aPolyPolygon = GetPolyPolygon( aAny ); + tools::Polygon aPoly; + if ( aPolyPolygon.Count() > 0 ) + { + AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleBent ); + aPoly = aPolyPolygon[ 0 ]; + sal_Int32 nAdjCount = lcl_GetAdjustValueCount( aPoly ); + rShapeType = static_cast( ESCHER_ShpInst_BentConnector2 + nAdjCount); + for ( sal_Int32 i = 0 ; i < nAdjCount; ++ i) + AddOpt( static_cast( ESCHER_Prop_adjustValue+i) , lcl_GetConnectorAdjustValue( aPoly, i ) ); + } + sal_Int32 nAngle=0; + if (lcl_GetAngle(aPoly,rShapeFlags,nAngle )) + { + AddOpt( ESCHER_Prop_Rotation, nAngle ); + } + } + else + { + rShapeType = ESCHER_ShpInst_BentConnector3; + AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleBent ); + } + } + break; + default: + case drawing::ConnectorType_LINE : + case drawing::ConnectorType_LINES : // Connector 2->5 + { + rShapeType = ESCHER_ShpInst_StraightConnector1; + AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleStraight ); + } + break; + } + CreateLineProperties( aXPropSet, false ); + bRetValue = true; + } + } + } + } + } + return bRetValue; +} + +void EscherPropertyContainer::CreateShadowProperties( + const uno::Reference & rXPropSet ) +{ + uno::Any aAny; + + sal_uInt32 nLineFlags = 0; // default : shape has no line + sal_uInt32 nFillFlags = 0x10; // shape is filled + + GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ); + GetOpt( ESCHER_Prop_fNoFillHitTest, nFillFlags ); + + sal_uInt32 nDummy; + bool bGraphic = GetOpt( DFF_Prop_pib, nDummy ) || GetOpt( DFF_Prop_pibName, nDummy ) || GetOpt( DFF_Prop_pibFlags, nDummy ); + + sal_uInt32 nShadowFlags = 0x20000; + if ( ( nLineFlags & 8 ) || ( nFillFlags & 0x10 ) || bGraphic ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "Shadow", true ) ) + { + bool bHasShadow = false; // shadow is possible only if at least a fillcolor, linecolor or graphic is set + if ( (aAny >>= bHasShadow) && bHasShadow ) + { + nShadowFlags |= 2; + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowColor" ) ) + AddOpt( ESCHER_Prop_shadowColor, ImplGetColor( *o3tl::doAccess(aAny) ) ); + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowXDistance" ) ) + AddOpt( ESCHER_Prop_shadowOffsetX, *o3tl::doAccess(aAny) * 360 ); + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowYDistance" ) ) + AddOpt( ESCHER_Prop_shadowOffsetY, *o3tl::doAccess(aAny) * 360 ); + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowTransparence" ) ) + AddOpt( ESCHER_Prop_shadowOpacity, 0x10000 - (static_cast(*o3tl::doAccess(aAny)) * 655 ) ); + } + } + } + AddOpt( ESCHER_Prop_fshadowObscured, nShadowFlags ); +} + +sal_Int32 EscherPropertyContainer::GetValueForEnhancedCustomShapeParameter( const drawing::EnhancedCustomShapeParameter& rParameter, + const std::vector< sal_Int32 >& rEquationOrder, bool bAdjustTrans ) +{ + sal_Int32 nValue = 0; + if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fValue(0.0); + if ( rParameter.Value >>= fValue ) + nValue = static_cast(fValue); + } + else + rParameter.Value >>= nValue; + + switch( rParameter.Type ) + { + case drawing::EnhancedCustomShapeParameterType::EQUATION : + { + size_t nIndex = static_cast(nValue); + OSL_ASSERT(nIndex < rEquationOrder.size()); + if ( nIndex < rEquationOrder.size() ) + { + nValue = static_cast(rEquationOrder[ nIndex ]); + nValue |= sal_uInt32(0x80000000); + } + } + break; + case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT: + { + if(bAdjustTrans) + { + sal_uInt32 nAdjustValue = 0; + bool bGot = GetOpt(static_cast( DFF_Prop_adjustValue + nValue ), nAdjustValue); + if(bGot) nValue = static_cast(nAdjustValue); + } + } + break; + case drawing::EnhancedCustomShapeParameterType::NORMAL : + default: + break; +/* not sure if it is allowed to set following values +(but they are not yet used) + case drawing::EnhancedCustomShapeParameterType::BOTTOM : + case drawing::EnhancedCustomShapeParameterType::RIGHT : + case drawing::EnhancedCustomShapeParameterType::TOP : + case drawing::EnhancedCustomShapeParameterType::LEFT : +*/ + } + return nValue; +} + +static bool GetValueForEnhancedCustomShapeHandleParameter( sal_Int32& nRetValue, const drawing::EnhancedCustomShapeParameter& rParameter ) +{ + bool bSpecial = false; + nRetValue = 0; + if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fValue(0.0); + if ( rParameter.Value >>= fValue ) + nRetValue = static_cast(fValue); + } + else + rParameter.Value >>= nRetValue; + + switch( rParameter.Type ) + { + case drawing::EnhancedCustomShapeParameterType::EQUATION : + { + nRetValue += 3; + bSpecial = true; + } + break; + case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : + { + nRetValue += 0x100; + bSpecial = true; + } + break; + case drawing::EnhancedCustomShapeParameterType::TOP : + case drawing::EnhancedCustomShapeParameterType::LEFT : + { + nRetValue = 0; + bSpecial = true; + } + break; + case drawing::EnhancedCustomShapeParameterType::RIGHT : + case drawing::EnhancedCustomShapeParameterType::BOTTOM : + { + nRetValue = 1; + bSpecial = true; + } + break; + case drawing::EnhancedCustomShapeParameterType::NORMAL : + { + + } + break; + } + return bSpecial; +} + +static void ConvertEnhancedCustomShapeEquation( + const SdrObjCustomShape& rSdrObjCustomShape, + std::vector< EnhancedCustomShapeEquation >& rEquations, + std::vector< sal_Int32 >& rEquationOrder ) +{ + uno::Sequence< OUString > sEquationSource; + const SdrCustomShapeGeometryItem& rGeometryItem = + rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ); + const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "Equations" ); + if ( pAny ) + *pAny >>= sEquationSource; + sal_Int32 nEquationSourceCount = sEquationSource.getLength(); + if ( !(nEquationSourceCount && (nEquationSourceCount <= 128)) ) + return; + + sal_Int32 i; + for ( i = 0; i < nEquationSourceCount; i++ ) + { + EnhancedCustomShape2d aCustomShape2d( + const_cast< SdrObjCustomShape& >(rSdrObjCustomShape)); + try + { + std::shared_ptr< EnhancedCustomShape::ExpressionNode > aExpressNode( + EnhancedCustomShape::FunctionParser::parseFunction( + sEquationSource[ i ], aCustomShape2d)); + drawing::EnhancedCustomShapeParameter aPara( aExpressNode->fillNode( rEquations, nullptr, 0 ) ); + if ( aPara.Type != drawing::EnhancedCustomShapeParameterType::EQUATION ) + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation = 0; + EnhancedCustomShape::FillEquationParameter( aPara, 0, aEquation ); + rEquations.push_back( aEquation ); + } + } + catch ( const EnhancedCustomShape::ParseError& ) + { + EnhancedCustomShapeEquation aEquation; // ups, we should not be here, + aEquation.nOperation = 0; // creating a default equation with value 1 + aEquation.nPara[ 0 ] = 1; // hoping that this will not break anything + rEquations.push_back( aEquation ); + } + catch ( ... ) + { + EnhancedCustomShapeEquation aEquation; // #i112309# EnhancedCustomShape::Parse error + aEquation.nOperation = 0; // not caught on linux platform + aEquation.nPara[ 0 ] = 1; + rEquations.push_back( aEquation ); + } + rEquationOrder.push_back( rEquations.size() - 1 ); + } + // now updating our old equation indices, they are marked with a bit in the hiword of nOperation + for (auto & equation : rEquations) + { + sal_uInt32 nMask = 0x20000000; + for( i = 0; i < 3; i++ ) + { + if ( equation.nOperation & nMask ) + { + equation.nOperation ^= nMask; + const size_t nIndex(equation.nPara[ i ] & 0x3ff); + + // #i124661# check index access, there are cases where this is out of bound leading + // to errors up to crashes when executed + if(nIndex < rEquationOrder.size()) + { + equation.nPara[ i ] = rEquationOrder[ nIndex ] | 0x400; + } + else + { + OSL_ENSURE(false, "Attempted out of bound access to rEquationOrder of CustomShape (!)"); + } + } + nMask <<= 1; + } + } +} + +bool EscherPropertyContainer::IsDefaultObject( + const SdrObjCustomShape& rSdrObjCustomShape, + const MSO_SPT eShapeType) +{ + switch(eShapeType) + { + // if the custom shape is not default shape of ppt, return false; + case mso_sptTearDrop: + return false; + + default: + break; + } + + return rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Equations ) + && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Viewbox ) + && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Path ) + && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Gluepoints ) + && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Segments ) + && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchX ) + && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchY ) + && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::TextFrames ); +} + +void EscherPropertyContainer::LookForPolarHandles( const MSO_SPT eShapeType, sal_Int32& nAdjustmentsWhichNeedsToBeConverted ) +{ + const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eShapeType ); + if ( !(pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles) ) + return; + + sal_Int32 k, nkCount = pDefCustomShape->nHandles; + const SvxMSDffHandle* pData = pDefCustomShape->pHandles; + for ( k = 0; k < nkCount; k++, pData++ ) + { + if ( pData->nFlags & SvxMSDffHandleFlags::POLAR ) + { + if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) ) + nAdjustmentsWhichNeedsToBeConverted |= ( 1 << k ); + } + } +} + +bool EscherPropertyContainer::GetAdjustmentValue( const drawing::EnhancedCustomShapeAdjustmentValue & rkProp, sal_Int32 nIndex, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, sal_Int32& nValue ) +{ + if ( rkProp.State != beans::PropertyState_DIRECT_VALUE ) + return false; + + bool bUseFixedFloat = ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << nIndex ) ) != 0; + if ( rkProp.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fValue(0.0); + rkProp.Value >>= fValue; + if ( bUseFixedFloat ) + fValue *= 65536.0; + nValue = static_cast(fValue); + } + else + { + rkProp.Value >>= nValue; + if ( bUseFixedFloat ) + nValue <<= 16; + } + + return true; +} + +void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeType, const uno::Reference< drawing::XShape > & rXShape ) +{ + uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY ); + if ( !aXPropSet.is() ) + return; + + SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(rXShape)); + if(!pSdrObjCustomShape) + { + return; + } + + SdrObjCustomShape& rSdrObjCustomShape = *pSdrObjCustomShape; + uno::Any aGeoPropSet = aXPropSet->getPropertyValue( "CustomShapeGeometry" ); + uno::Sequence< beans::PropertyValue > aGeoPropSeq; + if ( !(aGeoPropSet >>= aGeoPropSeq) ) + return; + + static const OUStringLiteral sViewBox ( u"ViewBox" ); + static const OUStringLiteral sTextRotateAngle ( u"TextRotateAngle" ); + static const OUStringLiteral sExtrusion ( u"Extrusion" ); + static const OUStringLiteral sEquations ( u"Equations" ); + static const OUStringLiteral sPath ( u"Path" ); + static const OUStringLiteral sTextPath ( u"TextPath" ); + static const OUStringLiteral sHandles ( u"Handles" ); + static const OUStringLiteral sAdjustmentValues ( u"AdjustmentValues" ); + + bool bAdjustmentValuesProp = false; + uno::Any aAdjustmentValuesProp; + bool bPathCoordinatesProp = false; + uno::Any aPathCoordinatesProp; + + sal_Int32 nAdjustmentsWhichNeedsToBeConverted = 0; + uno::Sequence< beans::PropertyValues > aHandlesPropSeq; + bool bPredefinedHandlesUsed = true; + const bool bIsDefaultObject( + IsDefaultObject( + rSdrObjCustomShape, + eShapeType)); + + // convert property "Equations" into std::vector< EnhancedCustomShapeEquationEquation > + std::vector< EnhancedCustomShapeEquation > aEquations; + std::vector< sal_Int32 > aEquationOrder; + ConvertEnhancedCustomShapeEquation( + rSdrObjCustomShape, + aEquations, + aEquationOrder); + + sal_Int32 i, nCount = aGeoPropSeq.getLength(); + for ( i = 0; i < nCount; i++ ) + { + const beans::PropertyValue& rProp = aGeoPropSeq[ i ]; + if ( rProp.Name == sViewBox ) + { + if ( !bIsDefaultObject ) + { + awt::Rectangle aViewBox; + if ( rProp.Value >>= aViewBox ) + { + AddOpt( DFF_Prop_geoLeft, aViewBox.X ); + AddOpt( DFF_Prop_geoTop, aViewBox.Y ); + AddOpt( DFF_Prop_geoRight, aViewBox.X + aViewBox.Width ); + AddOpt( DFF_Prop_geoBottom,aViewBox.Y + aViewBox.Height ); + } + } + } + else if ( rProp.Name == sTextRotateAngle ) + { + double f = 0; + if ( rProp.Value >>= f ) + { + double fTextRotateAngle = fmod( f, 360.0 ); + if ( fTextRotateAngle < 0 ) + fTextRotateAngle = 360 + fTextRotateAngle; + if ( ( fTextRotateAngle < 271.0 ) && ( fTextRotateAngle > 269.0 ) ) + AddOpt( DFF_Prop_cdirFont, mso_cdir90 ); + else if ( ( fTextRotateAngle < 181.0 ) && ( fTextRotateAngle > 179.0 ) ) + AddOpt( DFF_Prop_cdirFont, mso_cdir180 ); + else if ( ( fTextRotateAngle < 91.0 ) && ( fTextRotateAngle > 79.0 ) ) + AddOpt( DFF_Prop_cdirFont, mso_cdir270 ); + } + } + else if ( rProp.Name == sExtrusion ) + { + uno::Sequence< beans::PropertyValue > aExtrusionPropSeq; + if ( rProp.Value >>= aExtrusionPropSeq ) + { + sal_uInt32 nLightFaceFlagsOrg, nLightFaceFlags; + sal_uInt32 nFillHarshFlagsOrg, nFillHarshFlags; + nLightFaceFlagsOrg = nLightFaceFlags = 0x000001; + nFillHarshFlagsOrg = nFillHarshFlags = 0x00001e; + if ( GetOpt( DFF_Prop_fc3DLightFace, nLightFaceFlags ) ) + nLightFaceFlagsOrg = nLightFaceFlags; + if ( GetOpt( DFF_Prop_fc3DFillHarsh, nFillHarshFlags ) ) + nFillHarshFlagsOrg = nFillHarshFlags; + + sal_Int32 r, nrCount = aExtrusionPropSeq.getLength(); + for ( r = 0; r < nrCount; r++ ) + { + const beans::PropertyValue& rrProp = aExtrusionPropSeq[ r ]; + + if ( rrProp.Name == sExtrusion ) + { + bool bExtrusionOn; + if ( rrProp.Value >>= bExtrusionOn ) + { + nLightFaceFlags |= 0x80000; + if ( bExtrusionOn ) + nLightFaceFlags |= 8; + else + nLightFaceFlags &=~8; + } + } + else if ( rrProp.Name == "Brightness" ) + { + double fExtrusionBrightness = 0; + if ( rrProp.Value >>= fExtrusionBrightness ) + AddOpt( DFF_Prop_c3DAmbientIntensity, static_cast( fExtrusionBrightness * 655.36 ) ); + } + else if ( rrProp.Name == "Depth" ) + { + double fDepth = 0; + double fFraction = 0; + drawing::EnhancedCustomShapeParameterPair aDepthParaPair; + if ( ( rrProp.Value >>= aDepthParaPair ) && ( aDepthParaPair.First.Value >>= fDepth ) && ( aDepthParaPair.Second.Value >>= fFraction ) ) + { + double fForeDepth = fDepth * fFraction; + double fBackDepth = fDepth - fForeDepth; + + fBackDepth *= 360.0; + AddOpt( DFF_Prop_c3DExtrudeBackward, static_cast(fBackDepth) ); + + if ( fForeDepth != 0.0 ) + { + fForeDepth *= 360.0; + AddOpt( DFF_Prop_c3DExtrudeForward, static_cast(fForeDepth) ); + } + } + } + else if ( rrProp.Name == "Diffusion" ) + { + double fExtrusionDiffusion = 0; + if ( rrProp.Value >>= fExtrusionDiffusion ) + AddOpt( DFF_Prop_c3DDiffuseAmt, static_cast( fExtrusionDiffusion * 655.36 ) ); + } + else if ( rrProp.Name == "NumberOfLineSegments" ) + { + sal_Int32 nExtrusionNumberOfLineSegments = 0; + if ( rrProp.Value >>= nExtrusionNumberOfLineSegments ) + AddOpt( DFF_Prop_c3DTolerance, nExtrusionNumberOfLineSegments ); + } + else if ( rrProp.Name == "LightFace" ) + { + bool bExtrusionLightFace; + if ( rrProp.Value >>= bExtrusionLightFace ) + { + nLightFaceFlags |= 0x10000; + if ( bExtrusionLightFace ) + nLightFaceFlags |= 1; + else + nLightFaceFlags &=~1; + } + } + else if ( rrProp.Name == "FirstLightHarsh" ) + { + bool bExtrusionFirstLightHarsh; + if ( rrProp.Value >>= bExtrusionFirstLightHarsh ) + { + nFillHarshFlags |= 0x20000; + if ( bExtrusionFirstLightHarsh ) + nFillHarshFlags |= 2; + else + nFillHarshFlags &=~2; + } + } + else if ( rrProp.Name == "SecondLightHarsh" ) + { + bool bExtrusionSecondLightHarsh; + if ( rrProp.Value >>= bExtrusionSecondLightHarsh ) + { + nFillHarshFlags |= 0x10000; + if ( bExtrusionSecondLightHarsh ) + nFillHarshFlags |= 1; + else + nFillHarshFlags &=~1; + } + } + else if ( rrProp.Name == "FirstLightLevel" ) + { + double fExtrusionFirstLightLevel = 0; + if ( rrProp.Value >>= fExtrusionFirstLightLevel ) + AddOpt( DFF_Prop_c3DKeyIntensity, static_cast( fExtrusionFirstLightLevel * 655.36 ) ); + } + else if ( rrProp.Name == "SecondLightLevel" ) + { + double fExtrusionSecondLightLevel = 0; + if ( rrProp.Value >>= fExtrusionSecondLightLevel ) + AddOpt( DFF_Prop_c3DFillIntensity, static_cast( fExtrusionSecondLightLevel * 655.36 ) ); + } + else if ( rrProp.Name == "FirstLightDirection" ) + { + drawing::Direction3D aExtrusionFirstLightDirection; + if ( rrProp.Value >>= aExtrusionFirstLightDirection ) + { + AddOpt( DFF_Prop_c3DKeyX, static_cast(aExtrusionFirstLightDirection.DirectionX) ); + AddOpt( DFF_Prop_c3DKeyY, static_cast(aExtrusionFirstLightDirection.DirectionY) ); + AddOpt( DFF_Prop_c3DKeyZ, static_cast(aExtrusionFirstLightDirection.DirectionZ) ); + } + } + else if ( rrProp.Name == "SecondLightDirection" ) + { + drawing::Direction3D aExtrusionSecondLightPosition; + if ( rrProp.Value >>= aExtrusionSecondLightPosition ) + { + AddOpt( DFF_Prop_c3DFillX, static_cast(aExtrusionSecondLightPosition.DirectionX) ); + AddOpt( DFF_Prop_c3DFillY, static_cast(aExtrusionSecondLightPosition.DirectionY) ); + AddOpt( DFF_Prop_c3DFillZ, static_cast(aExtrusionSecondLightPosition.DirectionZ) ); + } + } + else if ( rrProp.Name == "Metal" ) + { + bool bExtrusionMetal; + if ( rrProp.Value >>= bExtrusionMetal ) + { + nLightFaceFlags |= 0x40000; + if ( bExtrusionMetal ) + nLightFaceFlags |= 4; + else + nLightFaceFlags &=~4; + } + } + else if ( rrProp.Name == "ShadeMode" ) + { + drawing::ShadeMode eExtrusionShadeMode; + if ( rrProp.Value >>= eExtrusionShadeMode ) + { + sal_uInt32 nRenderMode; + switch( eExtrusionShadeMode ) + { + default: + case drawing::ShadeMode_FLAT : + case drawing::ShadeMode_PHONG : + case drawing::ShadeMode_SMOOTH : + nRenderMode = mso_FullRender; + break; + case drawing::ShadeMode_DRAFT : + { + nRenderMode = mso_Wireframe; + } + break; + } + AddOpt( DFF_Prop_c3DRenderMode, nRenderMode ); + } + } + else if ( rrProp.Name == "RotateAngle" ) + { + double fExtrusionAngleX = 0; + double fExtrusionAngleY = 0; + drawing::EnhancedCustomShapeParameterPair aRotateAnglePair; + if ( ( rrProp.Value >>= aRotateAnglePair ) && ( aRotateAnglePair.First.Value >>= fExtrusionAngleX ) && ( aRotateAnglePair.Second.Value >>= fExtrusionAngleY ) ) + { + fExtrusionAngleX *= 65536; + fExtrusionAngleY *= 65536; + AddOpt( DFF_Prop_c3DXRotationAngle, static_cast(fExtrusionAngleX) ); + AddOpt( DFF_Prop_c3DYRotationAngle, static_cast(fExtrusionAngleY) ); + } + } + else if ( rrProp.Name == "RotationCenter" ) + { + drawing::Direction3D aExtrusionRotationCenter; + if ( rrProp.Value >>= aExtrusionRotationCenter ) + { + // tdf#145904 X- and Y-component is fraction, Z-component in EMU + AddOpt( DFF_Prop_c3DRotationCenterX, static_cast( aExtrusionRotationCenter.DirectionX * 65536.0 ) ); + AddOpt( DFF_Prop_c3DRotationCenterY, static_cast( aExtrusionRotationCenter.DirectionY * 65536.0 ) ); + AddOpt( DFF_Prop_c3DRotationCenterZ, static_cast( aExtrusionRotationCenter.DirectionZ * 360.0 ) ); + nFillHarshFlags &=~8; // don't use AutoRotationCenter; + } + } + else if ( rrProp.Name == "Shininess" ) + { + double fExtrusionShininess = 0; + if ( rrProp.Value >>= fExtrusionShininess ) + { + // ODF to MS Office conversion invers to msdffimp.cxx + fExtrusionShininess = basegfx::fround(fExtrusionShininess / 10.0); + AddOpt( DFF_Prop_c3DShininess, static_cast(fExtrusionShininess) ); + } + } + else if ( rrProp.Name == "Skew" ) + { + double fSkewAmount = 0; + double fSkewAngle = 0; + drawing::EnhancedCustomShapeParameterPair aSkewParaPair; + if ( ( rrProp.Value >>= aSkewParaPair ) && ( aSkewParaPair.First.Value >>= fSkewAmount ) && ( aSkewParaPair.Second.Value >>= fSkewAngle ) ) + { + AddOpt( DFF_Prop_c3DSkewAmount, static_cast(fSkewAmount) ); + AddOpt( DFF_Prop_c3DSkewAngle, static_cast( fSkewAngle * 65536 ) ); + } + } + else if ( rrProp.Name == "Specularity" ) + { + double fExtrusionSpecularity = 0; + if ( rrProp.Value >>= fExtrusionSpecularity ) + AddOpt( DFF_Prop_c3DSpecularAmt, static_cast( fExtrusionSpecularity * 655.36 ) ); + } + else if ( rrProp.Name == "ProjectionMode" ) + { + drawing::ProjectionMode eExtrusionProjectionMode; + if ( rrProp.Value >>= eExtrusionProjectionMode ) + { + nFillHarshFlags |= 0x40000; + if ( eExtrusionProjectionMode == drawing::ProjectionMode_PARALLEL ) + nFillHarshFlags |= 4; + else + nFillHarshFlags &=~4; + } + } + else if ( rrProp.Name == "ViewPoint" ) + { + drawing::Position3D aExtrusionViewPoint; + if ( rrProp.Value >>= aExtrusionViewPoint ) + { + aExtrusionViewPoint.PositionX *= 360.0; + aExtrusionViewPoint.PositionY *= 360.0; + aExtrusionViewPoint.PositionZ *= 360.0; + AddOpt( DFF_Prop_c3DXViewpoint, static_cast(aExtrusionViewPoint.PositionX) ); + AddOpt( DFF_Prop_c3DYViewpoint, static_cast(aExtrusionViewPoint.PositionY) ); + AddOpt( DFF_Prop_c3DZViewpoint, static_cast(aExtrusionViewPoint.PositionZ) ); + } + } + else if ( rrProp.Name == "Origin" ) + { + double fExtrusionOriginX = 0; + double fExtrusionOriginY = 0; + drawing::EnhancedCustomShapeParameterPair aOriginPair; + if ( ( rrProp.Value >>= aOriginPair ) && ( aOriginPair.First.Value >>= fExtrusionOriginX ) && ( aOriginPair.Second.Value >>= fExtrusionOriginY ) ) + { + AddOpt( DFF_Prop_c3DOriginX, static_cast( fExtrusionOriginX * 65536 ) ); + AddOpt( DFF_Prop_c3DOriginY, static_cast( fExtrusionOriginY * 65536 ) ); + } + } + else if ( rrProp.Name == "Color" ) + { + bool bExtrusionColor; + if ( rrProp.Value >>= bExtrusionColor ) + { + nLightFaceFlags |= 0x20000; + if ( bExtrusionColor ) + { + nLightFaceFlags |= 2; + uno::Any aFillColor2; + if ( EscherPropertyValueHelper::GetPropertyValue( aFillColor2, aXPropSet, "FillColor2", true ) ) + { + sal_uInt32 nFillColor = ImplGetColor( *o3tl::doAccess(aFillColor2) ); + AddOpt( DFF_Prop_c3DExtrusionColor, nFillColor ); + } + } + else + nLightFaceFlags &=~2; + } + } + } + if ( nLightFaceFlags != nLightFaceFlagsOrg ) + AddOpt( DFF_Prop_fc3DLightFace, nLightFaceFlags ); + if ( nFillHarshFlags != nFillHarshFlagsOrg ) + AddOpt( DFF_Prop_fc3DFillHarsh, nFillHarshFlags ); + } + } + else if ( rProp.Name == sEquations ) + { + if ( !bIsDefaultObject ) + { + sal_uInt16 nElements = static_cast(aEquations.size()); + if ( nElements ) + { + sal_uInt16 nElementSize = 8; + sal_uInt32 nStreamSize = nElementSize * nElements + 6; + SvMemoryStream aMemStrm( nStreamSize ); + aMemStrm.WriteUInt16( nElements ) + .WriteUInt16( nElements ) + .WriteUInt16( nElementSize ); + + for (auto const& equation : aEquations) + { + aMemStrm.WriteUInt16( equation.nOperation ) + .WriteInt16( + std::clamp( + equation.nPara[ 0 ], sal_Int32(SAL_MIN_INT16), + sal_Int32(SAL_MAX_INT16)) ) + .WriteInt16( + std::clamp( + equation.nPara[ 1 ], sal_Int32(SAL_MIN_INT16), + sal_Int32(SAL_MAX_INT16)) ) + .WriteInt16( + std::clamp( + equation.nPara[ 2 ], sal_Int32(SAL_MIN_INT16), + sal_Int32(SAL_MAX_INT16)) ); + } + + AddOpt(DFF_Prop_pFormulas, true, 6, aMemStrm); + } + else + { + AddOpt(DFF_Prop_pFormulas, 0, true); + } + } + } + else if ( rProp.Name == sPath ) + { + uno::Sequence< beans::PropertyValue > aPathPropSeq; + if ( rProp.Value >>= aPathPropSeq ) + { + sal_uInt32 nPathFlags, nPathFlagsOrg; + nPathFlagsOrg = nPathFlags = 0x39; + if ( GetOpt( DFF_Prop_fFillOK, nPathFlags ) ) + nPathFlagsOrg = nPathFlags; + + sal_Int32 r, nrCount = aPathPropSeq.getLength(); + for ( r = 0; r < nrCount; r++ ) + { + const beans::PropertyValue& rrProp = aPathPropSeq[ r ]; + + if ( rrProp.Name == "ExtrusionAllowed" ) + { + bool bExtrusionAllowed; + if ( rrProp.Value >>= bExtrusionAllowed ) + { + nPathFlags |= 0x100000; + if ( bExtrusionAllowed ) + nPathFlags |= 16; + else + nPathFlags &=~16; + } + } + else if ( rrProp.Name == "ConcentricGradientFillAllowed" ) + { + bool bConcentricGradientFillAllowed; + if ( rrProp.Value >>= bConcentricGradientFillAllowed ) + { + nPathFlags |= 0x20000; + if ( bConcentricGradientFillAllowed ) + nPathFlags |= 2; + else + nPathFlags &=~2; + } + } + else if ( rrProp.Name == "TextPathAllowed" ) + { + bool bTextPathAllowed; + if ( rrProp.Value >>= bTextPathAllowed ) + { + nPathFlags |= 0x40000; + if ( bTextPathAllowed ) + nPathFlags |= 4; + else + nPathFlags &=~4; + } + } + else if ( rrProp.Name == "Coordinates" ) + { + if ( !bIsDefaultObject ) + { + aPathCoordinatesProp = rrProp.Value; + bPathCoordinatesProp = true; + } + } + else if ( rrProp.Name == "GluePoints" ) + { + if ( !bIsDefaultObject ) + { + uno::Sequence aGluePoints; + if ( rrProp.Value >>= aGluePoints ) + { + // creating the vertices + sal_uInt16 nElements = static_cast(aGluePoints.getLength()); + if ( nElements ) + { + sal_uInt16 j, nElementSize = 8; + sal_uInt32 nStreamSize = nElementSize * nElements + 6; + SvMemoryStream aMemStrm( nStreamSize ); + aMemStrm.WriteUInt16( nElements ) + .WriteUInt16( nElements ) + .WriteUInt16( nElementSize ); + for( j = 0; j < nElements; j++ ) + { + sal_Int32 X = GetValueForEnhancedCustomShapeParameter( aGluePoints[ j ].First, aEquationOrder ); + sal_Int32 Y = GetValueForEnhancedCustomShapeParameter( aGluePoints[ j ].Second, aEquationOrder ); + aMemStrm.WriteInt32( X ) + .WriteInt32( Y ); + } + + AddOpt(DFF_Prop_connectorPoints, true, 6, aMemStrm); // -6 + } + else + { + AddOpt(DFF_Prop_connectorPoints, 0, true); + } + } + } + } + else if ( rrProp.Name == "GluePointType" ) + { + sal_Int16 nGluePointType = sal_Int16(); + if ( rrProp.Value >>= nGluePointType ) + AddOpt( DFF_Prop_connectorType, static_cast(nGluePointType) ); + } + else if ( rrProp.Name == "Segments" ) + { + if ( !bIsDefaultObject ) + { + uno::Sequence aSegments; + if ( rrProp.Value >>= aSegments ) + { + // creating seginfo + if ( aSegments.hasElements() ) + { + sal_uInt16 j, nElements = static_cast(aSegments.getLength()); + sal_uInt16 nElementSize = 2; + sal_uInt32 nStreamSize = nElementSize * nElements + 6; + SvMemoryStream aMemStrm( nStreamSize ); + aMemStrm.WriteUInt16( nElements ) + .WriteUInt16( nElements ) + .WriteUInt16( nElementSize ); + for ( j = 0; j < nElements; j++ ) + { + // The segment type is stored in the upper 3 bits + // and segment count is stored in the lower 13 + // bits. + // + // If the segment type is msopathEscape, the lower 13 bits + // are divided in a 5 bit escape code and 8 bit + // vertex count (not segment count!) + sal_uInt16 nVal = static_cast(aSegments[ j ].Count); + switch( aSegments[ j ].Command ) + { + case drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN : + case drawing::EnhancedCustomShapeSegmentCommand::LINETO : + break; + case drawing::EnhancedCustomShapeSegmentCommand::MOVETO : + nVal = (msopathMoveTo << 13); + break; + case drawing::EnhancedCustomShapeSegmentCommand::CURVETO : + { + nVal |= (msopathCurveTo << 13); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH : + { + nVal = 1; + nVal |= (msopathClose << 13); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH : + { + nVal = (msopathEnd << 13); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::NOFILL : + { + nVal = (msopathEscape << 13) | (10 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE : + { + nVal = (msopathEscape << 13) | (11 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO : + { + nVal *= 3; + nVal |= (msopathEscape << 13) | (1 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE : + { + nVal *= 3; + nVal |= (msopathEscape << 13) | (2 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::ARCTO : + { + nVal <<= 2; + nVal |= (msopathEscape << 13) | (3 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::ARC : + { + nVal <<= 2; + nVal |= (msopathEscape << 13) | (4 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO : + { + nVal <<= 2; + nVal |= (msopathEscape << 13) | (5 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC : + { + nVal <<= 2; + nVal |= (msopathEscape << 13) | (6 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX : + { + nVal |= (msopathEscape << 13) | (7 << 8); + } + break; + case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY : + { + nVal |= (msopathEscape << 13) | (8 << 8); + } + break; + } + aMemStrm.WriteUInt16( nVal ); + } + + AddOpt(DFF_Prop_pSegmentInfo, false, 6, aMemStrm); + } + else + { + AddOpt(DFF_Prop_pSegmentInfo, 0, true); + } + } + } + } + else if ( rrProp.Name == "StretchX" ) + { + if ( !bIsDefaultObject ) + { + sal_Int32 nStretchX = 0; + if ( rrProp.Value >>= nStretchX ) + AddOpt( DFF_Prop_stretchPointX, nStretchX ); + } + } + else if ( rrProp.Name == "StretchY" ) + { + if ( !bIsDefaultObject ) + { + sal_Int32 nStretchY = 0; + if ( rrProp.Value >>= nStretchY ) + AddOpt( DFF_Prop_stretchPointY, nStretchY ); + } + } + else if ( rrProp.Name == "TextFrames" ) + { + if ( !bIsDefaultObject ) + { + uno::Sequence aPathTextFrames; + if ( rrProp.Value >>= aPathTextFrames ) + { + if ( aPathTextFrames.hasElements() ) + { + sal_uInt16 j, nElements = static_cast(aPathTextFrames.getLength()); + sal_uInt16 nElementSize = 16; + sal_uInt32 nStreamSize = nElementSize * nElements + 6; + SvMemoryStream aMemStrm( nStreamSize ); + aMemStrm.WriteUInt16( nElements ) + .WriteUInt16( nElements ) + .WriteUInt16( nElementSize ); + for ( j = 0; j < nElements; j++ ) + { + sal_Int32 nLeft = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].TopLeft.First, aEquationOrder ); + sal_Int32 nTop = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].TopLeft.Second, aEquationOrder ); + sal_Int32 nRight = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].BottomRight.First, aEquationOrder ); + sal_Int32 nBottom = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].BottomRight.Second, aEquationOrder ); + + aMemStrm.WriteInt32( nLeft ) + .WriteInt32( nTop ) + .WriteInt32( nRight ) + .WriteInt32( nBottom ); + } + + AddOpt(DFF_Prop_textRectangles, true, 6, aMemStrm); + } + else + { + AddOpt(DFF_Prop_textRectangles, 0, true); + } + } + } + } + } + if ( nPathFlags != nPathFlagsOrg ) + AddOpt( DFF_Prop_fFillOK, nPathFlags ); + } + } + else if ( rProp.Name == sTextPath ) + { + uno::Sequence< beans::PropertyValue > aTextPathPropSeq; + if ( rProp.Value >>= aTextPathPropSeq ) + { + sal_uInt32 nTextPathFlagsOrg, nTextPathFlags; + nTextPathFlagsOrg = nTextPathFlags = 0xffff1000; // default + if ( GetOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags ) ) + nTextPathFlagsOrg = nTextPathFlags; + + sal_Int32 r, nrCount = aTextPathPropSeq.getLength(); + for ( r = 0; r < nrCount; r++ ) + { + const beans::PropertyValue& rrProp = aTextPathPropSeq[ r ]; + + if ( rrProp.Name == sTextPath ) + { + bool bTextPathOn; + if ( rrProp.Value >>= bTextPathOn ) + { + nTextPathFlags |= 0x40000000; + if ( bTextPathOn ) + { + nTextPathFlags |= 0x4000; + + sal_uInt32 nPathFlags = 0x39; + GetOpt( DFF_Prop_fFillOK, nPathFlags ); // SJ: can be removed if we are supporting the TextPathAllowed property in XML + nPathFlags |= 0x40004; + AddOpt( DFF_Prop_fFillOK, nPathFlags ); + } + else + nTextPathFlags &=~0x4000; + } + } + else if ( rrProp.Name == "TextPathMode" ) + { + drawing::EnhancedCustomShapeTextPathMode eTextPathMode; + if ( rrProp.Value >>= eTextPathMode ) + { + nTextPathFlags |= 0x05000000; + nTextPathFlags &=~0x500; // TextPathMode_NORMAL + if ( eTextPathMode == drawing::EnhancedCustomShapeTextPathMode_PATH ) + nTextPathFlags |= 0x100; + else if ( eTextPathMode == drawing::EnhancedCustomShapeTextPathMode_SHAPE ) + nTextPathFlags |= 0x500; + } + } + else if ( rrProp.Name == "ScaleX" ) + { + bool bTextPathScaleX; + if ( rrProp.Value >>= bTextPathScaleX ) + { + nTextPathFlags |= 0x00400000; + if ( bTextPathScaleX ) + nTextPathFlags |= 0x40; + else + nTextPathFlags &=~0x40; + } + } + else if ( rrProp.Name == "SameLetterHeights" ) + { + bool bSameLetterHeights; + if ( rrProp.Value >>= bSameLetterHeights ) + { + nTextPathFlags |= 0x00800000; + if ( bSameLetterHeights ) + nTextPathFlags |= 0x80; + else + nTextPathFlags &=~0x80; + } + } + } + if ( nTextPathFlags & 0x4000 ) // Is FontWork ? + { + // FontWork Text + OUString aText; + uno::Reference< text::XSimpleText > xText( rXShape, uno::UNO_QUERY ); + if ( xText.is() ) + aText = xText->getString(); + if ( aText.isEmpty() ) + aText = "your text"; // TODO: moving into a resource + AddOpt( DFF_Prop_gtextUNICODE, aText ); + + // FontWork Font + OUString aFontName; + uno::Any aAny = aXPropSet->getPropertyValue( "CharFontName" ); + aAny >>= aFontName; + if ( aFontName.isEmpty() ) + aFontName = "Arial Black"; + AddOpt( DFF_Prop_gtextFont, aFontName ); + + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharScaleWidth", true ) ) + { + sal_Int16 nCharScaleWidth = 100; + if ( aAny >>= nCharScaleWidth ) + { + if ( nCharScaleWidth != 100 ) + { + sal_Int32 nVal = nCharScaleWidth * 655; + AddOpt( DFF_Prop_gtextSpacing, nVal ); + } + } + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharHeight", true ) ) + { + float fCharHeight = 0.0; + if ( aAny >>= fCharHeight ) + { + sal_Int32 nTextSize = static_cast< sal_Int32 > ( fCharHeight * 65536 ); + AddOpt(ESCHER_Prop_gtextSize, nTextSize); + } + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharKerning", true ) ) + { + sal_Int16 nCharKerning = sal_Int16(); + if ( aAny >>= nCharKerning ) + { + nTextPathFlags |= 0x10000000; + if ( nCharKerning ) + nTextPathFlags |= 0x1000; + else + nTextPathFlags &=~0x1000; + } + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharPosture", true ) ) + { + awt::FontSlant eFontSlant; + if ( aAny >>= eFontSlant ) + { + nTextPathFlags |= 0x100010; + if ( eFontSlant != awt::FontSlant_NONE ) + nTextPathFlags |= 0x10; + else + nTextPathFlags &=~0x10; + } + } + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharWeight", true ) ) + { + float fFontWidth = 0; + if ( aAny >>= fFontWidth ) + { + nTextPathFlags |= 0x200020; + if ( fFontWidth > awt::FontWeight::NORMAL ) + nTextPathFlags |= 0x20; + else + nTextPathFlags &=~0x20; + } + } + // export gTextAlign attr + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "TextHorizontalAdjust", true ) ) + { + MSO_GeoTextAlign gTextAlign = mso_alignTextCenter; + drawing::TextHorizontalAdjust eHA( drawing::TextHorizontalAdjust_LEFT ); + aAny >>= eHA; + switch( eHA ) + { + case drawing::TextHorizontalAdjust_LEFT : + gTextAlign = mso_alignTextLeft; + break; + case drawing::TextHorizontalAdjust_CENTER: + gTextAlign = mso_alignTextCenter; + break; + case drawing::TextHorizontalAdjust_RIGHT: + gTextAlign = mso_alignTextRight; + break; + case drawing::TextHorizontalAdjust_BLOCK: + { + drawing::TextFitToSizeType const eFTS( + rSdrObjCustomShape.GetMergedItem( SDRATTR_TEXT_FITTOSIZE ).GetValue() ); + if (eFTS == drawing::TextFitToSizeType_ALLLINES || + eFTS == drawing::TextFitToSizeType_PROPORTIONAL) + { + gTextAlign = mso_alignTextStretch; + } + else + { + gTextAlign = mso_alignTextWordJust; + } + break; + } + default: + break; + } + AddOpt(DFF_Prop_gtextAlign,gTextAlign); + } + } + if((nTextPathFlags & 0x4000) != 0) // Is Font work + { + OutlinerParaObject* pOutlinerParaObject(rSdrObjCustomShape.GetOutlinerParaObject()); + if ( pOutlinerParaObject && pOutlinerParaObject->IsEffectivelyVertical() ) + nTextPathFlags |= 0x2000; + } + + // Use gtextFStretch for Watermark like MSO does + nTextPathFlags |= use_gtextFBestFit | gtextFBestFit + | use_gtextFStretch | gtextFStretch + | use_gtextFShrinkFit | gtextFShrinkFit; + + if ( nTextPathFlags != nTextPathFlagsOrg ) + AddOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags ); + } + } + else if ( rProp.Name == sHandles ) + { + if ( !bIsDefaultObject ) + { + bPredefinedHandlesUsed = false; + if ( rProp.Value >>= aHandlesPropSeq ) + { + sal_uInt16 nElements = static_cast(aHandlesPropSeq.getLength()); + if ( nElements ) + { + sal_uInt16 k, nElementSize = 36; + sal_uInt32 nStreamSize = nElementSize * nElements + 6; + SvMemoryStream aMemStrm( nStreamSize ); + aMemStrm.WriteUInt16( nElements ) + .WriteUInt16( nElements ) + .WriteUInt16( nElementSize ); + + for ( k = 0; k < nElements; k++ ) + { + sal_uInt32 nFlags = 0; + sal_Int32 nXPosition = 0; + sal_Int32 nYPosition = 0; + sal_Int32 nXMap = 0; + sal_Int32 nYMap = 0; + sal_Int32 nXRangeMin = 0x80000000; + sal_Int32 nXRangeMax = 0x7fffffff; + sal_Int32 nYRangeMin = 0x80000000; + sal_Int32 nYRangeMax = 0x7fffffff; + + const uno::Sequence< beans::PropertyValue >& rPropSeq = aHandlesPropSeq[ k ]; + for ( const beans::PropertyValue& rPropVal: rPropSeq ) + { + if ( rPropVal.Name == "Position" ) + { + drawing::EnhancedCustomShapeParameterPair aPosition; + if ( rPropVal.Value >>= aPosition ) + { + GetValueForEnhancedCustomShapeHandleParameter( nXPosition, aPosition.First ); + GetValueForEnhancedCustomShapeHandleParameter( nYPosition, aPosition.Second ); + } + } + else if ( rPropVal.Name == "MirroredX" ) + { + bool bMirroredX; + if ( rPropVal.Value >>= bMirroredX ) + { + if ( bMirroredX ) + nFlags |= 1; + } + } + else if ( rPropVal.Name == "MirroredY" ) + { + bool bMirroredY; + if ( rPropVal.Value >>= bMirroredY ) + { + if ( bMirroredY ) + nFlags |= 2; + } + } + else if ( rPropVal.Name == "Switched" ) + { + bool bSwitched; + if ( rPropVal.Value >>= bSwitched ) + { + if ( bSwitched ) + nFlags |= 4; + } + } + else if ( rPropVal.Name == "Polar" ) + { + drawing::EnhancedCustomShapeParameterPair aPolar; + if ( rPropVal.Value >>= aPolar ) + { + if ( GetValueForEnhancedCustomShapeHandleParameter( nXMap, aPolar.First ) ) + nFlags |= 0x800; + if ( GetValueForEnhancedCustomShapeHandleParameter( nYMap, aPolar.Second ) ) + nFlags |= 0x1000; + nFlags |= 8; + } + } + else if ( rPropVal.Name == "RadiusRangeMinimum" ) + { + nYRangeMin = sal_Int32(0xff4c0000); // the range of angles seems to be a not + nYRangeMax = sal_Int32(0x00b40000); // used feature, so we are defaulting this + + drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum; + if ( rPropVal.Value >>= aRadiusRangeMinimum ) + { + if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin, aRadiusRangeMinimum ) ) + nFlags |= 0x80; + nFlags |= 0x2000; + } + } + else if ( rPropVal.Name == "RadiusRangeMaximum" ) + { + nYRangeMin = sal_Int32(0xff4c0000); // the range of angles seems to be a not + nYRangeMax = sal_Int32(0x00b40000); // used feature, so we are defaulting this + + drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum; + if ( rPropVal.Value >>= aRadiusRangeMaximum ) + { + if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax, aRadiusRangeMaximum ) ) + nFlags |= 0x100; + nFlags |= 0x2000; + } + } + else if ( rPropVal.Name == "RangeXMinimum" ) + { + drawing::EnhancedCustomShapeParameter aXRangeMinimum; + if ( rPropVal.Value >>= aXRangeMinimum ) + { + if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin, aXRangeMinimum ) ) + nFlags |= 0x80; + nFlags |= 0x20; + } + } + else if ( rPropVal.Name == "RangeXMaximum" ) + { + drawing::EnhancedCustomShapeParameter aXRangeMaximum; + if ( rPropVal.Value >>= aXRangeMaximum ) + { + if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax, aXRangeMaximum ) ) + nFlags |= 0x100; + nFlags |= 0x20; + } + } + else if ( rPropVal.Name == "RangeYMinimum" ) + { + drawing::EnhancedCustomShapeParameter aYRangeMinimum; + if ( rPropVal.Value >>= aYRangeMinimum ) + { + if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMin, aYRangeMinimum ) ) + nFlags |= 0x200; + nFlags |= 0x20; + } + } + else if ( rPropVal.Name == "RangeYMaximum" ) + { + drawing::EnhancedCustomShapeParameter aYRangeMaximum; + if ( rPropVal.Value >>= aYRangeMaximum ) + { + if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMax, aYRangeMaximum ) ) + nFlags |= 0x400; + nFlags |= 0x20; + } + } + } + aMemStrm.WriteUInt32( nFlags ) + .WriteInt32( nXPosition ) + .WriteInt32( nYPosition ) + .WriteInt32( nXMap ) + .WriteInt32( nYMap ) + .WriteInt32( nXRangeMin ) + .WriteInt32( nXRangeMax ) + .WriteInt32( nYRangeMin ) + .WriteInt32( nYRangeMax ); + + if ( nFlags & 8 ) + nAdjustmentsWhichNeedsToBeConverted |= ( 1 << ( nYPosition - 0x100 ) ); + } + + AddOpt(DFF_Prop_Handles, true, 6, aMemStrm); + } + else + { + AddOpt(DFF_Prop_Handles, 0, true); + } + } + } + } + else if ( rProp.Name == sAdjustmentValues ) + { + // it is required, that the information which handle is polar has already be read, + // so we are able to change the polar value to a fixed float + aAdjustmentValuesProp = rProp.Value; + bAdjustmentValuesProp = true; + } + } + if ( bAdjustmentValuesProp ) + { + uno::Sequence aAdjustmentSeq; + if ( aAdjustmentValuesProp >>= aAdjustmentSeq ) + { + if ( bPredefinedHandlesUsed ) + LookForPolarHandles( eShapeType, nAdjustmentsWhichNeedsToBeConverted ); + + sal_Int32 k, nValue = 0, nAdjustmentValues = aAdjustmentSeq.getLength(); + for ( k = 0; k < nAdjustmentValues; k++ ) + if( GetAdjustmentValue( aAdjustmentSeq[ k ], k, nAdjustmentsWhichNeedsToBeConverted, nValue ) ) + AddOpt( static_cast( DFF_Prop_adjustValue + k ), static_cast(nValue) ); + } + } + if( !bPathCoordinatesProp ) + return; + + uno::Sequence aCoordinates; + if ( !(aPathCoordinatesProp >>= aCoordinates) ) + return; + + // creating the vertices + if (aCoordinates.hasElements()) + { + sal_uInt16 j, nElements = static_cast(aCoordinates.getLength()); + sal_uInt16 nElementSize = 8; + sal_uInt32 nStreamSize = nElementSize * nElements + 6; + SvMemoryStream aMemStrm( nStreamSize ); + aMemStrm.WriteUInt16( nElements ) + .WriteUInt16( nElements ) + .WriteUInt16( nElementSize ); + for( j = 0; j < nElements; j++ ) + { + sal_Int32 X = GetValueForEnhancedCustomShapeParameter( aCoordinates[ j ].First, aEquationOrder, true ); + sal_Int32 Y = GetValueForEnhancedCustomShapeParameter( aCoordinates[ j ].Second, aEquationOrder, true ); + aMemStrm.WriteInt32( X ) + .WriteInt32( Y ); + } + + AddOpt(DFF_Prop_pVertices, true, 6, aMemStrm); // -6 + } + else + { + AddOpt(DFF_Prop_pVertices, 0, true); + } +} + +MSO_SPT EscherPropertyContainer::GetCustomShapeType( const uno::Reference< drawing::XShape > & rXShape, ShapeFlag& nMirrorFlags, OUString& rShapeType, bool bOOXML ) +{ + MSO_SPT eShapeType = mso_sptNil; + nMirrorFlags = ShapeFlag::NONE; + uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY ); + if ( aXPropSet.is() ) + { + try + { + uno::Any aGeoPropSet = aXPropSet->getPropertyValue( "CustomShapeGeometry" ); + uno::Sequence< beans::PropertyValue > aGeoPropSeq; + if ( aGeoPropSet >>= aGeoPropSeq ) + { + sal_Int32 i, nCount = aGeoPropSeq.getLength(); + for ( i = 0; i < nCount; i++ ) + { + const beans::PropertyValue& rProp = aGeoPropSeq[ i ]; + if ( rProp.Name == "Type" ) + { + if ( rProp.Value >>= rShapeType ) + { + if (bOOXML) + { + // In case of VML export, try to handle the + // ooxml- prefix in rShapeType. If that fails, + // just do the same as the binary export. + eShapeType = msfilter::util::GETVMLShapeType(rShapeType); + if (eShapeType == mso_sptNil) + eShapeType = EnhancedCustomShapeTypeNames::Get(rShapeType); + } + else + eShapeType = EnhancedCustomShapeTypeNames::Get( rShapeType ); + } + } + else if ( rProp.Name == "MirroredX" ) + { + bool bMirroredX; + if ( ( rProp.Value >>= bMirroredX ) && bMirroredX ) + nMirrorFlags |= ShapeFlag::FlipH; + } + else if ( rProp.Name == "MirroredY" ) + { + bool bMirroredY; + if ( ( rProp.Value >>= bMirroredY ) && bMirroredY ) + nMirrorFlags |= ShapeFlag::FlipV; + } + } + } + } + catch( const uno::Exception& ) + { + } + } + return eShapeType; +} + + +// Implement for form control export +bool EscherPropertyContainer::CreateBlipPropertiesforOLEControl(const uno::Reference & rXPropSet, + const uno::Reference & rXShape) +{ + SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rXShape); + if ( !pShape ) + return false; + + const Graphic aGraphic(SdrExchangeView::GetObjGraphic(*pShape)); + const GraphicObject aGraphicObject(aGraphic); + + if (!aGraphicObject.GetUniqueID().isEmpty()) + { + if ( pGraphicProvider && pPicOutStrm && pShapeBoundRect ) + { + sal_uInt32 nBlibId = pGraphicProvider->GetBlibID(*pPicOutStrm, aGraphicObject); + if ( nBlibId ) + { + AddOpt( ESCHER_Prop_pib, nBlibId, true ); + ImplCreateGraphicAttributes( rXPropSet, nBlibId, false ); + return true; + } + } + } + + return false; +} + +EscherPersistTable::EscherPersistTable() +{ +} + +EscherPersistTable::~EscherPersistTable() +{ +} + +bool EscherPersistTable::PtIsID( sal_uInt32 nID ) +{ + for(auto const & pPtr : maPersistTable) { + if ( pPtr->mnID == nID ) { + return true; + } + } + return false; +} + +void EscherPersistTable::PtInsert( sal_uInt32 nID, sal_uInt32 nOfs ) +{ + maPersistTable.push_back( std::make_unique( nID, nOfs ) ); +} + +void EscherPersistTable::PtDelete( sal_uInt32 nID ) +{ + auto it = std::find_if(maPersistTable.begin(), maPersistTable.end(), + [&nID](const std::unique_ptr& rxEntry) { return rxEntry->mnID == nID; }); + if (it != maPersistTable.end()) + maPersistTable.erase( it ); +} + +sal_uInt32 EscherPersistTable::PtGetOffsetByID( sal_uInt32 nID ) +{ + for(auto const & pPtr : maPersistTable) { + if ( pPtr->mnID == nID ) { + return pPtr->mnOffset; + } + } + return 0; +}; + +void EscherPersistTable::PtReplace( sal_uInt32 nID, sal_uInt32 nOfs ) +{ + for(auto const & pPtr : maPersistTable) { + if ( pPtr->mnID == nID ) { + pPtr->mnOffset = nOfs; + return; + } + } +} + +void EscherPersistTable::PtReplaceOrInsert( sal_uInt32 nID, sal_uInt32 nOfs ) +{ + for(auto const & pPtr : maPersistTable) { + if ( pPtr->mnID == nID ) { + pPtr->mnOffset = nOfs; + return; + } + } + PtInsert( nID, nOfs ); +} + +bool EscherPropertyValueHelper::GetPropertyValue( + uno::Any& rAny, + const uno::Reference & rXPropSet, + const OUString& rString, + bool bTestPropertyAvailability) +{ + bool bRetValue = true; + if ( bTestPropertyAvailability ) + { + bRetValue = false; + try + { + uno::Reference + aXPropSetInfo( rXPropSet->getPropertySetInfo() ); + if ( aXPropSetInfo.is() ) + bRetValue = aXPropSetInfo->hasPropertyByName( rString ); + } + catch( const uno::Exception& ) + { + bRetValue = false; + } + } + if ( bRetValue ) + { + try + { + rAny = rXPropSet->getPropertyValue( rString ); + if ( !rAny.hasValue() ) + bRetValue = false; + } + catch( const uno::Exception& ) + { + bRetValue = false; + } + } + return bRetValue; +} + +beans::PropertyState EscherPropertyValueHelper::GetPropertyState( + const uno::Reference & rXPropSet, + const OUString& rPropertyName ) +{ + beans::PropertyState eRetValue = beans::PropertyState_AMBIGUOUS_VALUE; + try + { + uno::Reference aXPropState + ( rXPropSet, uno::UNO_QUERY ); + if ( aXPropState.is() ) + eRetValue = aXPropState->getPropertyState( rPropertyName ); + } + catch( const uno::Exception& ) + { + } + return eRetValue; +} + +EscherBlibEntry::EscherBlibEntry( sal_uInt32 nPictureOffset, const GraphicObject& rObject, const OString& rId, + const GraphicAttr* pGraphicAttr ) : + maPrefMapMode ( rObject.GetPrefMapMode() ), + maPrefSize ( rObject.GetPrefSize() ), + mnPictureOffset ( nPictureOffset ), + mnRefCount ( 1 ), + mnSizeExtra ( 0 ), + mbIsEmpty ( true ) +{ + mbIsNativeGraphicPossible = ( pGraphicAttr == nullptr ); + meBlibType = UNKNOWN; + mnSize = 0; + + sal_uInt32 nLen = static_cast(rId.getLength()); + const char* pData = rId.getStr(); + GraphicType eType( rObject.GetType() ); + if (!(nLen && (eType != GraphicType::NONE))) + return; + + mnIdentifier[ 0 ] = rtl_crc32( 0,pData, nLen ); + mnIdentifier[ 1 ] = 0; + + if ( pGraphicAttr ) + { + if ( pGraphicAttr->IsSpecialDrawMode() + || pGraphicAttr->IsMirrored() + || pGraphicAttr->IsCropped() + || pGraphicAttr->IsRotated() + || pGraphicAttr->IsTransparent() + || pGraphicAttr->IsAdjusted() ) + { + SvMemoryStream aSt( sizeof( GraphicAttr ) ); + aSt.WriteUInt16( static_cast(pGraphicAttr->GetDrawMode()) ) + .WriteUInt32( static_cast(pGraphicAttr->GetMirrorFlags()) ) + .WriteInt32( pGraphicAttr->GetLeftCrop() ) + .WriteInt32( pGraphicAttr->GetTopCrop() ) + .WriteInt32( pGraphicAttr->GetRightCrop() ) + .WriteInt32( pGraphicAttr->GetBottomCrop() ) + .WriteUInt16( pGraphicAttr->GetRotation().get() ) + .WriteInt16( pGraphicAttr->GetLuminance() ) + .WriteInt16( pGraphicAttr->GetContrast() ) + .WriteInt16( pGraphicAttr->GetChannelR() ) + .WriteInt16( pGraphicAttr->GetChannelG() ) + .WriteInt16( pGraphicAttr->GetChannelB() ) + .WriteDouble( pGraphicAttr->GetGamma() ); + aSt.WriteBool( pGraphicAttr->IsInvert() ) + .WriteUChar( 255 - pGraphicAttr->GetAlpha() ); // transparency + mnIdentifier[ 1 ] = rtl_crc32( 0, aSt.GetData(), aSt.Tell() ); + } + else + mbIsNativeGraphicPossible = true; + } + sal_uInt32 i, nTmp, n1, n2; + n1 = n2 = 0; + for ( i = 0; i < nLen; i++ ) + { + nTmp = n2 >> 28; // rotating 4 bit + n2 <<= 4; + n2 |= n1 >> 28; + n1 <<= 4; + n1 |= nTmp; + n1 ^= *pData++ - '0'; + } + mnIdentifier[ 2 ] = n1; + mnIdentifier[ 3 ] = n2; + mbIsEmpty = false; +}; + +void EscherBlibEntry::WriteBlibEntry( SvStream& rSt, bool bWritePictureOffset, sal_uInt32 nResize ) +{ + sal_uInt32 nPictureOffset = bWritePictureOffset ? mnPictureOffset : 0; + + rSt.WriteUInt32( ( ESCHER_BSE << 16 ) | ( ( static_cast(meBlibType) << 4 ) | 2 ) ) + .WriteUInt32( 36 + nResize ) + .WriteUChar( meBlibType ); + + switch ( meBlibType ) + { + case EMF : + case WMF : // converting EMF/WMF on OS2 to Pict + rSt.WriteUChar( PICT ); + break; + default: + rSt.WriteUChar( meBlibType ); + } + + rSt.WriteBytes(&mnIdentifier[0], 16); + rSt.WriteUInt16( 0 ) + .WriteUInt32( mnSize + mnSizeExtra ) + .WriteUInt32( mnRefCount ) + .WriteUInt32( nPictureOffset ) + .WriteUInt32( 0 ); +} + +EscherBlibEntry::~EscherBlibEntry() +{ +}; + +bool EscherBlibEntry::operator==( const EscherBlibEntry& rEscherBlibEntry ) const +{ + for ( int i = 0; i < 3; i++ ) + { + if ( mnIdentifier[ i ] != rEscherBlibEntry.mnIdentifier[ i ] ) + return false; + } + return true; +} + +EscherGraphicProvider::EscherGraphicProvider( EscherGraphicProviderFlags nFlags ) : + mnFlags ( nFlags ) +{ +} + +EscherGraphicProvider::~EscherGraphicProvider() +{ +} + +void EscherGraphicProvider::SetNewBlipStreamOffset( sal_Int32 nOffset ) +{ + for( size_t i = 0; i < mvBlibEntrys.size(); i++ ) + { + mvBlibEntrys[ i ]->mnPictureOffset += nOffset; + } +} + +sal_uInt32 EscherGraphicProvider::ImplInsertBlib( EscherBlibEntry* p_EscherBlibEntry ) +{ + mvBlibEntrys.push_back( std::unique_ptr(p_EscherBlibEntry) ); + return mvBlibEntrys.size(); +} + +sal_uInt32 EscherGraphicProvider::GetBlibStoreContainerSize( SvStream const * pMergePicStreamBSE ) const +{ + sal_uInt32 nSize = 44 * mvBlibEntrys.size() + 8; + if ( pMergePicStreamBSE ) + { + for ( size_t i = 0; i < mvBlibEntrys.size(); i++ ) + nSize += mvBlibEntrys[ i ]->mnSize + mvBlibEntrys[ i ]->mnSizeExtra; + } + return nSize; +} + +void EscherGraphicProvider::WriteBlibStoreEntry(SvStream& rSt, + sal_uInt32 nBlipId, sal_uInt32 nResize) +{ + if (nBlipId > mvBlibEntrys.size() || nBlipId == 0) + return; + mvBlibEntrys[nBlipId-1]->WriteBlibEntry(rSt, true/*bWritePictureOffSet*/, nResize); +} + +void EscherGraphicProvider::WriteBlibStoreContainer( SvStream& rSt, SvStream* pMergePicStreamBSE ) +{ + sal_uInt32 nSize = GetBlibStoreContainerSize( pMergePicStreamBSE ); + if ( !nSize ) + return; + + rSt.WriteUInt32( ( ESCHER_BstoreContainer << 16 ) | 0x1f ) + .WriteUInt32( nSize - 8 ); + + if ( pMergePicStreamBSE ) + { + sal_uInt32 nBlipSize, nOldPos = pMergePicStreamBSE->Tell(); + const sal_uInt32 nBuf = 0x40000; // 256KB buffer + std::unique_ptr pBuf(new sal_uInt8[ nBuf ]); + + for ( size_t i = 0; i < mvBlibEntrys.size(); i++ ) + { + EscherBlibEntry* pBlibEntry = mvBlibEntrys[ i ].get(); + + ESCHER_BlibType nBlibType = pBlibEntry->meBlibType; + nBlipSize = pBlibEntry->mnSize + pBlibEntry->mnSizeExtra; + pBlibEntry->WriteBlibEntry( rSt, false, nBlipSize ); + + // BLIP + pMergePicStreamBSE->Seek( pBlibEntry->mnPictureOffset ); + sal_uInt16 n16; + // record version and instance + pMergePicStreamBSE->ReadUInt16( n16 ); + rSt.WriteUInt16( n16 ); + // record type + pMergePicStreamBSE->ReadUInt16( n16 ); + rSt.WriteUInt16( ESCHER_BlipFirst + nBlibType ); + DBG_ASSERT( n16 == ESCHER_BlipFirst + nBlibType , "EscherGraphicProvider::WriteBlibStoreContainer: BLIP record types differ" ); + sal_uInt32 n32; + // record size + pMergePicStreamBSE->ReadUInt32( n32 ); + nBlipSize -= 8; + rSt.WriteUInt32( nBlipSize ); + DBG_ASSERT( nBlipSize == n32, "EscherGraphicProvider::WriteBlibStoreContainer: BLIP sizes differ" ); + // record + while ( nBlipSize ) + { + sal_uInt32 nBytes = std::min( nBlipSize, nBuf ); + pMergePicStreamBSE->ReadBytes(pBuf.get(), nBytes); + rSt.WriteBytes(pBuf.get(), nBytes); + nBlipSize -= nBytes; + } + } + pMergePicStreamBSE->Seek( nOldPos ); + } + else + { + for ( size_t i = 0; i < mvBlibEntrys.size(); i++ ) + mvBlibEntrys[ i ]->WriteBlibEntry( rSt, true ); + } +} + +bool EscherGraphicProvider::GetPrefSize( const sal_uInt32 nBlibId, Size& rPrefSize, MapMode& rPrefMapMode ) +{ + bool bInRange = nBlibId && ( ( nBlibId - 1 ) < mvBlibEntrys.size() ); + if ( bInRange ) + { + EscherBlibEntry* pEntry = mvBlibEntrys[ nBlibId - 1 ].get(); + rPrefSize = pEntry->maPrefSize; + rPrefMapMode = pEntry->maPrefMapMode; + } + return bInRange; +} + +sal_uInt32 EscherGraphicProvider::GetBlibID( SvStream& rPicOutStrm, GraphicObject const & rGraphicObject, + const awt::Rectangle* pVisArea, + const GraphicAttr* pGraphicAttr, const bool bOOxmlExport ) +{ + sal_uInt32 nBlibId = 0; + + std::unique_ptr p_EscherBlibEntry( new EscherBlibEntry( rPicOutStrm.Tell(), rGraphicObject, rGraphicObject.GetUniqueID(), pGraphicAttr ) ); + if ( !p_EscherBlibEntry->IsEmpty() ) + { + for ( size_t i = 0; i < mvBlibEntrys.size(); i++ ) + { + if ( *( mvBlibEntrys[ i ] ) == *p_EscherBlibEntry ) + { + mvBlibEntrys[ i ]->mnRefCount++; + return i + 1; + } + } + + bool bUseNativeGraphic( false ); + + Graphic aGraphic(rGraphicObject.GetTransformedGraphic(pGraphicAttr)); + GfxLink aGraphicLink; + SvMemoryStream aStream; + + const sal_uInt8* pGraphicAry = nullptr; + + if ( p_EscherBlibEntry->mbIsNativeGraphicPossible && aGraphic.IsGfxLink() ) + { + aGraphicLink = aGraphic.GetGfxLink(); + + p_EscherBlibEntry->mnSize = aGraphicLink.GetDataSize(); + pGraphicAry = aGraphicLink.GetData(); + + if ( p_EscherBlibEntry->mnSize && pGraphicAry ) + { + switch ( aGraphicLink.GetType() ) + { + case GfxLinkType::NativeJpg : p_EscherBlibEntry->meBlibType = PEG; break; + case GfxLinkType::NativePng : p_EscherBlibEntry->meBlibType = PNG; break; + + // #i15508# added BMP type for better exports; need to check this + // checked - does not work that way, so keep out for now. It may + // work somehow with direct DIB data, but that would need to be checked + // carefully + // for more comments please check RtfAttributeOutput::FlyFrameGraphic + // + // case GfxLinkType::NativeBmp : p_EscherBlibEntry->meBlibType = DIB; break; + + case GfxLinkType::NativeWmf : + { + if ( aGraphicLink.IsEMF() ) + { + p_EscherBlibEntry->meBlibType = EMF; + } + else if ( pGraphicAry && ( p_EscherBlibEntry->mnSize > 0x2c ) ) + { + p_EscherBlibEntry->meBlibType = WMF; + if ( ( pGraphicAry[ 0 ] == 0xd7 ) && ( pGraphicAry[ 1 ] == 0xcd ) + && ( pGraphicAry[ 2 ] == 0xc6 ) && ( pGraphicAry[ 3 ] == 0x9a ) ) + { // we have to get rid of the metafileheader + pGraphicAry += 22; + p_EscherBlibEntry->mnSize -= 22; + } + } + } + break; + default: break; + } + if ( p_EscherBlibEntry->meBlibType != UNKNOWN ) + bUseNativeGraphic = true; + } + } + if ( !bUseNativeGraphic ) + { + GraphicType eGraphicType = aGraphic.GetType(); + if ( ( eGraphicType == GraphicType::Bitmap ) || ( eGraphicType == GraphicType::GdiMetafile ) ) + { + ErrCode nErrCode; + if ( !aGraphic.IsAnimated() ) + nErrCode = GraphicConverter::Export( aStream, aGraphic, ( eGraphicType == GraphicType::Bitmap ) ? ConvertDataFormat::PNG : ConvertDataFormat::EMF ); + else + { // to store an animation, a gif has to be included into the msOG chunk of a png #I5583# + GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter(); + SvMemoryStream aGIFStream; + const char* const pString = "MSOFFICE9.0"; + aGIFStream.WriteBytes(pString, strlen(pString)); + nErrCode = rFilter.ExportGraphic( aGraphic, u"", aGIFStream, + rFilter.GetExportFormatNumberForShortName( u"GIF" ) ); + SAL_WARN_IF( + nErrCode != ERRCODE_NONE, "filter.ms", + "ExportGraphic to GIF failed with " << nErrCode); + if (nErrCode == ERRCODE_NONE) + { + sal_uInt32 nGIFSreamLen = aGIFStream.Tell(); + uno::Sequence aGIFSeq( nGIFSreamLen ); + sal_Int8* pSeq = aGIFSeq.getArray(); + aGIFStream.Seek( STREAM_SEEK_TO_BEGIN ); + aGIFStream.ReadBytes(pSeq, nGIFSreamLen); + beans::PropertyValue aChunkProp, aFilterProp; + aChunkProp.Name = "msOG"; + aChunkProp.Value <<= aGIFSeq; + uno::Sequence aAdditionalChunkSequence{ aChunkProp }; + aFilterProp.Name = "AdditionalChunks"; + aFilterProp.Value <<= aAdditionalChunkSequence; + uno::Sequence aFilterData{ aFilterProp }; + nErrCode = rFilter.ExportGraphic( aGraphic, u"", aStream, + rFilter.GetExportFormatNumberForShortName( u"PNG" ), &aFilterData ); + } + } + if ( nErrCode == ERRCODE_NONE ) + { + p_EscherBlibEntry->meBlibType = ( eGraphicType == GraphicType::Bitmap ) ? PNG : EMF; + p_EscherBlibEntry->mnSize = aStream.TellEnd(); + pGraphicAry = static_cast(aStream.GetData()); + } + } + } + + ESCHER_BlibType eBlibType = p_EscherBlibEntry->meBlibType; + if ( p_EscherBlibEntry->mnSize && pGraphicAry && ( eBlibType != UNKNOWN ) ) + { + sal_uInt32 nExtra, nAtomSize = 0; + sal_uInt32 nInstance, nUncompressedSize = p_EscherBlibEntry->mnSize; + + if ( mnFlags & EscherGraphicProviderFlags::UseInstances ) + { + rPicOutStrm.WriteUInt32( 0x7f90000 | static_cast( mvBlibEntrys.size() << 4 ) ) + .WriteUInt32( 0 ); + nAtomSize = rPicOutStrm.Tell(); + if ( eBlibType == PNG ) + rPicOutStrm.WriteUInt16( 0x0606 ); + else if ( eBlibType == WMF ) + rPicOutStrm.WriteUInt16( 0x0403 ); + else if ( eBlibType == EMF ) + rPicOutStrm.WriteUInt16( 0x0402 ); + else if ( eBlibType == PEG ) + rPicOutStrm.WriteUInt16( 0x0505 ); + } + + // fdo#69607 do not compress WMF files if we are in OOXML export + if ( ( eBlibType == PEG ) || ( eBlibType == PNG ) // || ( eBlibType == DIB )) // #i15508# + || ( ( ( eBlibType == WMF ) || ( eBlibType == EMF ) ) && bOOxmlExport ) ) + { + nExtra = 17; + p_EscherBlibEntry->mnSizeExtra = nExtra + 8; + + // #i15508# type see SvxMSDffManager::GetBLIPDirect (checked, does not work this way) + // see RtfAttributeOutput::FlyFrameGraphic for more comments + // maybe it would work with direct DIB data, but that would need thorough testing + if( eBlibType == PNG ) + { + nInstance = 0xf01e6e00; + } + else // if( eBlibType == PEG ) + { + nInstance = 0xf01d46a0; + } + //else // eBlibType == DIB + //{ + // nInstance = 0xf01d7A80; + //} + + // #i15508# + //nInstance = ( eBlibType == PNG ) ? 0xf01e6e00 : 0xf01d46a0; + + + rPicOutStrm.WriteUInt32( nInstance ).WriteUInt32( p_EscherBlibEntry->mnSize + nExtra ); + rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16); + rPicOutStrm.WriteUChar( 0xff ); + rPicOutStrm.WriteBytes(pGraphicAry, p_EscherBlibEntry->mnSize); + } + else + { + ZCodec aZCodec( 0x8000, 0x8000 ); + aZCodec.BeginCompression(); + SvMemoryStream aDestStrm; + aZCodec.Write( aDestStrm, pGraphicAry, p_EscherBlibEntry->mnSize ); + aZCodec.EndCompression(); + p_EscherBlibEntry->mnSize = aDestStrm.TellEnd(); + pGraphicAry = static_cast(aDestStrm.GetData()); + if ( p_EscherBlibEntry->mnSize && pGraphicAry ) + { + nExtra = eBlibType == WMF ? 0x42 : 0x32; // !EMF -> no change + p_EscherBlibEntry->mnSizeExtra = nExtra + 8; + nInstance = ( eBlibType == WMF ) ? 0xf01b2170 : 0xf01a3d40; // !EMF -> no change + rPicOutStrm.WriteUInt32( nInstance ).WriteUInt32( p_EscherBlibEntry->mnSize + nExtra ); + if ( eBlibType == WMF ) // !EMF -> no change + rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16); + rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16); + + /* + ##913## + For Word the stored size of the graphic is critical the + metafile boundaries must match the actual graphics + boundaries, and the width and height must be in EMU's + + If you don't do it this way then objects edited in the + msoffice app may show strange behaviour as the size jumps + around, and the original size and scaling factor in word + will be a very strange figure + */ + sal_uInt32 nPrefWidth = p_EscherBlibEntry->maPrefSize.Width(); + sal_uInt32 nPrefHeight = p_EscherBlibEntry->maPrefSize.Height(); + sal_uInt32 nWidth, nHeight; + if ( pVisArea ) + { + nWidth = pVisArea->Width * 360; + nHeight = pVisArea->Height * 360; + } + else + { + Size aPrefSize(lcl_SizeToEmu(p_EscherBlibEntry->maPrefSize, p_EscherBlibEntry->maPrefMapMode)); + nWidth = aPrefSize.Width() * 360; + nHeight = aPrefSize.Height() * 360; + } + rPicOutStrm.WriteUInt32( nUncompressedSize ) // WMFSize without FileHeader + .WriteInt32( 0 ) // since we can't find out anymore what the original size of + .WriteInt32( 0 ) // the WMF (without Fileheader) was we write 10cm / x + .WriteUInt32( nPrefWidth ) + .WriteUInt32( nPrefHeight ) + .WriteUInt32( nWidth ) + .WriteUInt32( nHeight ) + .WriteUInt32( p_EscherBlibEntry->mnSize ) + .WriteUInt16( 0xfe00 ); // compression Flags + rPicOutStrm.WriteBytes(pGraphicAry, p_EscherBlibEntry->mnSize); + } + } + if ( nAtomSize ) + { + sal_uInt32 nPos = rPicOutStrm.Tell(); + rPicOutStrm.Seek( nAtomSize - 4 ); + rPicOutStrm.WriteUInt32( nPos - nAtomSize ); + rPicOutStrm.Seek( nPos ); + } + nBlibId = ImplInsertBlib( p_EscherBlibEntry.release() ); + } + } + return nBlibId; +} + +namespace { + +struct EscherConnectorRule +{ + sal_uInt32 nRuleId; + sal_uInt32 nShapeA; // SPID of shape A + sal_uInt32 nShapeB; // SPID of shape B + sal_uInt32 nShapeC; // SPID of connector shape + sal_uInt32 ncptiA; // Connection site Index of shape A + sal_uInt32 ncptiB; // Connection site Index of shape B +}; + +} + +struct EscherShapeListEntry +{ + uno::ReferenceaXShape; + sal_uInt32 n_EscherId; + + EscherShapeListEntry(uno::Reference xShape, sal_uInt32 nId) + : aXShape(std::move(xShape)) + , n_EscherId(nId) + {} +}; + +sal_uInt32 EscherConnectorListEntry::GetClosestPoint( const tools::Polygon& rPoly, const awt::Point& rPoint ) +{ + sal_uInt16 nCount = rPoly.GetSize(); + sal_uInt16 nClosest = nCount; + double fDist = sal_uInt32(0xffffffff); + while( nCount-- ) + { + double fDistance = hypot( rPoint.X - rPoly[ nCount ].X(), rPoint.Y - rPoly[ nCount ].Y() ); + if ( fDistance < fDist ) + { + nClosest = nCount; + fDist = fDistance; + } + } + return nClosest; +}; + + +// for rectangles for ellipses for polygons +// +// nRule = 0 ->Top 0 ->Top nRule = index to a (Poly)Polygon point +// 1 ->Left 2 ->Left +// 2 ->Bottom 4 ->Bottom +// 3 ->Right 6 ->Right + +sal_uInt32 EscherConnectorListEntry::GetConnectorRule( bool bFirst ) +{ + sal_uInt32 nRule = 0; + + uno::Any aAny; + awt::Point aRefPoint( bFirst ? maPointA : maPointB ); + uno::Reference + aXShape( bFirst ? mXConnectToA : mXConnectToB ); + + OUString aString(aXShape->getShapeType()); + OStringBuffer aBuf(OUStringToOString(aString, RTL_TEXTENCODING_UTF8)); + aBuf.remove( 0, 13 ); // removing "com.sun.star." + sal_Int16 nPos = aBuf.toString().indexOf("Shape"); + aBuf.remove(nPos, 5); + OString aType = aBuf.makeStringAndClear(); + + uno::Reference + aPropertySet( aXShape, uno::UNO_QUERY ); + + if ((aType == "drawing.PolyPolygon") || (aType == "drawing.PolyLine")) + { + if ( aPropertySet.is() ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet, "PolyPolygon" ) ) + { + auto pSourcePolyPolygon = + o3tl::doAccess(aAny); + sal_Int32 nOuterSequenceCount = pSourcePolyPolygon->getLength(); + drawing::PointSequence const * pOuterSequence = pSourcePolyPolygon->getConstArray(); + + if ( pOuterSequence ) + { + sal_Int32 a, b, nIndex = 0; + sal_uInt32 nDistance = 0xffffffff; + for( a = 0; a < nOuterSequenceCount; a++ ) + { + drawing::PointSequence const * pInnerSequence = pOuterSequence++; + if ( pInnerSequence ) + { + awt::Point const * pArray = pInnerSequence->getConstArray(); + if ( pArray ) + { + for ( b = 0; b < pInnerSequence->getLength(); b++, nIndex++, pArray++ ) + { + sal_uInt32 nDist = static_cast(hypot( aRefPoint.X - pArray->X, aRefPoint.Y - pArray->Y )); + if ( nDist < nDistance ) + { + nRule = nIndex; + nDistance = nDist; + } + } + } + } + } + } + } + } + } + else if ((aType == "drawing.OpenBezier") || (aType == "drawing.OpenFreeHand") || (aType == "drawing.PolyLinePath") + || (aType == "drawing.ClosedBezier") || ( aType == "drawing.ClosedFreeHand") || (aType == "drawing.PolyPolygonPath") ) + { + uno::Reference + aPropertySet2( aXShape, uno::UNO_QUERY ); + if ( aPropertySet2.is() ) + { + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet2, "PolyPolygonBezier" ) ) + { + auto pSourcePolyPolygon = + o3tl::doAccess(aAny); + sal_Int32 nOuterSequenceCount = pSourcePolyPolygon->Coordinates.getLength(); + + // get pointer of inner sequences + drawing::PointSequence const * pOuterSequence = + pSourcePolyPolygon->Coordinates.getConstArray(); + drawing::FlagSequence const * pOuterFlags = + pSourcePolyPolygon->Flags.getConstArray(); + + if ( pOuterSequence && pOuterFlags ) + { + sal_Int32 a, b, nIndex = 0; + sal_uInt32 nDistance = 0xffffffff; + + for ( a = 0; a < nOuterSequenceCount; a++ ) + { + drawing::PointSequence const * pInnerSequence = pOuterSequence++; + drawing::FlagSequence const * pInnerFlags = pOuterFlags++; + if ( pInnerSequence && pInnerFlags ) + { + awt::Point const * pArray = pInnerSequence->getConstArray(); + drawing::PolygonFlags const * pFlags = pInnerFlags->getConstArray(); + if ( pArray && pFlags ) + { + for ( b = 0; b < pInnerSequence->getLength(); b++, pArray++ ) + { + drawing::PolygonFlags ePolyFlags = *pFlags++; + if ( ePolyFlags == drawing::PolygonFlags_CONTROL ) + continue; + sal_uInt32 nDist = static_cast(hypot( aRefPoint.X - pArray->X, aRefPoint.Y - pArray->Y )); + if ( nDist < nDistance ) + { + nRule = nIndex; + nDistance = nDist; + } + nIndex++; + } + } + } + } + } + } + } + } + else + { + bool bRectangularConnection = true; + + if (aType == "drawing.Custom") + { + if (auto pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(aXShape))) + { + const SdrCustomShapeGeometryItem& rGeometryItem = + pSdrObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ); + + OUString sShapeType; + const uno::Any* pType = rGeometryItem.GetPropertyValueByName( "Type" ); + if ( pType ) + *pType >>= sShapeType; + MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType ); + + uno::Any* pGluePointType = const_cast(rGeometryItem).GetPropertyValueByName( "Path", "GluePointType" ); + + sal_Int16 nGluePointType = sal_Int16(); + if ( !( pGluePointType && + ( *pGluePointType >>= nGluePointType ) ) ) + nGluePointType = GetCustomShapeConnectionTypeDefault( eSpType ); + + if ( nGluePointType == drawing::EnhancedCustomShapeGluePointType::CUSTOM ) + { + const SdrGluePointList* pList = pSdrObjCustomShape->GetGluePointList(); + if ( pList ) + { + tools::Polygon aPoly; + sal_uInt16 nNum, nCnt = pList->GetCount(); + if ( nCnt ) + { + for ( nNum = 0; nNum < nCnt; nNum++ ) + { + const SdrGluePoint& rGP = (*pList)[ nNum ]; + Point aPt(rGP.GetAbsolutePos(*pSdrObjCustomShape)); + aPoly.Insert( POLY_APPEND, aPt ); + } + nRule = GetClosestPoint( aPoly, aRefPoint ); + bRectangularConnection = false; + } + } + } + else if ( nGluePointType == drawing::EnhancedCustomShapeGluePointType::SEGMENTS ) + { + tools::PolyPolygon aPolyPoly; + SdrObjectUniquePtr pTemporaryConvertResultObject(pSdrObjCustomShape->DoConvertToPolyObj(true, true)); + SdrPathObj* pSdrPathObj(dynamic_cast< SdrPathObj* >(pTemporaryConvertResultObject.get())); + + if(pSdrPathObj) + { + // #i74631# use explicit constructor here. Also XPolyPolygon is not necessary, + // reducing to PolyPolygon + aPolyPoly = tools::PolyPolygon(pSdrPathObj->GetPathPoly()); + } + + // do *not* forget to delete the temporary used SdrObject - possible memory leak (!) + pTemporaryConvertResultObject.reset(); + pSdrPathObj = nullptr; + + if(0 != aPolyPoly.Count()) + { + sal_Int16 nIndex = 0; + sal_uInt16 a, b; + sal_uInt32 nDistance = 0xffffffff; + + for ( a = 0; a < aPolyPoly.Count(); a++ ) + { + const tools::Polygon& rPoly = aPolyPoly.GetObject( a ); + for ( b = 0; b < rPoly.GetSize(); b++ ) + { + if ( rPoly.GetFlags( b ) != PolyFlags::Normal ) + continue; + const Point& rPt = rPoly[ b ]; + sal_uInt32 nDist = static_cast(hypot( aRefPoint.X - rPt.X(), aRefPoint.Y - rPt.Y() )); + if ( nDist < nDistance ) + { + nRule = nIndex; + nDistance = nDist; + } + nIndex++; + } + } + + if ( nDistance != 0xffffffff ) + bRectangularConnection = false; + } + } + } + } + if ( bRectangularConnection ) + { + awt::Point aPoint( aXShape->getPosition() ); + awt::Size aSize( aXShape->getSize() ); + + tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) ); + Point aCenter( aRect.Center() ); + tools::Polygon aPoly( 4 ); + + aPoly[ 0 ] = Point( aCenter.X(), aRect.Top() ); + aPoly[ 1 ] = Point( aRect.Left(), aCenter.Y() ); + aPoly[ 2 ] = Point( aCenter.X(), aRect.Bottom() ); + aPoly[ 3 ] = Point( aRect.Right(), aCenter.Y() ); + + sal_Int32 nAngle = ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet, "RotateAngle", true ) ) + ? *o3tl::doAccess(aAny) : 0; + if ( nAngle ) + aPoly.Rotate( aRect.TopLeft(), Degree10(static_cast( ( nAngle + 5 ) / 10 )) ); + nRule = GetClosestPoint( aPoly, aRefPoint ); + + if (aType == "drawing.Ellipse") + nRule <<= 1; // In PPT an ellipse has 8 ways to connect + } + } + return nRule; +} + +EscherSolverContainer::EscherSolverContainer() +{ +} + +EscherSolverContainer::~EscherSolverContainer() +{ +} + +void EscherSolverContainer::AddShape( const uno::Reference & rXShape, sal_uInt32 nId ) +{ + maShapeList.push_back( std::make_unique( rXShape, nId ) ); +} + +void EscherSolverContainer::AddConnector( + const uno::Reference & rConnector, + const awt::Point& rPA, + uno::Reference const & rConA, + const awt::Point& rPB, + uno::Reference const & rConB +) +{ + maConnectorList.push_back( std::make_unique( rConnector, rPA, rConA, rPB, rConB ) ); +} + +sal_uInt32 EscherSolverContainer::GetShapeId( const uno::Reference & rXShape ) const +{ + for (auto const & pPtr : maShapeList) + { + if ( rXShape == pPtr->aXShape ) + return pPtr->n_EscherId; + } + return 0; +} + +void EscherSolverContainer::WriteSolver( SvStream& rStrm ) +{ + sal_uInt32 nCount = maConnectorList.size(); + if ( !nCount ) + return; + + sal_uInt32 nRecHdPos, nCurrentPos, nSize; + rStrm .WriteUInt16( ( nCount << 4 ) | 0xf ) // open an ESCHER_SolverContainer + .WriteUInt16( ESCHER_SolverContainer ) + .WriteUInt32( 0 ); + + nRecHdPos = rStrm.Tell() - 4; + + EscherConnectorRule aConnectorRule; + aConnectorRule.nRuleId = 2; + for (auto const & pPtr : maConnectorList) + { + aConnectorRule.ncptiA = aConnectorRule.ncptiB = 0xffffffff; + aConnectorRule.nShapeC = GetShapeId( pPtr->mXConnector ); + aConnectorRule.nShapeA = GetShapeId( pPtr->mXConnectToA ); + aConnectorRule.nShapeB = GetShapeId( pPtr->mXConnectToB ); + + if ( aConnectorRule.nShapeC ) + { + if ( aConnectorRule.nShapeA ) + aConnectorRule.ncptiA = pPtr->GetConnectorRule( true ); + if ( aConnectorRule.nShapeB ) + aConnectorRule.ncptiB = pPtr->GetConnectorRule( false ); + } + rStrm .WriteUInt32( ( ESCHER_ConnectorRule << 16 ) | 1 ) // atom hd + .WriteUInt32( 24 ) + .WriteUInt32( aConnectorRule.nRuleId ) + .WriteUInt32( aConnectorRule.nShapeA ) + .WriteUInt32( aConnectorRule.nShapeB ) + .WriteUInt32( aConnectorRule.nShapeC ) + .WriteUInt32( aConnectorRule.ncptiA ) + .WriteUInt32( aConnectorRule.ncptiB ); + + aConnectorRule.nRuleId += 2; + } + + nCurrentPos = rStrm.Tell(); // close the ESCHER_SolverContainer + nSize = ( nCurrentPos - nRecHdPos ) - 4; + rStrm.Seek( nRecHdPos ); + rStrm.WriteUInt32( nSize ); + rStrm.Seek( nCurrentPos ); +} + +EscherExGlobal::EscherExGlobal() : + EscherGraphicProvider( EscherGraphicProviderFlags::NONE ), + mpPicStrm( nullptr ), + mbHasDggCont( false ), + mbPicStrmQueried( false ) +{ +} + +EscherExGlobal::~EscherExGlobal() +{ +} + +sal_uInt32 EscherExGlobal::GenerateDrawingId() +{ + // new drawing starts a new cluster in the cluster table (cluster identifiers are one-based) + sal_uInt32 nClusterId = static_cast< sal_uInt32 >( maClusterTable.size() + 1 ); + // drawing identifiers are one-based + sal_uInt32 nDrawingId = static_cast< sal_uInt32 >( maDrawingInfos.size() + 1 ); + // prepare new entries in the tables + maClusterTable.emplace_back( nDrawingId ); + maDrawingInfos.emplace_back( nClusterId ); + // return the new drawing identifier + return nDrawingId; +} + +sal_uInt32 EscherExGlobal::GenerateShapeId( sal_uInt32 nDrawingId, bool bIsInSpgr ) +{ + // drawing identifier is one-based + // make sure the drawing is valid (bnc#656503) + if ( nDrawingId == 0 ) + return 0; + // create index from the identifier + size_t nDrawingIdx = nDrawingId - 1; + OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GenerateShapeId - invalid drawing ID" ); + if( nDrawingIdx >= maDrawingInfos.size() ) + return 0; + DrawingInfo& rDrawingInfo = maDrawingInfos[ nDrawingIdx ]; + + // cluster identifier in drawing info struct is one-based + ClusterEntry* pClusterEntry = &maClusterTable[ rDrawingInfo.mnClusterId - 1 ]; + + // check cluster overflow, create new cluster entry + if( pClusterEntry->mnNextShapeId == DFF_DGG_CLUSTER_SIZE ) + { + // start a new cluster in the cluster table + maClusterTable.emplace_back( nDrawingId ); + pClusterEntry = &maClusterTable.back(); + // new size of maClusterTable is equal to one-based identifier of the new cluster + rDrawingInfo.mnClusterId = static_cast< sal_uInt32 >( maClusterTable.size() ); + } + + // build shape identifier from cluster identifier and next free cluster shape identifier + rDrawingInfo.mnLastShapeId = static_cast< sal_uInt32 >( rDrawingInfo.mnClusterId * DFF_DGG_CLUSTER_SIZE + pClusterEntry->mnNextShapeId ); + // update free shape identifier in cluster entry + ++pClusterEntry->mnNextShapeId; + /* Old code has counted the shapes only, if we are in a SPGRCONTAINER. Is + this really intended? Maybe it's always true... */ + if( bIsInSpgr ) + ++rDrawingInfo.mnShapeCount; + + // return the new shape identifier + return rDrawingInfo.mnLastShapeId; +} + +sal_uInt32 EscherExGlobal::GetDrawingShapeCount( sal_uInt32 nDrawingId ) const +{ + size_t nDrawingIdx = nDrawingId - 1; + OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GetDrawingShapeCount - invalid drawing ID" ); + return (nDrawingIdx < maDrawingInfos.size()) ? maDrawingInfos[ nDrawingIdx ].mnShapeCount : 0; +} + +sal_uInt32 EscherExGlobal::GetLastShapeId( sal_uInt32 nDrawingId ) const +{ + size_t nDrawingIdx = nDrawingId - 1; + OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GetLastShapeId - invalid drawing ID" ); + return (nDrawingIdx < maDrawingInfos.size()) ? maDrawingInfos[ nDrawingIdx ].mnLastShapeId : 0; +} + +sal_uInt32 EscherExGlobal::GetDggAtomSize() const +{ + // 8 bytes header, 16 bytes fixed DGG data, 8 bytes for each cluster + return static_cast< sal_uInt32 >( 24 + 8 * maClusterTable.size() ); +} + +void EscherExGlobal::WriteDggAtom( SvStream& rStrm ) const +{ + sal_uInt32 nDggSize = GetDggAtomSize(); + + // write the DGG record header (do not include the 8 bytes of the header in the data size) + rStrm.WriteUInt32( ESCHER_Dgg << 16 ).WriteUInt32( nDggSize - 8 ); + + // calculate and write the fixed DGG data + sal_uInt32 nShapeCount = 0; + sal_uInt32 nLastShapeId = 0; + for (auto const& drawingInfo : maDrawingInfos) + { + nShapeCount += drawingInfo.mnShapeCount; + nLastShapeId = ::std::max( nLastShapeId, drawingInfo.mnLastShapeId ); + } + // the non-existing cluster with index #0 is counted too + sal_uInt32 nClusterCount = static_cast< sal_uInt32 >( maClusterTable.size() + 1 ); + sal_uInt32 nDrawingCount = static_cast< sal_uInt32 >( maDrawingInfos.size() ); + rStrm.WriteUInt32( nLastShapeId ).WriteUInt32( nClusterCount ).WriteUInt32( nShapeCount ).WriteUInt32( nDrawingCount ); + + // write the cluster table + for (auto const& elem : maClusterTable) + rStrm.WriteUInt32( elem.mnDrawingId ).WriteUInt32( elem.mnNextShapeId ); +} + +SvStream* EscherExGlobal::QueryPictureStream() +{ + if( !mbPicStrmQueried ) + { + mpPicStrm = ImplQueryPictureStream(); + mbPicStrmQueried = true; + } + return mpPicStrm; +} + +SvStream* EscherExGlobal::ImplQueryPictureStream() +{ + return nullptr; +} + +namespace { + +// Implementation of an empty stream that silently succeeds, but does nothing. +// +// In fact, this is a hack. The right solution is to abstract EscherEx to be +// able to work without SvStream; but at the moment it is better to live with +// this I guess. +class SvNullStream : public SvStream +{ +protected: + virtual std::size_t GetData( void* pData, std::size_t nSize ) override { memset( pData, 0, nSize ); return nSize; } + virtual std::size_t PutData( const void*, std::size_t nSize ) override { return nSize; } + virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override { return nPos; } + virtual void SetSize( sal_uInt64 ) override {} + virtual void FlushData() override {} + +public: + SvNullStream() {} +}; + +} + +EscherEx::EscherEx(std::shared_ptr xGlobal, SvStream* pOutStrm, bool bOOXML) + : mxGlobal(std::move(xGlobal)) + , mpOutStrm(pOutStrm) + , mbOwnsStrm(false) + , mnCurrentDg(0) + , mnCountOfs(0) + , mnGroupLevel(0) + , mnHellLayerId(SDRLAYER_NOTFOUND) + , mbEscherSpgr(false) + , mbEscherDg(false) + , mbOOXML(bOOXML) +{ + if (!mpOutStrm) + { + mpOutStrm = new SvNullStream(); + mbOwnsStrm = true; + } + mnStrmStartOfs = mpOutStrm->Tell(); + mpImplEESdrWriter.reset( new ImplEESdrWriter( *this ) ); +} + +EscherEx::~EscherEx() +{ + if (mbOwnsStrm) + delete mpOutStrm; +} + +void EscherEx::Flush( SvStream* pPicStreamMergeBSE /* = NULL */ ) +{ + if ( !mxGlobal->HasDggContainer() ) + return; + + // store the current stream position at ESCHER_Persist_CurrentPosition key + PtReplaceOrInsert( ESCHER_Persist_CurrentPosition, mpOutStrm->Tell() ); + if ( DoSeek( ESCHER_Persist_Dgg ) ) + { + /* The DGG record is still not written. ESCHER_Persist_Dgg seeks + to the place where the complete record has to be inserted. */ + InsertAtCurrentPos( mxGlobal->GetDggAtomSize() ); + mxGlobal->WriteDggAtom( *mpOutStrm ); + + if ( mxGlobal->HasGraphics() ) + { + /* Calculate the total size of the BSTORECONTAINER including + all BSE records containing the picture data contained in + the passed in pPicStreamMergeBSE. */ + sal_uInt32 nBSCSize = mxGlobal->GetBlibStoreContainerSize( pPicStreamMergeBSE ); + if ( nBSCSize > 0 ) + { + InsertAtCurrentPos( nBSCSize ); + mxGlobal->WriteBlibStoreContainer( *mpOutStrm, pPicStreamMergeBSE ); + } + } + + /* Forget the stream position stored for the DGG which is invalid + after the call to InsertAtCurrentPos() anyway. */ + PtDelete( ESCHER_Persist_Dgg ); + } + // seek to initial position (may be different due to inserted DGG and BLIPs) + mpOutStrm->Seek( PtGetOffsetByID( ESCHER_Persist_CurrentPosition ) ); +} + +void EscherEx::InsertAtCurrentPos( sal_uInt32 nBytes ) +{ + sal_uInt32 nSize, nType, nSource, nBufSize, nToCopy, nCurPos = mpOutStrm->Tell(); + + // adjust persist table + for(auto const & pPtr : maPersistTable) { + sal_uInt32 nOfs = pPtr->mnOffset; + if ( nOfs >= nCurPos ) { + pPtr->mnOffset += nBytes; + } + } + + // adapt container and atom sizes + mpOutStrm->Seek( mnStrmStartOfs ); + while ( mpOutStrm->Tell() < nCurPos ) + { + mpOutStrm->ReadUInt32( nType ).ReadUInt32( nSize ); + sal_uInt32 nEndOfRecord = mpOutStrm->Tell() + nSize; + bool bContainer = (nType & 0x0F) == 0x0F; + /* Expand the record, if the insertion position is inside, or if the + position is at the end of a container (expands always), or at the + end of an atom and bExpandEndOfAtom is set. */ + if ( (nCurPos < nEndOfRecord) || ((nCurPos == nEndOfRecord) && bContainer) ) + { + mpOutStrm->SeekRel( -4 ); + mpOutStrm->WriteUInt32( nSize + nBytes ); + if ( !bContainer ) + mpOutStrm->SeekRel( nSize ); + } + else + mpOutStrm->SeekRel( nSize ); + } + for (auto & offset : mOffsets) + { + if ( offset > nCurPos ) + offset += nBytes; + } + nSource = mpOutStrm->TellEnd(); + nToCopy = nSource - nCurPos; // increase the size of the stream by nBytes + std::unique_ptr pBuf(new sal_uInt8[ 0x40000 ]); // 256KB Buffer + while ( nToCopy ) + { + nBufSize = ( nToCopy >= 0x40000 ) ? 0x40000 : nToCopy; + nToCopy -= nBufSize; + nSource -= nBufSize; + mpOutStrm->Seek( nSource ); + mpOutStrm->ReadBytes(pBuf.get(), nBufSize); + mpOutStrm->Seek( nSource + nBytes ); + mpOutStrm->WriteBytes(pBuf.get(), nBufSize); + } + mpOutStrm->Seek( nCurPos ); +} + +void EscherEx::InsertPersistOffset( sal_uInt32 nKey, sal_uInt32 nOffset ) +{ + PtInsert( ESCHER_Persist_PrivateEntry | nKey, nOffset ); +} + +void EscherEx::ReplacePersistOffset( sal_uInt32 nKey, sal_uInt32 nOffset ) +{ + PtReplace( ESCHER_Persist_PrivateEntry | nKey, nOffset ); +} + +void EscherEx::SetEditAs( const OUString& rEditAs ) +{ + mEditAs = rEditAs; +} + +sal_uInt32 EscherEx::GetPersistOffset( sal_uInt32 nKey ) +{ + return PtGetOffsetByID( ESCHER_Persist_PrivateEntry | nKey ); +} + +bool EscherEx::DoSeek( sal_uInt32 nKey ) +{ + sal_uInt32 nPos = PtGetOffsetByID( nKey ); + if ( nPos ) + mpOutStrm->Seek( nPos ); + else + { + if (! PtIsID( nKey ) ) + return false; + mpOutStrm->Seek( 0 ); + } + return true; +} + +bool EscherEx::SeekToPersistOffset( sal_uInt32 nKey ) +{ + return DoSeek( ESCHER_Persist_PrivateEntry | nKey ); +} + +void EscherEx::InsertAtPersistOffset( sal_uInt32 nKey, sal_uInt32 nValue ) +{ + sal_uInt32 nOldPos = mpOutStrm->Tell(); + bool bRetValue = SeekToPersistOffset( nKey ); + if ( bRetValue ) + { + mpOutStrm->WriteUInt32( nValue ); + mpOutStrm->Seek( nOldPos ); + } +} + +void EscherEx::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance ) +{ + mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | 0xf ).WriteUInt16( nEscherContainer ).WriteUInt32( 0 ); + mOffsets.push_back( mpOutStrm->Tell() - 4 ); + mRecTypes.push_back( nEscherContainer ); + switch( nEscherContainer ) + { + case ESCHER_DggContainer : + { + mxGlobal->SetDggContainer(); + mnCurrentDg = 0; + /* Remember the current position as start position of the DGG + record and BSTORECONTAINER, but do not write them actually. + This will be done later in Flush() when the number of drawings, + the size and contents of the FIDCL cluster table, and the size + of the BLIP container are known. */ + PtReplaceOrInsert( ESCHER_Persist_Dgg, mpOutStrm->Tell() ); + } + break; + + case ESCHER_DgContainer : + { + if ( mxGlobal->HasDggContainer() ) + { + if ( !mbEscherDg ) + { + mbEscherDg = true; + mnCurrentDg = mxGlobal->GenerateDrawingId(); + AddAtom( 8, ESCHER_Dg, 0, mnCurrentDg ); + PtReplaceOrInsert( ESCHER_Persist_Dg | mnCurrentDg, mpOutStrm->Tell() ); + mpOutStrm->WriteUInt32( 0 ) // The number of shapes in this drawing + .WriteUInt32( 0 ); // The last MSOSPID given to an SP in this DG + } + } + } + break; + + case ESCHER_SpgrContainer : + { + if ( mbEscherDg ) + { + mbEscherSpgr = true; + } + } + break; + + case ESCHER_SpContainer : + { + } + break; + + default: + break; + } +} + +void EscherEx::CloseContainer() +{ + sal_uInt32 nSize, nPos = mpOutStrm->Tell(); + nSize = ( nPos - mOffsets.back() ) - 4; + mpOutStrm->Seek( mOffsets.back() ); + mpOutStrm->WriteUInt32( nSize ); + + switch( mRecTypes.back() ) + { + case ESCHER_DgContainer : + { + if ( mbEscherDg ) + { + mbEscherDg = false; + if ( DoSeek( ESCHER_Persist_Dg | mnCurrentDg ) ) + mpOutStrm->WriteUInt32( mxGlobal->GetDrawingShapeCount( mnCurrentDg ) ).WriteUInt32( mxGlobal->GetLastShapeId( mnCurrentDg ) ); + } + } + break; + + case ESCHER_SpgrContainer : + { + if ( mbEscherSpgr ) + { + mbEscherSpgr = false; + + } + } + break; + + default: + break; + } + mOffsets.pop_back(); + mRecTypes.pop_back(); + mpOutStrm->Seek( nPos ); +} + +void EscherEx::BeginAtom() +{ + mnCountOfs = mpOutStrm->Tell(); + mpOutStrm->WriteUInt32( 0 ).WriteUInt32( 0 ); // record header will be written later +} + +void EscherEx::EndAtom( sal_uInt16 nRecType, int nRecVersion, int nRecInstance ) +{ + sal_uInt32 nOldPos = mpOutStrm->Tell(); + mpOutStrm->Seek( mnCountOfs ); + sal_uInt32 nSize = nOldPos - mnCountOfs; + mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | ( nRecVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nSize - 8 ); + mpOutStrm->Seek( nOldPos ); +} + +void EscherEx::AddAtom( sal_uInt32 nAtomSize, sal_uInt16 nRecType, int nRecVersion, int nRecInstance ) +{ + mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | ( nRecVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nAtomSize ); +} + +void EscherEx::AddChildAnchor( const tools::Rectangle& rRect ) +{ + AddAtom( 16, ESCHER_ChildAnchor ); + mpOutStrm ->WriteInt32( rRect.Left() ) + .WriteInt32( rRect.Top() ) + .WriteInt32( rRect.Right() ) + .WriteInt32( rRect.Bottom() ); +} + +void EscherEx::AddClientAnchor( const tools::Rectangle& rRect ) +{ + AddAtom( 8, ESCHER_ClientAnchor ); + mpOutStrm->WriteInt16( rRect.Top() ) + .WriteInt16( rRect.Left() ) + .WriteInt16( rRect.GetWidth() + rRect.Left() ) + .WriteInt16( rRect.GetHeight() + rRect.Top() ); +} + +EscherExHostAppData* EscherEx::EnterAdditionalTextGroup() +{ + return nullptr; +} + +sal_uInt32 EscherEx::EnterGroup( const OUString& rShapeName, const tools::Rectangle* pBoundRect ) +{ + tools::Rectangle aRect; + if( pBoundRect ) + aRect = *pBoundRect; + + OpenContainer( ESCHER_SpgrContainer ); + OpenContainer( ESCHER_SpContainer ); + AddAtom( 16, ESCHER_Spgr, 1 ); + PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel, + mpOutStrm->Tell() ); + mpOutStrm ->WriteInt32( aRect.Left() ) // Bounding box for the grouped shapes to which they will be attached + .WriteInt32( aRect.Top() ) + .WriteInt32( aRect.IsWidthEmpty() ? aRect.Left() : aRect.Right() ) + .WriteInt32( aRect.IsHeightEmpty() ? aRect.Top() : aRect.Bottom() ); + + sal_uInt32 nShapeId = GenerateShapeId(); + if ( !mnGroupLevel ) + AddShape( ESCHER_ShpInst_Min, ShapeFlag::Group | ShapeFlag::Patriarch, nShapeId ); + else + { + AddShape( ESCHER_ShpInst_Min, ShapeFlag::Group | ShapeFlag::HaveAnchor, nShapeId ); + EscherPropertyContainer aPropOpt; + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x00040004 ); + aPropOpt.AddOpt( ESCHER_Prop_dxWrapDistLeft, 0 ); + aPropOpt.AddOpt( ESCHER_Prop_dxWrapDistRight, 0 ); + + // #i51348# shape name + if( rShapeName.getLength() > 0 ) + aPropOpt.AddOpt( ESCHER_Prop_wzName, rShapeName ); + + Commit( aPropOpt, aRect ); + if ( mnGroupLevel > 1 ) + AddChildAnchor( aRect ); + + EscherExHostAppData* pAppData = mpImplEESdrWriter->ImplGetHostData(); + if( pAppData ) + { + if ( mnGroupLevel <= 1 ) + pAppData->WriteClientAnchor( *this, aRect ); + pAppData->WriteClientData( *this ); + } + } + CloseContainer(); // ESCHER_SpContainer + mnGroupLevel++; + return nShapeId; +} + +sal_uInt32 EscherEx::EnterGroup( const tools::Rectangle* pBoundRect ) +{ + return EnterGroup( OUString(), pBoundRect ); +} + +void EscherEx::SetGroupSnapRect( sal_uInt32 nGroupLevel, const tools::Rectangle& rRect ) +{ + if ( nGroupLevel ) + { + sal_uInt32 nCurrentPos = mpOutStrm->Tell(); + if ( DoSeek( ESCHER_Persist_Grouping_Snap | ( nGroupLevel - 1 ) ) ) + { + mpOutStrm ->WriteInt32( rRect.Left() ) // Bounding box for the grouped shapes to which they will be attached + .WriteInt32( rRect.Top() ) + .WriteInt32( rRect.Right() ) + .WriteInt32( rRect.Bottom() ); + mpOutStrm->Seek( nCurrentPos ); + } + } +} + +void EscherEx::SetGroupLogicRect( sal_uInt32 nGroupLevel, const tools::Rectangle& rRect ) +{ + if ( nGroupLevel ) + { + sal_uInt32 nCurrentPos = mpOutStrm->Tell(); + if ( DoSeek( ESCHER_Persist_Grouping_Logic | ( nGroupLevel - 1 ) ) ) + { + mpOutStrm->WriteInt16( rRect.Top() ).WriteInt16( rRect.Left() ).WriteInt16( rRect.Right() ).WriteInt16( rRect.Bottom() ); + mpOutStrm->Seek( nCurrentPos ); + } + } +} + +void EscherEx::LeaveGroup() +{ + --mnGroupLevel; + PtDelete( ESCHER_Persist_Grouping_Snap | mnGroupLevel ); + PtDelete( ESCHER_Persist_Grouping_Logic | mnGroupLevel ); + CloseContainer(); +} + +void EscherEx::AddShape( sal_uInt32 nShpInstance, ShapeFlag nFlags, sal_uInt32 nShapeID ) +{ + AddAtom( 8, ESCHER_Sp, 2, nShpInstance ); + + if ( !nShapeID ) + nShapeID = GenerateShapeId(); + + if (nFlags ^ ShapeFlag::Group) // no pure group shape + { + if ( mnGroupLevel > 1 ) + nFlags |= ShapeFlag::Child; // this not a topmost shape + } + mpOutStrm->WriteUInt32( nShapeID ).WriteUInt32( static_cast(nFlags) ); +} + +void EscherEx::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& ) +{ + rProps.Commit( GetStream() ); +} + +sal_uInt32 EscherEx::GetColor( const sal_uInt32 nSOColor ) +{ + sal_uInt32 nColor = nSOColor & 0xff00; // Green + nColor |= static_cast(nSOColor) << 16; // Red + nColor |= static_cast( nSOColor >> 16 ); // Blue + return nColor; +} + +sal_uInt32 EscherEx::GetColor( const Color& rSOColor ) +{ + sal_uInt32 nColor = ( rSOColor.GetRed() << 16 ); + nColor |= ( rSOColor.GetGreen() << 8 ); + nColor |= rSOColor.GetBlue(); + nColor = GetColor( nColor ); + return nColor; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/eschesdo.cxx b/filter/source/msfilter/eschesdo.cxx new file mode 100644 index 000000000..d052b5968 --- /dev/null +++ b/filter/source/msfilter/eschesdo.cxx @@ -0,0 +1,1237 @@ +/* -*- 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 +#include "eschesdo.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::task; + +constexpr o3tl::Length geUnitsSrc(o3tl::Length::mm100); +// PowerPoint: 576 dpi, WinWord: 1440 dpi, Excel: 1440 dpi +constexpr o3tl::Length geUnitsDest(o3tl::Length::twip); + +ImplEESdrWriter::ImplEESdrWriter( EscherEx& rEx ) + : mpEscherEx(&rEx) + , mpPicStrm(nullptr) + , mpHostAppData(nullptr) + , mbIsTitlePossible(false) + , mpSdrPage( nullptr ) +{ +} + + + +Point ImplEESdrWriter::ImplMapPoint( const Point& rPoint ) +{ + return o3tl::convert( rPoint, geUnitsSrc, geUnitsDest ); +} + +Size ImplEESdrWriter::ImplMapSize( const Size& rSize ) +{ + Size aRetSize( o3tl::convert( rSize, geUnitsSrc, geUnitsDest ) ); + + if ( !aRetSize.Width() ) + aRetSize.AdjustWidth( 1 ); + if ( !aRetSize.Height() ) + aRetSize.AdjustHeight( 1 ); + return aRetSize; +} + +void ImplEESdrWriter::ImplFlipBoundingBox( ImplEESdrObject& rObj, EscherPropertyContainer& rPropOpt ) +{ + sal_Int32 nAngle = rObj.GetAngle(); + tools::Rectangle aRect( rObj.GetRect() ); + + // for position calculations, we normalize the angle between 0 and 90 degrees + if ( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + if ( nAngle % 18000 == 0 ) + nAngle = 0; + while ( nAngle > 9000 ) + nAngle = ( 18000 - ( nAngle % 18000 ) ); + + double fVal = basegfx::deg2rad<100>(nAngle); + double fCos = cos( fVal ); + double fSin = sin( fVal ); + + double nWidthHalf = static_cast(aRect.GetWidth()) / 2; + double nHeightHalf = static_cast(aRect.GetHeight()) / 2; + + // fdo#70838: + // when you rotate an object, the top-left corner of its bounding box is moved + // nXDiff and nYDiff pixels. To get their values we use these equations: + // + // fSin * nHeightHalf + fCos * nWidthHalf == nXDiff + nWidthHalf + // fSin * nWidthHalf + fCos * nHeightHalf == nYDiff + nHeightHalf + + double nXDiff = fSin * nHeightHalf + fCos * nWidthHalf - nWidthHalf; + double nYDiff = fSin * nWidthHalf + fCos * nHeightHalf - nHeightHalf; + + aRect.Move( static_cast(nXDiff), static_cast(nYDiff) ); + + // calculate the proper angle value to be saved + nAngle = rObj.GetAngle(); + if ( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + else + nAngle = ( 36000 - ( nAngle % 36000 ) ); + + nAngle *= 655; + nAngle += 0x8000; + nAngle &=~0xffff; // nAngle round to full degrees + rPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle ); + + rObj.SetAngle( nAngle ); + rObj.SetRect( aRect ); +} + + +sal_uInt32 ImplEESdrWriter::ImplWriteShape( ImplEESdrObject& rObj, + EscherSolverContainer& rSolverContainer, + const bool bOOxmlExport ) +{ + sal_uInt32 nShapeID = 0; + sal_uInt16 nShapeType = 0; + bool bDontWriteText = false; // if a metafile is written as shape replacement, then the text is already part of the metafile + bool bAdditionalText = false; + sal_uInt32 nGrpShapeID = 0; + auto addShape = [this, &rObj, &rSolverContainer, &nShapeID, &nShapeType](sal_uInt16 nType, ShapeFlag nFlags) + { + nShapeType = nType; + nShapeID = mpEscherEx->GenerateShapeId(); + rObj.SetShapeId( nShapeID ); + mpEscherEx->AddShape( nType, nFlags, nShapeID ); + rSolverContainer.AddShape( rObj.GetShapeRef(), nShapeID ); + }; + + do { + mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : nullptr ); + if ( mpHostAppData && mpHostAppData->DontWriteShape() ) + break; + + // #i51348# get shape name + OUString aShapeName; + if( const SdrObject* pSdrObj = rObj.GetSdrObject() ) + if (!pSdrObj->GetName().isEmpty()) + aShapeName = pSdrObj->GetName(); + uno::Reference< drawing::XShape> xShape = rObj.GetShapeRef(); + if (xShape.is()) + { + uno::Reference xPropertySet(xShape, uno::UNO_QUERY); + if (xPropertySet.is()) + { + uno::Sequence aGrabBag; + uno::Reference< XPropertySetInfo > xPropInfo = xPropertySet->getPropertySetInfo(); + if ( xPropInfo.is() && xPropInfo->hasPropertyByName( "InteropGrabBag" ) ) + { + xPropertySet->getPropertyValue( "InteropGrabBag" ) >>= aGrabBag; + for (const beans::PropertyValue& rProp : std::as_const(aGrabBag)) + { + if (rProp.Name == "mso-edit-as") + { + OUString rEditAs; + rProp.Value >>= rEditAs; + mpEscherEx->SetEditAs(rEditAs); + break; + } + } + } + } + } + + if( rObj.GetType() == "drawing.Group" ) + { + Reference< XIndexAccess > xXIndexAccess( rObj.GetShapeRef(), UNO_QUERY ); + + if( xXIndexAccess.is() && 0 != xXIndexAccess->getCount() ) + { + nShapeID = mpEscherEx->EnterGroup( aShapeName, &rObj.GetRect() ); + nShapeType = ESCHER_ShpInst_Min; + + for( sal_uInt32 n = 0, nCnt = xXIndexAccess->getCount(); + n < nCnt; ++n ) + { + ImplEESdrObject aObj( *o3tl::doAccess>( + xXIndexAccess->getByIndex( n )) ); + if( aObj.IsValid() ) + { + aObj.SetOOXML(bOOxmlExport); + ImplWriteShape( aObj, rSolverContainer, bOOxmlExport ); + } + } + mpEscherEx->LeaveGroup(); + } + break; + } + rObj.SetAngle( rObj.ImplGetInt32PropertyValue( "RotateAngle" )); + + if( ( rObj.ImplGetPropertyValue( "IsFontwork" ) && + ::cppu::any2bool( rObj.GetUsrAny() ) ) || + rObj.GetType() == "drawing.Measure" ) + { + rObj.SetType("drawing.dontknow"); + } + + const css::awt::Size aSize100thmm( rObj.GetShapeRef()->getSize() ); + const css::awt::Point aPoint100thmm( rObj.GetShapeRef()->getPosition() ); + tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) ); + if ( !mpPicStrm ) + mpPicStrm = mpEscherEx->QueryPictureStream(); + EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm ); + + // #i51348# shape name + if (!aShapeName.isEmpty()) + aPropOpt.AddOpt( ESCHER_Prop_wzName, aShapeName ); + if ( InteractionInfo* pInteraction = mpHostAppData ? mpHostAppData->GetInteractionInfo():nullptr ) + { + const std::unique_ptr< SvMemoryStream >& pMemStrm = pInteraction->getHyperlinkRecord(); + if (pMemStrm) + { + aPropOpt.AddOpt(ESCHER_Prop_pihlShape, false, 0, *pMemStrm); + } + aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080008 ); + } + + if ( rObj.GetType() == "drawing.Custom" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + ShapeFlag nMirrorFlags; + + OUString sCustomShapeType; + MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( rObj.GetShapeRef(), nMirrorFlags, sCustomShapeType, rObj.GetOOXML() ); + if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" ) + { + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) ) + { + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); // no fill + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); // no linestyle + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rObj.GetShapeRef()); + if ( pObj ) + { + tools::Rectangle aBound = pObj->GetCurrentBoundRect(); + Point aPosition( ImplMapPoint( aBound.TopLeft() ) ); + Size aSize( ImplMapSize( aBound.GetSize() ) ); + rObj.SetRect( tools::Rectangle( aPosition, aSize ) ); + rObj.SetAngle( 0 ); + bDontWriteText = true; + } + } + } + else + { + const Reference< XPropertySet > xPropSet = rObj.mXPropSet; + drawing::FillStyle eFS = drawing::FillStyle_NONE; + if(xPropSet.is()) + { + uno::Reference< XPropertySetInfo > xPropInfo = xPropSet->getPropertySetInfo(); + if ( xPropInfo.is() && xPropInfo->hasPropertyByName("FillStyle")) + xPropSet->getPropertyValue("FillStyle") >>= eFS; + } + + if (eFS == drawing::FillStyle_BITMAP && eShapeType == mso_sptMax) + { + // We can't map this custom shape to a DOC preset and it has a bitmap fill. + // Make sure that at least the bitmap fill is not lost. + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Bitmap", false, true, true, bOOxmlExport ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else + { + addShape(sal::static_int_cast< sal_uInt16 >(eShapeType), + nMirrorFlags | ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor); + aPropOpt.CreateCustomShapeProperties( eShapeType, rObj.GetShapeRef() ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + if ( rObj.ImplGetText() ) + { + if ( !aPropOpt.IsFontWork() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, mpEscherEx->QueryTextID( + rObj.GetShapeRef(), rObj.GetShapeId() ), true, false ); + } + } + } + } + else if ( rObj.GetType() == "drawing.Rectangle" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + sal_Int32 nRadius = rObj.ImplGetInt32PropertyValue("CornerRadius"); + if( nRadius ) + { + nRadius = ImplMapSize( Size( nRadius, 0 )).Width(); + addShape( ESCHER_ShpInst_RoundRectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + sal_Int32 nLength = rObj.GetRect().GetWidth(); + if ( nLength > rObj.GetRect().GetHeight() ) + nLength = rObj.GetRect().GetHeight(); + nLength >>= 1; + if ( nRadius >= nLength || nLength == 0 ) + nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius + else + nRadius = ( 0x2a30 * nRadius ) / nLength; + aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius ); + } + else + { + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + } + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + if( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ), false, false ); + } + else if ( rObj.GetType() == "drawing.Ellipse" ) + { + CircleKind eCircleKind = CircleKind_FULL; + PolyStyle ePolyKind = PolyStyle(); + if ( rObj.ImplGetPropertyValue( "CircleKind" ) ) + { + eCircleKind = *o3tl::doAccess(rObj.GetUsrAny()); + switch ( eCircleKind ) + { + case CircleKind_SECTION : + { + ePolyKind = PolyStyle::Pie; + } + break; + case CircleKind_ARC : + { + ePolyKind = PolyStyle::Arc; + } + break; + + case CircleKind_CUT : + { + ePolyKind = PolyStyle::Chord; + } + break; + + default: + eCircleKind = CircleKind_FULL; + } + } + if ( eCircleKind == CircleKind_FULL ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_Ellipse, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + } + else + { + sal_Int32 nStartAngle, nEndAngle; + if ( !rObj.ImplGetPropertyValue( "CircleStartAngle" ) ) + break; + nStartAngle = *o3tl::doAccess(rObj.GetUsrAny()); + if( !rObj.ImplGetPropertyValue( "CircleEndAngle" ) ) + break; + nEndAngle = *o3tl::doAccess(rObj.GetUsrAny()); + + Point aStart, aEnd, aCenter; + aStart.setX( static_cast( cos( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 ) ); + aStart.setY( - static_cast( sin( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 ) ); + aEnd.setX( static_cast( cos( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 ) ); + aEnd.setY( - static_cast( sin( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 ) ); + const tools::Rectangle& rRect = aRect100thmm; + aCenter.setX( rRect.Left() + ( rRect.GetWidth() / 2 ) ); + aCenter.setY( rRect.Top() + ( rRect.GetHeight() / 2 ) ); + aStart.AdjustX(aCenter.X() ); + aStart.AdjustY(aCenter.Y() ); + aEnd.AdjustX(aCenter.X() ); + aEnd.AdjustY(aCenter.Y() ); + tools::Polygon aPolygon( rRect, aStart, aEnd, ePolyKind ); + if( rObj.GetAngle() ) + { + aPolygon.Rotate( rRect.TopLeft(), Degree10(static_cast( rObj.GetAngle() / 10 )) ); + rObj.SetAngle( 0 ); + } + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + switch ( ePolyKind ) + { + case PolyStyle::Pie : + case PolyStyle::Chord : + { + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + } + break; + + case PolyStyle::Arc : + { + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + } + break; + } + rObj.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ), + ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) ); + } + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ), false, false ); + + } + else if ( rObj.GetType() == "drawing.Control" ) + { + const Reference< XPropertySet > xPropSet = rObj.mXPropSet; + const Reference xPropInfo = xPropSet.is() ? xPropSet->getPropertySetInfo() : Reference(); + // This code is expected to be called only for DOCX/XLSX formats. + if (xPropInfo.is() && bOOxmlExport) + { + bool bInline = false; + if (xPropInfo->hasPropertyByName("AnchorType")) + { + text::TextContentAnchorType eAnchorType; + xPropSet->getPropertyValue("AnchorType") >>= eAnchorType; + bInline = eAnchorType == text::TextContentAnchorType_AS_CHARACTER; + } + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + if(bInline) + { + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + } + else + { + addShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + } + } + else + break; + } + else if ( rObj.GetType() == "drawing.Connector" ) + { + sal_uInt16 nSpType; + ShapeFlag nSpFlags; + css::awt::Rectangle aNewRect; + if ( ! aPropOpt.CreateConnectorProperties( rObj.GetShapeRef(), + rSolverContainer, aNewRect, nSpType, nSpFlags ) ) + break; + rObj.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ), + ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) ); + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( nSpType, nSpFlags ); + } + else if ( rObj.GetType() == "drawing.Measure" ) + { + break; + } + else if ( rObj.GetType() == "drawing.Line" ) + { + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect ); + //i27942: Poly/Lines/Bezier do not support text. + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + ShapeFlag nFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor; + if( aNewRect.Height < 0 ) + nFlags |= ShapeFlag::FlipV; + if( aNewRect.Width < 0 ) + nFlags |= ShapeFlag::FlipH; + + addShape( ESCHER_ShpInst_Line, nFlags ); + aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.PolyPolygon" ) + { + if( rObj.ImplHasText() ) + { + nGrpShapeID = ImplEnterAdditionalTextGroup( rObj.GetShapeRef(), &rObj.GetRect() ); + bAdditionalText = true; + } + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.PolyLine" ) + { + //i27942: Poly/Lines/Bezier do not support text. + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.OpenBezier" ) + { + //i27942: Poly/Lines/Bezier do not support text. + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.ClosedBezier" ) + { + if ( rObj.ImplHasText() ) + { + nGrpShapeID = ImplEnterAdditionalTextGroup( rObj.GetShapeRef(), &rObj.GetRect() ); + bAdditionalText = true; + } + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.GraphicObject" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + + // a GraphicObject can also be a ClickMe element + if( rObj.IsEmptyPresObj() ) + { + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveMaster | ShapeFlag::HaveAnchor ); + sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ); + aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_hspMaster, 0 ); + } + else + { + if( rObj.ImplGetText() ) + { + /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we + have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat). + */ + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Graphic", true, true, false ) ) + { + aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone ); + aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 ); + aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 ); + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ), false, false ); + } + } + else + { + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Graphic", false, true, true, bOOxmlExport ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + } + } + else if ( rObj.GetType() == "drawing.Text" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + if( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ) ); + } + else if ( rObj.GetType() == "drawing.Page" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x40004 ); + aPropOpt.AddOpt( ESCHER_Prop_fFillOK, 0x100001 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110011 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90008 ); + aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x10001 ); + } + else if ( rObj.GetType() == "drawing.Frame" ) + { + break; + } + else if ( rObj.GetType() == "drawing.OLE2" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + if( rObj.IsEmptyPresObj() ) + { + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveMaster | ShapeFlag::HaveAnchor ); + sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ); + aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_hspMaster, 0 ); + } + else + { + //2do: could be made an option in HostAppData whether OLE object should be written or not + const bool bAppOLE = true; + addShape( ESCHER_ShpInst_PictureFrame, + ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | (bAppOLE ? ShapeFlag::OLEShape : ShapeFlag::NONE) ); + if ( aPropOpt.CreateOLEGraphicProperties( rObj.GetShapeRef() ) ) + { + if ( bAppOLE ) + { // snooped from Xcl hex dump, nobody knows the trouble I have seen + aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); + aPropOpt.AddOpt( ESCHER_Prop_pictureId, 0x00000001 ); + aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x08000041 ); + aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x08000041 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 ); + aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x08000040 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash,0x00080008 ); + aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 ); + } + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + } + } + else if( '3' == rObj.GetType()[8] && + 'D' == rObj.GetType()[9] ) // drawing.3D + { + // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject + if ( !rObj.ImplGetPropertyValue( "Bitmap" ) ) + break; + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Bitmap", false ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else if ( rObj.GetType() == "drawing.Caption" ) + { + rObj.SetAngle( 0 ); + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else if ( rObj.GetType() == "drawing.dontknow" ) + { + rObj.SetAngle( 0 ); + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else + { + break; + } + aPropOpt.CreateShadowProperties( rObj.mXPropSet ); + + if( SDRLAYER_NOTFOUND != mpEscherEx->GetHellLayerId() && + rObj.ImplGetPropertyValue( "LayerID" ) && + *o3tl::doAccess(rObj.GetUsrAny()) == mpEscherEx->GetHellLayerId().get() ) + { + aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x200020 ); + } + + { + tools::Rectangle aRect( rObj.GetRect() ); + aRect.Justify(); + rObj.SetRect( aRect ); + } + + if( rObj.GetAngle() ) + ImplFlipBoundingBox( rObj, aPropOpt ); + + aPropOpt.CreateShapeProperties( rObj.GetShapeRef() ); + const SdrObject* sdrObj = rObj.GetSdrObject(); + mpEscherEx->AddSdrObjectVMLObject(*sdrObj ); + mpEscherEx->Commit( aPropOpt, rObj.GetRect()); + if( mpEscherEx->GetGroupLevel() > 1 ) + mpEscherEx->AddChildAnchor( rObj.GetRect() ); + + if ( mpHostAppData ) + { //! with AdditionalText the App has to control whether these are written or not + mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() ); + mpHostAppData->WriteClientData( *mpEscherEx ); + if ( !bDontWriteText ) + mpHostAppData->WriteClientTextbox( *mpEscherEx ); + } + mpEscherEx->CloseContainer(); // ESCHER_SpContainer + + if( bAdditionalText ) + { + mpEscherEx->EndShape( nShapeType, nShapeID ); + ImplWriteAdditionalText( rObj ); + } + + } while ( false ); + + if ( bAdditionalText ) + mpEscherEx->EndShape( ESCHER_ShpInst_Min, nGrpShapeID ); + else + mpEscherEx->EndShape( nShapeType, nShapeID ); + return nShapeID; +} + +void ImplEESdrWriter::ImplWriteAdditionalText( ImplEESdrObject& rObj ) +{ + sal_uInt32 nShapeID = 0; + sal_uInt16 nShapeType = 0; + do + { + mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : nullptr ); + if ( mpHostAppData && mpHostAppData->DontWriteShape() ) + break; + + const css::awt::Size aSize100thmm( rObj.GetShapeRef()->getSize() ); + const css::awt::Point aPoint100thmm( rObj.GetShapeRef()->getPosition() ); + tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) ); + if ( !mpPicStrm ) + mpPicStrm = mpEscherEx->QueryPictureStream(); + EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm ); + rObj.SetAngle( rObj.ImplGetInt32PropertyValue( "RotateAngle" )); + sal_Int32 nAngle = rObj.GetAngle(); + if( rObj.GetType() == "drawing.Line" ) + { +//2do: this does not work right + double fDist = hypot( rObj.GetRect().GetWidth(), + rObj.GetRect().GetHeight() ); + rObj.SetRect( tools::Rectangle( Point(), + Point( static_cast( fDist ), -1 ) ) ); + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + mpEscherEx->AddShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ) ); + + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); + aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text + if ( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + if ( nAngle ) + ImplFlipBoundingBox( rObj, aPropOpt ); + } + else + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + nShapeID = mpEscherEx->GenerateShapeId(); + nShapeType = ESCHER_ShpInst_TextBox; + mpEscherEx->AddShape( nShapeType, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor, nShapeID ); + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ) ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); + + if( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + else + nAngle = ( 36000 - ( nAngle % 36000 ) ); + + nAngle *= 655; + nAngle += 0x8000; + nAngle &=~0xffff; // nAngle round to full degrees + aPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle ); + mpEscherEx->SetGroupSnapRect( mpEscherEx->GetGroupLevel(), + rObj.GetRect() ); + mpEscherEx->SetGroupLogicRect( mpEscherEx->GetGroupLevel(), + rObj.GetRect() ); + } + rObj.SetAngle( nAngle ); + aPropOpt.CreateShapeProperties( rObj.GetShapeRef() ); + const SdrObject* sdrObj = rObj.GetSdrObject(); + mpEscherEx->AddSdrObjectVMLObject(*sdrObj ); + mpEscherEx->Commit( aPropOpt, rObj.GetRect()); + + // write the childanchor + mpEscherEx->AddChildAnchor( rObj.GetRect() ); + +#if defined EES_WRITE_EPP + // ClientAnchor + mpEscherEx->AddClientAnchor( maRect ); + // ClientTextbox + mpEscherEx->OpenContainer( ESCHER_ClientTextbox ); + mpEscherEx->AddAtom( 4, EPP_TextHeaderAtom ); + *mpStrm << (sal_uInt32)EPP_TEXTTYPE_Other; // Text in a Shape + ImplWriteTextStyleAtom(); + mpEscherEx->CloseContainer(); // ESCHER_ClientTextBox +#else // !EES_WRITE_EPP + if ( mpHostAppData ) + { //! the App has to control whether these are written or not + mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() ); + mpHostAppData->WriteClientData( *mpEscherEx ); + mpHostAppData->WriteClientTextbox( *mpEscherEx ); + } +#endif // EES_WRITE_EPP + mpEscherEx->CloseContainer(); // ESCHER_SpContainer + } while ( false ); + mpEscherEx->LeaveGroup(); + mpEscherEx->EndShape( nShapeType, nShapeID ); +} + + +sal_uInt32 ImplEESdrWriter::ImplEnterAdditionalTextGroup( const Reference< XShape >& rShape, + const tools::Rectangle* pBoundRect ) +{ + mpHostAppData = mpEscherEx->EnterAdditionalTextGroup(); + sal_uInt32 nGrpId = mpEscherEx->EnterGroup( pBoundRect ); + mpHostAppData = mpEscherEx->StartShape( rShape, pBoundRect ); + return nGrpId; +} + + +void ImplEESdrWriter::ImplInitPageValues() +{ + mbIsTitlePossible = true; // With more than one title PowerPoint will fail. +} + +void ImplEESdrWriter::ImplWritePage( + EscherSolverContainer& rSolverContainer, bool ooxmlExport ) +{ + ImplInitPageValues(); + + const sal_uInt32 nShapes = mXShapes->getCount(); + for( sal_uInt32 n = 0; n < nShapes; ++n ) + { + ImplEESdrObject aObj( *o3tl::doAccess>( + mXShapes->getByIndex( n )) ); + if( aObj.IsValid() ) + { + ImplWriteShape( aObj, rSolverContainer, ooxmlExport ); + } + } +} + +ImplEESdrWriter::~ImplEESdrWriter() +{ + DBG_ASSERT( !mpSolverContainer, "ImplEESdrWriter::~ImplEESdrWriter: unwritten SolverContainer" ); + Reference xComp(mXDrawPage, UNO_QUERY); + if (xComp.is()) + xComp->dispose(); +} + + +bool ImplEESdrWriter::ImplInitPage( const SdrPage& rPage ) +{ + rtl::Reference pSvxDrawPage; + if ( mpSdrPage != &rPage || !mXDrawPage.is() ) + { + // eventually write SolverContainer of current page, deletes the Solver + ImplFlushSolverContainer(); + + mpSdrPage = nullptr; + Reference xOldDrawPage(mXDrawPage, UNO_QUERY); + if (xOldDrawPage.is()) + xOldDrawPage->dispose(); + mXDrawPage = pSvxDrawPage = new SvxFmDrawPage( const_cast(&rPage) ); + mXShapes = mXDrawPage; + if ( !mXShapes.is() ) + return false; + ImplInitPageValues(); + mpSdrPage = &rPage; + + mpSolverContainer.reset( new EscherSolverContainer ); + } + else + pSvxDrawPage = comphelper::getFromUnoTunnel(mXDrawPage); + + return pSvxDrawPage != nullptr; +} + +bool ImplEESdrWriter::ImplInitUnoShapes( const Reference< XShapes >& rxShapes ) +{ + // eventually write SolverContainer of current page, deletes the Solver + ImplFlushSolverContainer(); + + if( !rxShapes.is() ) + return false; + + mpSdrPage = nullptr; + mXDrawPage.clear(); + mXShapes = rxShapes; + + ImplInitPageValues(); + + mpSolverContainer.reset( new EscherSolverContainer ); + return true; +} + +void ImplEESdrWriter::ImplExitPage() +{ + // close all groups before the solver container is written + while( mpEscherEx->GetGroupLevel() ) + mpEscherEx->LeaveGroup(); + + ImplFlushSolverContainer(); + mpSdrPage = nullptr; // reset page for next init +} + + +void ImplEESdrWriter::ImplFlushSolverContainer() +{ + if ( mpSolverContainer ) + { + mpSolverContainer->WriteSolver( mpEscherEx->GetStream() ); + mpSolverContainer.reset(); + } +} + +void ImplEESdrWriter::ImplWriteCurrentPage(bool ooxmlExport) +{ + assert(mpSolverContainer && "ImplEESdrWriter::ImplWriteCurrentPage: no SolverContainer"); + ImplWritePage( *mpSolverContainer, ooxmlExport ); + ImplExitPage(); +} + +sal_uInt32 ImplEESdrWriter::ImplWriteTheShape( ImplEESdrObject& rObj , bool ooxmlExport ) +{ + assert(mpSolverContainer && "ImplEESdrWriter::ImplWriteShape: no SolverContainer"); + return ImplWriteShape( rObj, *mpSolverContainer, ooxmlExport ); +} + +void EscherEx::AddSdrPage( const SdrPage& rPage, bool ooxmlExport ) +{ + if ( mpImplEESdrWriter->ImplInitPage( rPage ) ) + mpImplEESdrWriter->ImplWriteCurrentPage(ooxmlExport); +} + +void EscherEx::AddUnoShapes( const Reference< XShapes >& rxShapes, bool ooxmlExport ) +{ + if ( mpImplEESdrWriter->ImplInitUnoShapes( rxShapes ) ) + mpImplEESdrWriter->ImplWriteCurrentPage(ooxmlExport); +} + +sal_uInt32 EscherEx::AddSdrObject( const SdrObject& rObj, bool ooxmlExport ) +{ + ImplEESdrObject aObj( *mpImplEESdrWriter, rObj, mbOOXML ); + if( aObj.IsValid() ) + return mpImplEESdrWriter->ImplWriteTheShape( aObj, ooxmlExport ); + return 0; +} + + +void EscherEx::EndSdrObjectPage() +{ + mpImplEESdrWriter->ImplExitPage(); +} + +EscherExHostAppData* EscherEx::StartShape( const Reference< XShape >& /* rShape */, const tools::Rectangle* /*pChildAnchor*/ ) +{ + return nullptr; +} + +void EscherEx::EndShape( sal_uInt16 /* nShapeType */, sal_uInt32 /* nShapeID */ ) +{ +} + +sal_uInt32 EscherEx::QueryTextID( const Reference< XShape >&, sal_uInt32 ) +{ + return 0; +} + +// add a dummy rectangle shape into the escher stream +sal_uInt32 EscherEx::AddDummyShape() +{ + OpenContainer( ESCHER_SpContainer ); + sal_uInt32 nShapeID = GenerateShapeId(); + AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor, nShapeID ); + CloseContainer(); + + return nShapeID; +} + +// static +const SdrObject* EscherEx::GetSdrObject( const Reference< XShape >& rShape ) +{ + const SdrObject* pRet = SdrObject::getSdrObjectFromXShape( rShape ); + DBG_ASSERT( pRet, "EscherEx::GetSdrObject: no SdrObj" ); + return pRet; +} + + +ImplEESdrObject::ImplEESdrObject( ImplEESdrWriter& rEx, + const SdrObject& rObj, bool bOOXML ) : + mnShapeId( 0 ), + mnTextSize( 0 ), + mnAngle( 0 ), + mbValid( false ), + mbPresObj( false ), + mbEmptyPresObj( false ), + mbOOXML(bOOXML) +{ + SdrPage* pPage = rObj.getSdrPageFromSdrObject(); + DBG_ASSERT( pPage, "ImplEESdrObject::ImplEESdrObject: no SdrPage" ); + if( pPage && rEx.ImplInitPage( *pPage ) ) + { + // why not declare a const parameter if the object will + // not be modified? + mXShape.set( const_cast(&rObj)->getUnoShape(), UNO_QUERY ); + Init(); + } +} + +ImplEESdrObject::ImplEESdrObject( const Reference< XShape >& rShape ) : + mXShape( rShape ), + mnShapeId( 0 ), + mnTextSize( 0 ), + mnAngle( 0 ), + mbValid( false ), + mbPresObj( false ), + mbEmptyPresObj( false ), + mbOOXML(false) +{ + Init(); +} + + +ImplEESdrObject::~ImplEESdrObject() +{ +} + +static basegfx::B2DRange getUnrotatedGroupBoundRange(const Reference< XShape >& rxShape) +{ + basegfx::B2DRange aRetval; + + try + { + if(rxShape.is()) + { + if(rxShape->getShapeType() == "com.sun.star.drawing.GroupShape") + { + // it's a group shape, iterate over children + const Reference< XIndexAccess > xXIndexAccess(rxShape, UNO_QUERY); + + if(xXIndexAccess.is()) + { + for(sal_uInt32 n(0), nCnt = xXIndexAccess->getCount(); n < nCnt; ++n) + { + const Reference< XShape > axShape(xXIndexAccess->getByIndex(n), UNO_QUERY); + + if(axShape.is()) + { + // we are calculating the bound for a group, correct rotation for sub-objects + // to get the unrotated bounds for the group + const basegfx::B2DRange aExtend(getUnrotatedGroupBoundRange(axShape)); + + aRetval.expand(aExtend); + } + } + } + } + else + { + // iT#s a xShape, get its transformation + const Reference< XPropertySet > xPropSet(rxShape, UNO_QUERY); + + if(xPropSet.is()) + { + const Any aAny = xPropSet->getPropertyValue("Transformation"); + + if(aAny.hasValue()) + { + HomogenMatrix3 aMatrix; + + if(aAny >>= aMatrix) + { + basegfx::B2DHomMatrix aHomogenMatrix; + + aHomogenMatrix.set(0, 0, aMatrix.Line1.Column1); + aHomogenMatrix.set(0, 1, aMatrix.Line1.Column2); + aHomogenMatrix.set(0, 2, aMatrix.Line1.Column3); + aHomogenMatrix.set(1, 0, aMatrix.Line2.Column1); + aHomogenMatrix.set(1, 1, aMatrix.Line2.Column2); + aHomogenMatrix.set(1, 2, aMatrix.Line2.Column3); + aHomogenMatrix.set(2, 0, aMatrix.Line3.Column1); + aHomogenMatrix.set(2, 1, aMatrix.Line3.Column2); + aHomogenMatrix.set(2, 2, aMatrix.Line3.Column3); + + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + // decompose transformation + aHomogenMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + + // check if rotation needs to be corrected + if(!basegfx::fTools::equalZero(fRotate)) + { + // to correct, keep in mind that ppt graphics are rotated around their center + const basegfx::B2DPoint aCenter(aHomogenMatrix * basegfx::B2DPoint(0.5, 0.5)); + + aHomogenMatrix.translate(-aCenter.getX(), -aCenter.getY()); + aHomogenMatrix.rotate(-fRotate); + aHomogenMatrix.translate(aCenter.getX(), aCenter.getY()); + } + + + // check if shear needs to be corrected (always correct shear, + // ppt does not know about it) + if(!basegfx::fTools::equalZero(fShearX)) + { + const basegfx::B2DPoint aMinimum(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0)); + + aHomogenMatrix.translate(-aMinimum.getX(), -aMinimum.getY()); + aHomogenMatrix.shearX(-fShearX); + aHomogenMatrix.translate(aMinimum.getX(), aMinimum.getY()); + } + + // create range. It's no longer rotated (or sheared), so use + // minimum and maximum values + aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0)); + aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(1.0, 1.0)); + } + } + } + } + } + } + catch(css::uno::Exception&) + { + } + + return aRetval; +} + +void ImplEESdrObject::Init() +{ + mXPropSet.set( mXShape, UNO_QUERY ); + if( !mXPropSet.is() ) + return; + + // detect name first to make below test (is group) work + mType = mXShape->getShapeType(); + (void)mType.startsWith( "com.sun.star.", &mType ); // strip "com.sun.star." + (void)mType.endsWith( "Shape", &mType ); // strip "Shape" + + if(GetType() == "drawing.Group") + { + // if it's a group, the unrotated range is needed for that group + const basegfx::B2DRange aUnrotatedRange(getUnrotatedGroupBoundRange(mXShape)); + const Point aNewP(basegfx::fround(aUnrotatedRange.getMinX()), basegfx::fround(aUnrotatedRange.getMinY())); + const Size aNewS(basegfx::fround(aUnrotatedRange.getWidth()), basegfx::fround(aUnrotatedRange.getHeight())); + + SetRect(ImplEESdrWriter::ImplMapPoint(aNewP), ImplEESdrWriter::ImplMapSize(aNewS)); + } + else + { + // if it's no group, use position and size directly, rotated/sheared or not + const Point aOldP(mXShape->getPosition().X, mXShape->getPosition().Y); + const Size aOldS(mXShape->getSize().Width, mXShape->getSize().Height); + + SetRect(ImplEESdrWriter::ImplMapPoint(aOldP), ImplEESdrWriter::ImplMapSize(aOldS)); + } + + if( ImplGetPropertyValue( "IsPresentationObject" ) ) + mbPresObj = ::cppu::any2bool( mAny ); + + if( mbPresObj && ImplGetPropertyValue( "IsEmptyPresentationObject" ) ) + mbEmptyPresObj = ::cppu::any2bool( mAny ); + + mbValid = true; +} + +bool ImplEESdrObject::ImplGetPropertyValue( const OUString& rString ) +{ + bool bRetValue = false; + if( mbValid ) + { + try + { + mAny = mXPropSet->getPropertyValue( rString ); + if( mAny.hasValue() ) + bRetValue = true; + } + catch( const css::uno::Exception& ) + { + bRetValue = false; + } + } + return bRetValue; +} + +void ImplEESdrObject::SetRect( const Point& rPos, const Size& rSz ) +{ + maRect = tools::Rectangle( rPos, rSz ); +} + +const SdrObject* ImplEESdrObject::GetSdrObject() const +{ + return EscherEx::GetSdrObject( mXShape ); +} + +// loads and converts text from shape, result is saved in mnTextSize +sal_uInt32 ImplEESdrObject::ImplGetText() +{ + Reference< XText > xXText( mXShape, UNO_QUERY ); + mnTextSize = 0; + if (xXText.is()) + { + try + { + mnTextSize = xXText->getString().getLength(); + } + catch (const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("filter.ms", "ImplGetText"); + } + } + return mnTextSize; +} + +bool ImplEESdrObject::ImplHasText() const +{ + Reference< XText > xXText( mXShape, UNO_QUERY ); + return xXText.is() && !xXText->getString().isEmpty(); +} + + +void ImplEESdrObject::SetOOXML(bool bOOXML) +{ + mbOOXML = bOOXML; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/eschesdo.hxx b/filter/source/msfilter/eschesdo.hxx new file mode 100644 index 000000000..cf46f49b6 --- /dev/null +++ b/filter/source/msfilter/eschesdo.hxx @@ -0,0 +1,138 @@ +/* -*- 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 . + */ +#pragma once +#include +#include + + +// fractions of Draw PPTWriter etc. + +class ImplEESdrWriter; +class SdrObject; +class SdrPage; + +class ImplEESdrObject +{ + css::uno::Reference< css::drawing::XShape > mXShape; + css::uno::Any mAny; + tools::Rectangle maRect; + OUString mType; + sal_uInt32 mnShapeId; + sal_uInt32 mnTextSize; + sal_Int32 mnAngle; + bool mbValid : 1; + bool mbPresObj : 1; + bool mbEmptyPresObj : 1; + bool mbOOXML; + + void Init(); +public: + css::uno::Reference< css::beans::XPropertySet > mXPropSet; + + ImplEESdrObject( ImplEESdrWriter& rEx, const SdrObject& rObj, bool bOOXML ); + ImplEESdrObject( const css::uno::Reference< css::drawing::XShape >& rShape ); + ~ImplEESdrObject(); + + bool ImplGetPropertyValue( const OUString& rString ); + + sal_Int32 ImplGetInt32PropertyValue( const OUString& rStr ) + { return ImplGetPropertyValue( rStr ) ? *o3tl::doAccess(mAny) : 0; } + + const css::uno::Reference< css::drawing::XShape >& GetShapeRef() const { return mXShape; } + const css::uno::Any& GetUsrAny() const { return mAny; } + const OUString& GetType() const { return mType; } + void SetType( const OUString& rS ) { mType = rS; } + + const tools::Rectangle& GetRect() const { return maRect; } + void SetRect( const Point& rPos, const Size& rSz ); + void SetRect( const tools::Rectangle& rRect ) + { maRect = rRect; } + + sal_Int32 GetAngle() const { return mnAngle; } + void SetAngle( sal_Int32 nVal ) { mnAngle = nVal; } + + bool IsValid() const { return mbValid; } + + bool IsEmptyPresObj() const { return mbEmptyPresObj; } + sal_uInt32 GetShapeId() const { return mnShapeId; } + void SetShapeId( sal_uInt32 nVal ) { mnShapeId = nVal; } + + const SdrObject* GetSdrObject() const; + + sal_uInt32 ImplGetText(); + bool ImplHasText() const; + bool GetOOXML() const { return mbOOXML;} + void SetOOXML(bool bOOXML); +}; + + +// fractions of the Draw PPTWriter + +class EscherEx; +namespace com::sun::star { + namespace drawing { + class XDrawPage; + class XShape; + } + namespace task { + class XStatusIndicator; + } +} +class EscherExHostAppData; + +class ImplEESdrWriter +{ + EscherEx* mpEscherEx; + css::uno::Reference< css::drawing::XDrawPage > mXDrawPage; + css::uno::Reference< css::drawing::XShapes > mXShapes; + SvStream* mpPicStrm; + // own extensions + EscherExHostAppData* mpHostAppData; + bool mbIsTitlePossible; + const SdrPage* mpSdrPage; + std::unique_ptr mpSolverContainer; + + void ImplInitPageValues(); + void ImplWritePage( EscherSolverContainer& rSolver, bool ooxmlExport ); + sal_uInt32 ImplWriteShape( ImplEESdrObject& rObj, + EscherSolverContainer& rSolver, + const bool bOOxmlExport = false ); // returns ShapeID + static void ImplFlipBoundingBox( ImplEESdrObject& rObj, EscherPropertyContainer& rPropOpt ); + void ImplWriteAdditionalText( + ImplEESdrObject& rObj ); + sal_uInt32 ImplEnterAdditionalTextGroup( + const css::uno::Reference< css::drawing::XShape >& rShape, + const tools::Rectangle* pBoundRect ); + void ImplFlushSolverContainer(); + +public: + explicit ImplEESdrWriter( EscherEx& rEx ); + ~ImplEESdrWriter(); + static Point ImplMapPoint( const Point& rPoint ); + static Size ImplMapSize( const Size& rSize ); + EscherExHostAppData* ImplGetHostData() { return mpHostAppData; } + bool ImplInitPage( const SdrPage& rPage ); + bool ImplInitUnoShapes( const css::uno::Reference< css::drawing::XShapes >& rxShapes ); + void ImplWriteCurrentPage( bool ooxmlExport ); + sal_uInt32 ImplWriteTheShape( ImplEESdrObject& rObj, bool ooxmlExport ); + void ImplExitPage(); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/mscodec.cxx b/filter/source/msfilter/mscodec.cxx new file mode 100644 index 000000000..376a45320 --- /dev/null +++ b/filter/source/msfilter/mscodec.cxx @@ -0,0 +1,642 @@ +/* -*- 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG_MSO_ENCRYPTION_STD97 0 + +#if DEBUG_MSO_ENCRYPTION_STD97 +#include +#endif + +using namespace ::com::sun::star; + +namespace msfilter { + + +namespace { + +/** Rotates rnValue left by nBits bits. */ +template< typename Type > +void lclRotateLeft( Type& rnValue, int nBits ) +{ + OSL_ASSERT( + nBits >= 0 && + sal::static_int_cast< unsigned int >(nBits) < sizeof( Type ) * 8 ); + rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) ); +} + +/** Rotates the lower nWidth bits of rnValue left by nBits bits. */ +template< typename Type > +void lclRotateLeft( Type& rnValue, sal_uInt8 nBits, sal_uInt8 nWidth ) +{ + OSL_ASSERT( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8) ); + Type nMask = static_cast< Type >( (1UL << nWidth) - 1 ); + rnValue = static_cast< Type >( + ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask ); +} + +std::size_t lclGetLen( const sal_uInt8* pnPassData, std::size_t nBufferSize ) +{ + std::size_t nLen = 0; + while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen; + return nLen; +} + +sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, std::size_t nBufferSize ) +{ + std::size_t nLen = lclGetLen( pnPassData, nBufferSize ); + if( !nLen ) return 0; + + sal_uInt16 nKey = 0; + sal_uInt16 nKeyBase = 0x8000; + sal_uInt16 nKeyEnd = 0xFFFF; + const sal_uInt8* pnChar = pnPassData + nLen - 1; + for( std::size_t nIndex = 0; nIndex < nLen; ++nIndex, --pnChar ) + { + sal_uInt8 cChar = *pnChar & 0x7F; + for( sal_uInt8 nBit = 0; nBit < 8; ++nBit ) + { + lclRotateLeft( nKeyBase, 1 ); + if( nKeyBase & 1 ) nKeyBase ^= 0x1020; + if( cChar & 1 ) nKey ^= nKeyBase; + cChar >>= 1; + lclRotateLeft( nKeyEnd, 1 ); + if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020; + } + } + return nKey ^ nKeyEnd; +} + +sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, std::size_t nBufferSize ) +{ + std::size_t nLen = lclGetLen( pnPassData, nBufferSize ); + + sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen ); + if( nLen ) + nHash ^= 0xCE4B; + + const sal_uInt8* pnChar = pnPassData; + for( std::size_t nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar ) + { + sal_uInt16 cChar = *pnChar; + sal_uInt8 nRot = static_cast< sal_uInt8 >( (nIndex + 1) % 15 ); + lclRotateLeft( cChar, nRot, 15 ); + nHash ^= cChar; + } + return nHash; +} + + +} // namespace + + +MSCodec_Xor95::MSCodec_Xor95(int nRotateDistance) : + mnOffset( 0 ), + mnKey( 0 ), + mnHash( 0 ), + mnRotateDistance( nRotateDistance ) +{ +} + +MSCodec_Xor95::~MSCodec_Xor95() +{ + memset( mpnKey, 0, sizeof( mpnKey ) ); + mnKey = mnHash = 0; +} + +void MSCodec_Xor95::InitKey( const sal_uInt8 pnPassData[ 16 ] ) +{ + mnKey = lclGetKey( pnPassData, 16 ); + mnHash = lclGetHash( pnPassData, 16 ); + + memcpy( mpnKey, pnPassData, 16 ); + + static const sal_uInt8 spnFillChars[] = + { + 0xBB, 0xFF, 0xFF, 0xBA, + 0xFF, 0xFF, 0xB9, 0x80, + 0x00, 0xBE, 0x0F, 0x00, + 0xBF, 0x0F, 0x00, 0x00 + }; + + std::size_t nLen = lclGetLen( pnPassData, 16 ); + const sal_uInt8* pnFillChar = spnFillChars; + for (std::size_t nIndex = nLen; nIndex < sizeof(mpnKey); ++nIndex, ++pnFillChar) + mpnKey[ nIndex ] = *pnFillChar; + + SVBT16 pnOrigKey; + ShortToSVBT16( mnKey, pnOrigKey ); + sal_uInt8* pnKeyChar = mpnKey; + for (std::size_t nIndex = 0; nIndex < sizeof(mpnKey); ++nIndex, ++pnKeyChar) + { + *pnKeyChar ^= pnOrigKey[ nIndex & 0x01 ]; + lclRotateLeft( *pnKeyChar, mnRotateDistance ); + } +} + +bool MSCodec_Xor95::InitCodec( const uno::Sequence< beans::NamedValue >& aData ) +{ + bool bResult = false; + + ::comphelper::SequenceAsHashMap aHashData( aData ); + uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("XOR95EncryptionKey", uno::Sequence< sal_Int8 >() ); + + if ( aKey.getLength() == 16 ) + { + memcpy( mpnKey, aKey.getConstArray(), 16 ); + bResult = true; + + mnKey = static_cast(aHashData.getUnpackedValueOrDefault("XOR95BaseKey", sal_Int16(0) )); + mnHash = static_cast(aHashData.getUnpackedValueOrDefault("XOR95PasswordHash", sal_Int16(0) )); + } + else + OSL_FAIL( "Unexpected key size!" ); + + return bResult; +} + +uno::Sequence< beans::NamedValue > MSCodec_Xor95::GetEncryptionData() +{ + ::comphelper::SequenceAsHashMap aHashData; + // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence + aHashData[ OUString( "XOR95EncryptionKey" ) ] <<= uno::Sequence( reinterpret_cast(mpnKey), 16 ); + aHashData[ OUString( "XOR95BaseKey" ) ] <<= static_cast(mnKey); + aHashData[ OUString( "XOR95PasswordHash" ) ] <<= static_cast(mnHash); + + return aHashData.getAsConstNamedValueList(); +} + +bool MSCodec_Xor95::VerifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const +{ + return (nKey == mnKey) && (nHash == mnHash); +} + +void MSCodec_Xor95::InitCipher() +{ + mnOffset = 0; +} + +void MSCodec_XorXLS95::Decode( sal_uInt8* pnData, std::size_t nBytes ) +{ + const sal_uInt8* pnCurrKey = mpnKey + mnOffset; + const sal_uInt8* pnKeyLast = mpnKey + 0x0F; + + for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData ) + { + lclRotateLeft( *pnData, 3 ); + *pnData ^= *pnCurrKey; + if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey; + } + + // update mnOffset + Skip( nBytes ); +} + +void MSCodec_XorWord95::Decode( sal_uInt8* pnData, std::size_t nBytes ) +{ + const sal_uInt8* pnCurrKey = mpnKey + mnOffset; + const sal_uInt8* pnKeyLast = mpnKey + 0x0F; + + for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData ) + { + const sal_uInt8 cChar = *pnData ^ *pnCurrKey; + if (*pnData && cChar) + *pnData = cChar; + + if( pnCurrKey < pnKeyLast ) + ++pnCurrKey; + else + pnCurrKey = mpnKey; + } + + // update mnOffset + Skip( nBytes ); +} + + +void MSCodec_Xor95::Skip( std::size_t nBytes ) +{ + mnOffset = (mnOffset + nBytes) & 0x0F; +} + +MSCodec97::MSCodec97(size_t nHashLen, OUString aEncKeyName) + : m_sEncKeyName(std::move(aEncKeyName)) + , m_nHashLen(nHashLen) + , m_hCipher(rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream)) + , m_aDocId(16, 0) + , m_aDigestValue(nHashLen, 0) +{ + assert(m_hCipher != nullptr); +} + +MSCodec_Std97::MSCodec_Std97() + : MSCodec97(RTL_DIGEST_LENGTH_MD5, "STD97EncryptionKey") +{ + m_hDigest = rtl_digest_create(rtl_Digest_AlgorithmMD5); + assert(m_hDigest != nullptr); +} + +MSCodec_CryptoAPI::MSCodec_CryptoAPI() + : MSCodec97(RTL_DIGEST_LENGTH_SHA1, "CryptoAPIEncryptionKey") +{ +} + +MSCodec97::~MSCodec97() +{ + memset(m_aDigestValue.data(), 0, m_aDigestValue.size()); + memset(m_aDocId.data(), 0, m_aDocId.size()); + rtl_cipher_destroy(m_hCipher); +} + +MSCodec_Std97::~MSCodec_Std97() +{ + rtl_digest_destroy(m_hDigest); +} + +#if DEBUG_MSO_ENCRYPTION_STD97 +static void lcl_PrintDigest(const sal_uInt8* pDigest, const char* msg) +{ + printf("digest: (%s)\n", msg); + for (int i = 0; i < 16; ++i) + printf("%2.2x ", pDigest[i]); + printf("\n"); +} +#else +static void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*msg*/) +{ +} +#endif + +bool MSCodec97::InitCodec( const uno::Sequence< beans::NamedValue >& aData ) +{ +#if DEBUG_MSO_ENCRYPTION_STD97 + fprintf(stdout, "MSCodec_Std97::InitCodec: --begin\n");fflush(stdout); +#endif + bool bResult = false; + + ::comphelper::SequenceAsHashMap aHashData( aData ); + uno::Sequence aKey = aHashData.getUnpackedValueOrDefault(m_sEncKeyName, uno::Sequence()); + const size_t nKeyLen = aKey.getLength(); + if (nKeyLen == m_nHashLen) + { + assert(m_aDigestValue.size() == m_nHashLen); + memcpy(m_aDigestValue.data(), aKey.getConstArray(), m_nHashLen); + uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault("STD97UniqueID", uno::Sequence< sal_Int8 >() ); + if ( aUniqueID.getLength() == 16 ) + { + assert(m_aDocId.size() == static_cast(aUniqueID.getLength())); + memcpy(m_aDocId.data(), aUniqueID.getConstArray(), m_aDocId.size()); + bResult = true; + lcl_PrintDigest(m_aDigestValue.data(), "digest value"); + lcl_PrintDigest(m_aDocId.data(), "DocId value"); + } + else + OSL_FAIL( "Unexpected document ID!" ); + } + else + OSL_FAIL( "Unexpected key size!" ); + + return bResult; +} + +uno::Sequence< beans::NamedValue > MSCodec97::GetEncryptionData() +{ + ::comphelper::SequenceAsHashMap aHashData; + assert(m_aDigestValue.size() == m_nHashLen); + aHashData[m_sEncKeyName] <<= uno::Sequence(reinterpret_cast(m_aDigestValue.data()), m_nHashLen); + aHashData[ OUString( "STD97UniqueID" ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast(m_aDocId.data()), m_aDocId.size() ); + + return aHashData.getAsConstNamedValueList(); +} + +void MSCodec_Std97::InitKey ( + const sal_uInt16 pPassData[16], + const sal_uInt8 pDocId[16]) +{ +#if DEBUG_MSO_ENCRYPTION_STD97 + fprintf(stdout, "MSCodec_Std97::InitKey: --begin\n");fflush(stdout); +#endif + uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key(pPassData, pDocId); + // Fill raw digest of above updates into DigestValue. + + const size_t nKeyLen = aKey.getLength(); + if (m_aDigestValue.size() == nKeyLen) + memcpy(m_aDigestValue.data(), aKey.getConstArray(), m_aDigestValue.size()); + else + memset(m_aDigestValue.data(), 0, m_aDigestValue.size()); + + lcl_PrintDigest(m_aDigestValue.data(), "digest value"); + + memcpy (m_aDocId.data(), pDocId, 16); + + lcl_PrintDigest(m_aDocId.data(), "DocId value"); +} + +void MSCodec_CryptoAPI::InitKey ( + const sal_uInt16 pPassData[16], + const sal_uInt8 pDocId[16]) +{ + sal_uInt32 const saltSize = 16; + + // Prepare initial data -> salt + password (in 16-bit chars) + std::vector initialData(pDocId, pDocId + saltSize); + + // Fill PassData into KeyData. + for (sal_Int32 nInd = 0; nInd < 16 && pPassData[nInd]; ++nInd) + { + initialData.push_back(sal::static_int_cast((pPassData[nInd] >> 0) & 0xff)); + initialData.push_back(sal::static_int_cast((pPassData[nInd] >> 8) & 0xff)); + } + + // calculate SHA1 hash of initialData + std::vector const sha1(::comphelper::Hash::calculateHash( + initialData.data(), initialData.size(), + ::comphelper::HashType::SHA1)); + m_aDigestValue = sha1; + + lcl_PrintDigest(m_aDigestValue.data(), "digest value"); + + memcpy(m_aDocId.data(), pDocId, 16); + + lcl_PrintDigest(m_aDocId.data(), "DocId value"); + + //generate the old format key while we have the required data + m_aStd97Key = ::comphelper::DocPasswordHelper::GenerateStd97Key(pPassData, pDocId); +} + +bool MSCodec97::VerifyKey(const sal_uInt8* pSaltData, const sal_uInt8* pSaltDigest) +{ + // both the salt data and salt digest (hash) come from the document being imported. + +#if DEBUG_MSO_ENCRYPTION_STD97 + fprintf(stdout, "MSCodec97::VerifyKey: \n"); + lcl_PrintDigest(pSaltData, "salt data"); + lcl_PrintDigest(pSaltDigest, "salt hash"); +#endif + bool result = false; + + if (InitCipher(0)) + { + std::vector aDigest(m_nHashLen); + GetDigestFromSalt(pSaltData, aDigest.data()); + + std::vector aBuffer(m_nHashLen); + // Decode original SaltDigest into Buffer. + rtl_cipher_decode(m_hCipher, pSaltDigest, m_nHashLen, aBuffer.data(), m_nHashLen); + + // Compare Buffer with computed Digest. + result = (memcmp(aBuffer.data(), aDigest.data(), m_nHashLen) == 0); + + // Erase Buffer and Digest arrays. + rtl_secureZeroMemory(aBuffer.data(), m_nHashLen); + rtl_secureZeroMemory(aDigest.data(), m_nHashLen); + } + + return result; +} + +void MSCodec_CryptoAPI::GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) +{ + std::vector verifier(16); + rtl_cipher_decode(m_hCipher, + pSaltData, 16, verifier.data(), verifier.size()); + + std::vector const sha1(::comphelper::Hash::calculateHash( + verifier.data(), verifier.size(), ::comphelper::HashType::SHA1)); + ::std::copy(sha1.begin(), sha1.end(), pDigest); +} + +bool MSCodec_Std97::InitCipher(sal_uInt32 nCounter) +{ + sal_uInt8 pKeyData[64] = {}; // 512-bit message block + + // Fill 40 bit of DigestValue into [0..4]. + memcpy (pKeyData, m_aDigestValue.data(), 5); + + // Fill counter into [5..8]. + pKeyData[ 5] = sal_uInt8((nCounter >> 0) & 0xff); + pKeyData[ 6] = sal_uInt8((nCounter >> 8) & 0xff); + pKeyData[ 7] = sal_uInt8((nCounter >> 16) & 0xff); + pKeyData[ 8] = sal_uInt8((nCounter >> 24) & 0xff); + + pKeyData[ 9] = 0x80; + pKeyData[56] = 0x48; + + // Fill raw digest of KeyData into KeyData. + (void)rtl_digest_updateMD5 ( + m_hDigest, pKeyData, sizeof(pKeyData)); + (void)rtl_digest_rawMD5 ( + m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5); + + // Initialize Cipher with KeyData (for decoding). + rtlCipherError result = rtl_cipher_init ( + m_hCipher, rtl_Cipher_DirectionBoth, + pKeyData, RTL_DIGEST_LENGTH_MD5, nullptr, 0); + + // Erase KeyData array and leave. + rtl_secureZeroMemory (pKeyData, sizeof(pKeyData)); + + return (result == rtl_Cipher_E_None); +} + +bool MSCodec_CryptoAPI::InitCipher(sal_uInt32 nCounter) +{ + // data = hash + iterator (4bytes) + std::vector aKeyData(m_aDigestValue); + aKeyData.push_back(sal_uInt8((nCounter >> 0) & 0xff)); + aKeyData.push_back(sal_uInt8((nCounter >> 8) & 0xff)); + aKeyData.push_back(sal_uInt8((nCounter >> 16) & 0xff)); + aKeyData.push_back(sal_uInt8((nCounter >> 24) & 0xff)); + + std::vector const hash(::comphelper::Hash::calculateHash( + aKeyData.data(), aKeyData.size(), ::comphelper::HashType::SHA1)); + + rtlCipherError result = + rtl_cipher_init(m_hCipher, rtl_Cipher_DirectionDecode, + hash.data(), ENCRYPT_KEY_SIZE_AES_128/8, nullptr, 0); + + return (result == rtl_Cipher_E_None); +} + +uno::Sequence MSCodec_CryptoAPI::GetEncryptionData() +{ + ::comphelper::SequenceAsHashMap aHashData(MSCodec97::GetEncryptionData()); + //add in the old encryption key as well as our new key so saving using the + //old crypto scheme can be done without reprompt for the password + aHashData[OUString("STD97EncryptionKey")] <<= m_aStd97Key; + return aHashData.getAsConstNamedValueList(); +} + +void MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] ) +{ +#if DEBUG_MSO_ENCRYPTION_STD97 + lcl_PrintDigest(nSaltData, "salt data"); +#endif + if (InitCipher(0)) + { + sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5]; + GetDigestFromSalt(nSaltData, pDigest); + + rtl_cipher_decode ( + m_hCipher, pDigest, 16, pDigest, sizeof(pDigest)); + + memcpy(nSaltDigest, pDigest, 16); + } +} + +bool MSCodec97::Encode ( + const void *pData, std::size_t nDatLen, + sal_uInt8 *pBuffer, std::size_t nBufLen) +{ + rtlCipherError result = rtl_cipher_encode( + m_hCipher, pData, nDatLen, pBuffer, nBufLen); + + return (result == rtl_Cipher_E_None); +} + +bool MSCodec97::Decode ( + const void *pData, std::size_t nDatLen, + sal_uInt8 *pBuffer, std::size_t nBufLen) +{ + rtlCipherError result = rtl_cipher_decode( + m_hCipher, pData, nDatLen, pBuffer, nBufLen); + + return (result == rtl_Cipher_E_None); +} + +bool MSCodec97::Skip(std::size_t nDatLen) +{ + sal_uInt8 pnDummy[ 1024 ]; + std::size_t nDatLeft = nDatLen; + bool bResult = true; + + while (bResult && nDatLeft) + { + std::size_t nBlockLen = ::std::min< std::size_t >( nDatLeft, sizeof(pnDummy) ); + bResult = Decode( pnDummy, nBlockLen, pnDummy, nBlockLen ); + nDatLeft -= nBlockLen; + } + + return bResult; +} + +void MSCodec_Std97::GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) +{ + sal_uInt8 pBuffer[64]; + sal_uInt8 pDigestLocal[16]; + + // Decode SaltData into Buffer. + rtl_cipher_decode ( + m_hCipher, pSaltData, 16, pBuffer, sizeof(pBuffer)); + + // set the 129th bit to make the buffer 128-bit in length. + pBuffer[16] = 0x80; + + // erase the rest of the buffer with zeros. + memset (pBuffer + 17, 0, sizeof(pBuffer) - 17); + + // set the 441st bit. + pBuffer[56] = 0x80; + + // Fill raw digest of Buffer into Digest. + rtl_digest_updateMD5 ( + m_hDigest, pBuffer, sizeof(pBuffer)); + rtl_digest_rawMD5 ( + m_hDigest, pDigestLocal, sizeof(pDigestLocal)); + + memcpy(pDigest, pDigestLocal, 16); +} + +void MSCodec_Std97::GetEncryptKey ( + const sal_uInt8 pSalt[16], + sal_uInt8 pSaltData[16], + sal_uInt8 pSaltDigest[16]) +{ + if (!InitCipher(0)) + return; + + sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5]; + sal_uInt8 pBuffer[64]; + + rtl_cipher_encode ( + m_hCipher, pSalt, 16, pSaltData, sizeof(pBuffer)); + + memcpy( pBuffer, pSalt, 16 ); + + pBuffer[16] = 0x80; + memset (pBuffer + 17, 0, sizeof(pBuffer) - 17); + pBuffer[56] = 0x80; + + rtl_digest_updateMD5 ( + m_hDigest, pBuffer, sizeof(pBuffer)); + rtl_digest_rawMD5 ( + m_hDigest, pDigest, sizeof(pDigest)); + + rtl_cipher_encode ( + m_hCipher, pDigest, 16, pSaltDigest, 16); + + rtl_secureZeroMemory (pBuffer, sizeof(pBuffer)); + rtl_secureZeroMemory (pDigest, sizeof(pDigest)); +} + +void MSCodec97::GetDocId( sal_uInt8 pDocId[16] ) +{ + assert(m_aDocId.size() == 16); + memcpy(pDocId, m_aDocId.data(), 16); +} + +EncryptionStandardHeader::EncryptionStandardHeader() +{ + flags = 0; + sizeExtra = 0; + algId = 0; + algIdHash = 0; + keyBits = 0; + providedType = 0; + reserved1 = 0; + reserved2 = 0; +} + +EncryptionVerifierAES::EncryptionVerifierAES() + : saltSize(SALT_LENGTH) + , encryptedVerifierHashSize(comphelper::SHA1_HASH_LENGTH) +{ +} + +EncryptionVerifierRC4::EncryptionVerifierRC4() + : saltSize(SALT_LENGTH) + , encryptedVerifierHashSize(comphelper::SHA1_HASH_LENGTH) +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/msdffimp.cxx b/filter/source/msfilter/msdffimp.cxx new file mode 100644 index 000000000..66bac102a --- /dev/null +++ b/filter/source/msfilter/msdffimp.cxx @@ -0,0 +1,7610 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "viscache.hxx" + +// SvxItem-Mapping. Is needed to successfully include the SvxItem-Header +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star ; +using namespace ::com::sun::star::drawing; +using namespace uno ; +using namespace beans ; +using namespace drawing ; +using namespace container ; + +// static counter for OLE-Objects +static sal_uInt32 nMSOleObjCntr = 0; +constexpr OUStringLiteral MSO_OLE_Obj = u"MSO_OLE_Obj"; + +namespace { +/* Office File Formats - 2.2.23 */ +enum class OfficeArtBlipRecInstance : sal_uInt32 +{ + EMF = 0x3D4, // defined in section 2.2.24. + WMF = 0x216, // defined in section 2.2.25. + PICT = 0x542, // as defined in section 2.2.26. + JPEG_RGB = 0x46A, // defined in section 2.2.27. + JPEG_CMYK = 0x6E2, // defined in section 2.2.27. + PNG = 0x6E0, // defined in section 2.2.28. + DIB = 0x7A8, // defined in section 2.2.29. + TIFF = 0x6E4 // defined in section 2.2.30. +}; + +struct SvxMSDffBLIPInfo +{ + sal_uLong nFilePos; ///< offset of the BLIP in data stream + explicit SvxMSDffBLIPInfo(sal_uLong nFPos) + : nFilePos(nFPos) + { + } +}; + +} + +/// the following will be sorted by the order of their appearance: +struct SvxMSDffBLIPInfos : public std::vector {}; + +/************************************************************************/ +void Impl_OlePres::Write( SvStream & rStm ) +{ + WriteClipboardFormat( rStm, SotClipboardFormatId::GDIMETAFILE ); + rStm.WriteInt32( 4 ); // a TargetDevice that's always empty + rStm.WriteUInt32( nAspect ); + rStm.WriteInt32( -1 ); //L-Index always -1 + rStm.WriteInt32( nAdvFlags ); + rStm.WriteInt32( 0 ); //Compression + rStm.WriteInt32( aSize.Width() ); + rStm.WriteInt32( aSize.Height() ); + sal_uInt64 nPos = rStm.Tell(); + rStm.WriteInt32( 0 ); + + if( nFormat == SotClipboardFormatId::GDIMETAFILE && pMtf ) + { + // Always to 1/100 mm, until Mtf-Solution found + // Assumption (no scaling, no origin translation) + DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleX() == Fraction( 1, 1 ), + "x-scale in the Mtf is wrong" ); + DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleY() == Fraction( 1, 1 ), + "y-scale in the Mtf is wrong" ); + DBG_ASSERT( pMtf->GetPrefMapMode().GetOrigin() == Point(), + "origin-shift in the Mtf is wrong" ); + MapUnit nMU = pMtf->GetPrefMapMode().GetMapUnit(); + if( MapUnit::Map100thMM != nMU ) + { + Size aPrefS( pMtf->GetPrefSize() ); + Size aS = OutputDevice::LogicToLogic(aPrefS, MapMode(nMU), MapMode(MapUnit::Map100thMM)); + + pMtf->Scale( Fraction( aS.Width(), aPrefS.Width() ), + Fraction( aS.Height(), aPrefS.Height() ) ); + pMtf->SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + pMtf->SetPrefSize( aS ); + } + WriteWindowMetafileBits( rStm, *pMtf ); + } + else + { + OSL_FAIL( "unknown format" ); + } + sal_uInt64 nEndPos = rStm.Tell(); + rStm.Seek( nPos ); + rStm.WriteUInt32( nEndPos - nPos - 4 ); + rStm.Seek( nEndPos ); +} + +DffPropertyReader::DffPropertyReader( const SvxMSDffManager& rMan ) + : rManager(rMan) + , mnFix16Angle(0) + , mbRotateGranientFillWithAngle(false) +{ + InitializePropSet( DFF_msofbtOPT ); +} + +void DffPropertyReader::SetDefaultPropSet( SvStream& rStCtrl, sal_uInt32 nOffsDgg ) const +{ + const_cast(this)->pDefaultPropSet.reset(); + sal_uInt64 nOldPos = rStCtrl.Tell(); + bool bOk = checkSeek(rStCtrl, nOffsDgg); + DffRecordHeader aRecHd; + if (bOk) + bOk = ReadDffRecordHeader( rStCtrl, aRecHd ); + if (bOk && aRecHd.nRecType == DFF_msofbtDggContainer) + { + if ( SvxMSDffManager::SeekToRec( rStCtrl, DFF_msofbtOPT, aRecHd.GetRecEndFilePos() ) ) + { + const_cast(this)->pDefaultPropSet.reset( new DffPropSet ); + ReadDffPropSet( rStCtrl, *pDefaultPropSet ); + } + } + rStCtrl.Seek( nOldPos ); +} + +#ifdef DBG_CUSTOMSHAPE +void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData, sal_uInt32 nShapeId ) const +#else +void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData ) const +#endif +{ + sal_uInt64 nFilePos = rIn.Tell(); + ReadDffPropSet( rIn, const_cast(*this) ); + + if ( IsProperty( DFF_Prop_hspMaster ) ) + { + if ( rManager.SeekToShape( rIn, pClientData, GetPropertyValue( DFF_Prop_hspMaster, 0 ) ) ) + { + DffRecordHeader aRecHd; + bool bOk = ReadDffRecordHeader(rIn, aRecHd); + if (bOk && SvxMSDffManager::SeekToRec(rIn, DFF_msofbtOPT, aRecHd.GetRecEndFilePos())) + { + rIn |= const_cast(*this); + } + } + } + + const_cast(this)->mnFix16Angle = Fix16ToAngle( GetPropertyValue( DFF_Prop_Rotation, 0 ) ); + +#ifdef DBG_CUSTOMSHAPE + + OUString aURLStr; + + if( osl::FileBase::getFileURLFromSystemPath( OUString("d:\\ashape.dbg"), aURLStr ) == osl::FileBase::E_None ) + { + std::unique_ptr xOut(::utl::UcbStreamHelper::CreateStream( aURLStr, StreamMode::WRITE )); + + if( xOut ) + { + xOut->Seek( STREAM_SEEK_TO_END ); + + if ( IsProperty( DFF_Prop_adjustValue ) || IsProperty( DFF_Prop_pVertices ) ) + { + xOut->WriteLine( "" ); + OString aString("ShapeId: " + OString::number(nShapeId)); + xOut->WriteLine(aString); + } + for ( sal_uInt32 i = DFF_Prop_adjustValue; i <= DFF_Prop_adjust10Value; i++ ) + { + if ( IsProperty( i ) ) + { + OString aString("Prop_adjustValue" + OString::number( ( i - DFF_Prop_adjustValue ) + 1 ) + + ":" + OString::number(GetPropertyValue(i)) ); + xOut->WriteLine(aString); + } + } + sal_Int32 i; + for ( i = 320; i < 383; i++ ) + { + if ( ( i >= DFF_Prop_adjustValue ) && ( i <= DFF_Prop_adjust10Value ) ) + continue; + if ( IsProperty( i ) ) + { + if ( SeekToContent( i, rIn ) ) + { + sal_Int32 nLen = (sal_Int32)GetPropertyValue( i ); + if ( nLen ) + { + xOut->WriteLine( "" ); + OStringBuffer aDesc("Property:" + OString::number(i) + + " Size:" + OString::number(nLen)); + xOut->WriteLine(aDesc.makeStringAndClear()); + sal_Int16 nNumElem, nNumElemMem, nNumSize; + rIn >> nNumElem >> nNumElemMem >> nNumSize; + aDesc.append("Entries: " + OString::number(nNumElem) + + " Size:" + OString::number(nNumSize)); + xOut->WriteLine(aDesc.makeStringAndClear()); + if ( nNumSize < 0 ) + nNumSize = ( ( -nNumSize ) >> 2 ); + if ( !nNumSize ) + nNumSize = 16; + nLen -= 6; + while ( nLen > 0 ) + { + for ( sal_uInt32 j = 0; nLen && ( j < ( nNumSize >> 1 ) ); j++ ) + { + for ( sal_uInt32 k = 0; k < 2; k++ ) + { + if ( nLen ) + { + sal_uInt8 nVal; + rIn >> nVal; + if ( ( nVal >> 4 ) > 9 ) + *xOut << (sal_uInt8)( ( nVal >> 4 ) + 'A' - 10 ); + else + *xOut << (sal_uInt8)( ( nVal >> 4 ) + '0' ); + + if ( ( nVal & 0xf ) > 9 ) + *xOut << (sal_uInt8)( ( nVal & 0xf ) + 'A' - 10 ); + else + *xOut << (sal_uInt8)( ( nVal & 0xf ) + '0' ); + + nLen--; + } + } + *xOut << (char)( ' ' ); + } + xOut->WriteLine( OString() ); + } + } + } + else + { + OString aString("Property" + OString::number(i) + + ":" + OString::number(GetPropertyValue(i))); + xOut->WriteLine(aString); + } + } + } + } + } + +#endif + + rIn.Seek( nFilePos ); +} + + +Degree100 DffPropertyReader::Fix16ToAngle( sal_Int32 nContent ) +{ + Degree100 nAngle(0); + if ( nContent ) + { + nAngle = Degree100(( static_cast( nContent >> 16) * 100L ) + ( ( ( nContent & 0x0000ffff) * 100L ) >> 16 )); + nAngle = NormAngle36000( -nAngle ); + } + return nAngle; +} + +DffPropertyReader::~DffPropertyReader() +{ +} + +static SvStream& operator>>( SvStream& rIn, SvxMSDffConnectorRule& rRule ) +{ + sal_uInt32 nRuleId; + rIn.ReadUInt32( nRuleId ) + .ReadUInt32( rRule.nShapeA ) + .ReadUInt32( rRule.nShapeB ) + .ReadUInt32( rRule.nShapeC ) + .ReadUInt32( rRule.ncptiA ) + .ReadUInt32( rRule.ncptiB ); + + return rIn; +} + +SvxMSDffSolverContainer::SvxMSDffSolverContainer() +{ +} + +SvxMSDffSolverContainer::~SvxMSDffSolverContainer() +{ +} + +SvStream& ReadSvxMSDffSolverContainer( SvStream& rIn, SvxMSDffSolverContainer& rContainer ) +{ + DffRecordHeader aHd; + bool bOk = ReadDffRecordHeader( rIn, aHd ); + if (!bOk || aHd.nRecType != DFF_msofbtSolverContainer) + return rIn; + + DffRecordHeader aCRule; + auto nEndPos = DffPropSet::SanitizeEndPos(rIn, aHd.GetRecEndFilePos()); + while ( rIn.good() && ( rIn.Tell() < nEndPos ) ) + { + if (!ReadDffRecordHeader(rIn, aCRule)) + break; + if ( aCRule.nRecType == DFF_msofbtConnectorRule ) + { + std::unique_ptr pRule(new SvxMSDffConnectorRule); + rIn >> *pRule; + rContainer.aCList.push_back( std::move(pRule) ); + } + if (!aCRule.SeekToEndOfRecord(rIn)) + break; + } + return rIn; +} + +void SvxMSDffManager::SolveSolver( const SvxMSDffSolverContainer& rSolver ) +{ + size_t i, nCnt; + for ( i = 0, nCnt = rSolver.aCList.size(); i < nCnt; i++ ) + { + SvxMSDffConnectorRule* pPtr = rSolver.aCList[ i ].get(); + if ( pPtr->pCObj ) + { + for ( int nN = 0; nN < 2; nN++ ) + { + SdrObject* pO; + sal_uInt32 nC; + ShapeFlag nSpFlags; + if ( !nN ) + { + pO = pPtr->pAObj; + nC = pPtr->ncptiA; + nSpFlags = pPtr->nSpFlagsA; + } + else + { + pO = pPtr->pBObj; + nC = pPtr->ncptiB; + nSpFlags = pPtr->nSpFlagsB; + } + if ( pO ) + { + SdrGluePoint aGluePoint; + Reference< XShape > aXShape( pO->getUnoShape(), UNO_QUERY ); + Reference< XShape > aXConnector( pPtr->pCObj->getUnoShape(), UNO_QUERY ); + SdrGluePointList* pList = pO->ForceGluePointList(); + + sal_Int32 nId = nC; + SdrInventor nInventor = pO->GetObjInventor(); + + if( nInventor == SdrInventor::Default ) + { + bool bValidGluePoint = false; + SdrObjKind nObjId = pO->GetObjIdentifier(); + switch( nObjId ) + { + case SdrObjKind::Group : + case SdrObjKind::Graphic : + case SdrObjKind::Rectangle : + case SdrObjKind::Text : + case SdrObjKind::Page : + case SdrObjKind::TitleText : + case SdrObjKind::OutlineText : + { + if ( nC & 1 ) + { + if ( nSpFlags & ShapeFlag::FlipH ) + nC ^= 2; // 1 <-> 3 + } + else + { + if ( nSpFlags & ShapeFlag::FlipV ) + nC ^= 1; // 0 <-> 2 + } + switch( nC ) + { + case 0 : + nId = 0; // SdrAlign::VERT_TOP; + break; + case 1 : + nId = 3; // SdrAlign::HORZ_RIGHT; + break; + case 2 : + nId = 2; // SdrAlign::VERT_BOTTOM; + break; + case 3 : + nId = 1; // SdrAlign::HORZ_LEFT; + break; + } + if ( nId <= 3 ) + bValidGluePoint = true; + } + break; + case SdrObjKind::Polygon : + case SdrObjKind::PolyLine : + case SdrObjKind::Line : + case SdrObjKind::PathLine : + case SdrObjKind::PathFill : + case SdrObjKind::FreehandLine : + case SdrObjKind::FreehandFill : + case SdrObjKind::SplineLine : + case SdrObjKind::SplineFill : + case SdrObjKind::PathPoly : + case SdrObjKind::PathPolyLine : + { + if (pList) + { + if (pList->GetCount() > nC ) + { + bValidGluePoint = true; + nId = static_cast((*pList)[ static_cast(nC)].GetId() + 3 ); + } + else + { + bool bNotFound = true; + + tools::PolyPolygon aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aXShape ) ); + sal_uInt16 k, j, nPolySize = aPolyPoly.Count(); + if ( nPolySize ) + { + tools::Rectangle aBoundRect( aPolyPoly.GetBoundRect() ); + if ( aBoundRect.GetWidth() && aBoundRect.GetHeight() ) + { + sal_uInt32 nPointCount = 0; + for ( k = 0; bNotFound && ( k < nPolySize ); k++ ) + { + const tools::Polygon& rPolygon = aPolyPoly.GetObject( k ); + for ( j = 0; bNotFound && ( j < rPolygon.GetSize() ); j++ ) + { + PolyFlags eFlags = rPolygon.GetFlags( j ); + if ( eFlags == PolyFlags::Normal ) + { + if ( nC == nPointCount ) + { + const Point& rPoint = rPolygon.GetPoint( j ); + double fXRel = rPoint.X() - aBoundRect.Left(); + double fYRel = rPoint.Y() - aBoundRect.Top(); + sal_Int32 nWidth = aBoundRect.GetWidth(); + if ( !nWidth ) + nWidth = 1; + sal_Int32 nHeight= aBoundRect.GetHeight(); + if ( !nHeight ) + nHeight = 1; + fXRel /= static_cast(nWidth); + fXRel *= 10000; + fYRel /= static_cast(nHeight); + fYRel *= 10000; + aGluePoint.SetPos( Point( static_cast(fXRel), static_cast(fYRel) ) ); + aGluePoint.SetPercent( true ); + aGluePoint.SetAlign( SdrAlign::VERT_TOP | SdrAlign::HORZ_LEFT ); + aGluePoint.SetEscDir( SdrEscapeDirection::SMART ); + nId = static_cast((*pList)[ pList->Insert( aGluePoint ) ].GetId() + 3 ); + bNotFound = false; + } + nPointCount++; + } + } + } + } + } + if ( !bNotFound ) + { + bValidGluePoint = true; + } + } + } + } + break; + + case SdrObjKind::CustomShape : + { + const SfxPoolItem& aCustomShape = static_cast(pO)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ); + SdrCustomShapeGeometryItem aGeometryItem( static_cast(aCustomShape) ); + static const OUStringLiteral sPath( u"Path" ); + sal_Int16 nGluePointType = EnhancedCustomShapeGluePointType::SEGMENTS; + css::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sPath, "GluePointType" ); + if ( pAny ) + *pAny >>= nGluePointType; + else + { + OUString sShapeType; + pAny = aGeometryItem.GetPropertyValueByName( "Type" ); + if ( pAny ) + *pAny >>= sShapeType; + MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType ); + nGluePointType = GetCustomShapeConnectionTypeDefault( eSpType ); + } + if ( nGluePointType == EnhancedCustomShapeGluePointType::CUSTOM ) + { + if ( pList && ( pList->GetCount() > nC ) ) + { + bValidGluePoint = true; + nId = static_cast((*pList)[ static_cast(nC)].GetId() + 3 ); + } + } + else if ( nGluePointType == EnhancedCustomShapeGluePointType::RECT ) + { + if ( nC & 1 ) + { + if ( nSpFlags & ShapeFlag::FlipH ) + nC ^= 2; // 1 <-> 3 + } + else + { + if ( nSpFlags & ShapeFlag::FlipV ) + nC ^= 1; // 0 <-> 2 + } + switch( nC ) + { + case 0 : + nId = 0; // SdrAlign::VERT_TOP; + break; + case 1 : + nId = 3; // SdrAlign::HORZ_RIGHT; + break; + case 2 : + nId = 2; // SdrAlign::VERT_BOTTOM; + break; + case 3 : + nId = 1; // SdrAlign::HORZ_LEFT; + break; + } + if ( nId <= 3 ) + bValidGluePoint = true; + } + else if ( nGluePointType == EnhancedCustomShapeGluePointType::SEGMENTS ) + { + sal_uInt32 nPt = nC; + css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments; + pAny = aGeometryItem.GetPropertyValueByName( sPath, "Segments" ); + if ( pAny && (*pAny >>= aSegments) ) + { + nPt = 0; + for ( sal_Int32 k = 1; nC && ( k < aSegments.getLength() ); k++ ) + { + sal_Int16 j, nCnt2 = aSegments[ k ].Count; + if ( aSegments[ k ].Command != EnhancedCustomShapeSegmentCommand::UNKNOWN ) + { + for ( j = 0; nC && ( j < nCnt2 ); j++ ) + { + switch( aSegments[ k ].Command ) + { + case EnhancedCustomShapeSegmentCommand::ENDSUBPATH : + case EnhancedCustomShapeSegmentCommand::CLOSESUBPATH : + case EnhancedCustomShapeSegmentCommand::LINETO : + case EnhancedCustomShapeSegmentCommand::MOVETO : + { + nC--; + nPt++; + } + break; + case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX : + case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY : + break; + + case EnhancedCustomShapeSegmentCommand::CURVETO : + { + nC--; + nPt += 3; + } + break; + + case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO : + case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE : + { + nC--; + nPt += 3; + } + break; + case EnhancedCustomShapeSegmentCommand::ARCTO : + case EnhancedCustomShapeSegmentCommand::ARC : + case EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO : + case EnhancedCustomShapeSegmentCommand::CLOCKWISEARC : + { + nC--; + nPt += 4; + } + break; + } + } + } + } + } + pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" ); + if ( pAny ) + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates; + *pAny >>= aCoordinates; + if ( nPt < o3tl::make_unsigned(aCoordinates.getLength()) ) + { + nId = 4; + css::drawing::EnhancedCustomShapeParameterPair& rPara = aCoordinates.getArray()[ nPt ]; + sal_Int32 nX = 0, nY = 0; + if ( ( rPara.First.Value >>= nX ) && ( rPara.Second.Value >>= nY ) ) + { + static const OUStringLiteral sGluePoints( u"GluePoints" ); + css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints; + pAny = aGeometryItem.GetPropertyValueByName( sPath, sGluePoints ); + if ( pAny ) + *pAny >>= aGluePoints; + sal_Int32 nGluePoints = aGluePoints.getLength(); + aGluePoints.realloc( nGluePoints + 1 ); + auto pGluePoints = aGluePoints.getArray(); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].First, nX ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].Second, nY ); + PropertyValue aProp; + aProp.Name = sGluePoints; + aProp.Value <<= aGluePoints; + aGeometryItem.SetPropertyValue( sPath, aProp ); + bValidGluePoint = true; + static_cast(pO)->SetMergedItem( aGeometryItem ); + SdrGluePointList* pLst = pO->ForceGluePointList(); + if ( pLst->GetCount() > nGluePoints ) + nId = static_cast((*pLst)[ static_cast(nGluePoints) ].GetId() + 3 ); + } + } + } + } + } + break; + default: ; + } + if ( bValidGluePoint ) + { + Reference< XPropertySet > xPropSet( aXConnector, UNO_QUERY ); + if ( xPropSet.is() ) + { + if ( nN ) + { + OUString aPropName( "EndShape" ); + SetPropValue( Any(aXShape), xPropSet, aPropName ); + aPropName = "EndGluePointIndex"; + SetPropValue( Any(nId), xPropSet, aPropName ); + } + else + { + OUString aPropName( "StartShape" ); + SetPropValue( Any(aXShape), xPropSet, aPropName ); + aPropName = "StartGluePointIndex"; + SetPropValue( Any(nId), xPropSet, aPropName ); + } + + // Not sure what this is good for, repaint or broadcast of object change. + //( Thus I am adding repaint here + pO->SetChanged(); + pO->BroadcastObjectChange(); + } + } + } + } + } + } + } +} + +static basegfx::B2DPolyPolygon GetLineArrow( const sal_Int32 nLineWidth, const sal_uInt32 eLineEnd, + const sal_uInt32 eLineWidth, const sal_uInt32 eLineLength, + sal_Int32& rnArrowWidth, bool& rbArrowCenter, + OUString& rsArrowName, bool bScaleArrow ) +{ + basegfx::B2DPolyPolygon aRetPolyPoly; + // 70 100mm = 2pt = 40 twip. In MS, line width less than 2pt has the same size arrow as 2pt + //If the unit is twip. Make all use this unit especially the critical value 70/40. + sal_Int32 nLineWidthCritical = bScaleArrow ? 40 : 70; + double fLineWidth = nLineWidth < nLineWidthCritical ? nLineWidthCritical : nLineWidth; + + double fLengthMul, fWidthMul; + sal_Int32 nLineNumber; + switch( eLineLength ) + { + default : + case mso_lineMediumLenArrow : fLengthMul = 3.0; nLineNumber = 2; break; + case mso_lineShortArrow : fLengthMul = 2.0; nLineNumber = 1; break; + case mso_lineLongArrow : fLengthMul = 5.0; nLineNumber = 3; break; + } + switch( eLineWidth ) + { + default : + case mso_lineMediumWidthArrow : fWidthMul = 3.0; nLineNumber += 3; break; + case mso_lineNarrowArrow : fWidthMul = 2.0; break; + case mso_lineWideArrow : fWidthMul = 5.0; nLineNumber += 6; break; + } + + rbArrowCenter = false; + OUStringBuffer aArrowName; + switch ( eLineEnd ) + { + case mso_lineArrowEnd : + { + basegfx::B2DPolygon aTriangle; + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, 0.0 )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth )); + aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth )); + aTriangle.setClosed(true); + aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle); + aArrowName.append("msArrowEnd "); + } + break; + + case mso_lineArrowOpenEnd : + { + switch( eLineLength ) + { + default : + case mso_lineMediumLenArrow : fLengthMul = 4.5; break; + case mso_lineShortArrow : fLengthMul = 3.5; break; + case mso_lineLongArrow : fLengthMul = 6.0; break; + } + switch( eLineWidth ) + { + default : + case mso_lineMediumWidthArrow : fWidthMul = 4.5; break; + case mso_lineNarrowArrow : fWidthMul = 3.5; break; + case mso_lineWideArrow : fWidthMul = 6.0; break; + } + basegfx::B2DPolygon aTriangle; + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth * 0.91 )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.85, fLengthMul * fLineWidth )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, fLengthMul * fLineWidth * 0.36 )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.15, fLengthMul * fLineWidth )); + aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.91 )); + aTriangle.setClosed(true); + aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle); + aArrowName.append("msArrowOpenEnd "); + } + break; + case mso_lineArrowStealthEnd : + { + basegfx::B2DPolygon aTriangle; + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth * 0.60 )); + aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth )); + aTriangle.setClosed(true); + aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle); + aArrowName.append("msArrowStealthEnd "); + } + break; + case mso_lineArrowDiamondEnd : + { + basegfx::B2DPolygon aTriangle; + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth * 0.50 )); + aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth )); + aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.50 )); + aTriangle.setClosed(true); + aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle); + rbArrowCenter = true; + aArrowName.append("msArrowDiamondEnd "); + } + break; + case mso_lineArrowOvalEnd : + { + aRetPolyPoly = basegfx::B2DPolyPolygon( + XPolygon( + Point( static_cast( fWidthMul * fLineWidth * 0.50 ), 0 ), + static_cast( fWidthMul * fLineWidth * 0.50 ), + static_cast( fLengthMul * fLineWidth * 0.50 ), + 0_deg100, 36000_deg100 ).getB2DPolygon() ); + rbArrowCenter = true; + aArrowName.append("msArrowOvalEnd "); + } + break; + default: break; + } + aArrowName.append(nLineNumber); + rsArrowName = aArrowName.makeStringAndClear(); + rnArrowWidth = static_cast( fLineWidth * fWidthMul ); + + return aRetPolyPoly; +} + +void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eShapeType ) const // #i28269# +{ + sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 )); + + if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( eShapeType )) + { + nLineFlags &= ~0x08; + } + + if ( nLineFlags & 8 ) + { + // Line Attributes + sal_Int32 nLineWidth = static_cast(GetPropertyValue( DFF_Prop_lineWidth, 9525 )); + + // support LineCap + auto eLineCap = GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapFlat); + + switch(eLineCap) + { + default: /* case mso_lineEndCapFlat */ + { + // no need to set, it is the default. If this changes, this needs to be activated + // rSet.Put(XLineCapItem(css::drawing::LineCap_BUTT)); + break; + } + case mso_lineEndCapRound: + { + rSet.Put(XLineCapItem(css::drawing::LineCap_ROUND)); + break; + } + case mso_lineEndCapSquare: + { + rSet.Put(XLineCapItem(css::drawing::LineCap_SQUARE)); + break; + } + } + + auto eLineDashing = GetPropertyValue( DFF_Prop_lineDashing, mso_lineSolid); + if (eLineDashing == mso_lineSolid || nLineWidth < 0) + rSet.Put(XLineStyleItem( drawing::LineStyle_SOLID ) ); + else + { + // Despite of naming "dot" and "dash", that are all dashes and a "dot" can be longer + // than a "dash". The naming indicates the order, "dot" is always the first dash and + // "dash" is always the second dash. MS Office always starts with the longer dash, so + // set it here accordingly. + // The preset from binary is essentially the same as from OOXML. So here the same + // setting is used as in oox import. The comment corresponds to + // "dots, dotLen, dashes, dashLen, distance" there. + // MS Office uses always relative length, so no need to consider nLineWidth + // here. Values are of kind 300 for 300% in css::drawing::DashStyle, for example. + + sal_uInt16 nDots = 1; // in all cases, "solid" is treated above + // initialize, will be changed if necessary + sal_uInt32 nDotLen = 300; + sal_uInt16 nDashes = 0; + sal_uInt32 nDashLen = 0; + sal_uInt32 nDistance = 300; + switch ( eLineDashing ) + { + default: + case mso_lineDotSys : // 1 1 0 0 1 + { + nDotLen =100; + nDistance = 100; + } + break; + + case mso_lineDashGEL : // 1 4 0 0 3 + { + nDotLen = 400; + } + break; + + case mso_lineDashDotGEL : // 1 4 1 1 3 + { + nDotLen = 400; + nDashes = 1; + nDashLen = 100; + } + break; + + case mso_lineLongDashGEL : // 1 8 0 0 3 + { + nDotLen = 800; + } + break; + + case mso_lineLongDashDotGEL : // 1 8 1 1 3 + { + nDotLen = 800; + nDashes = 1; + nDashLen = 100; + } + break; + + case mso_lineLongDashDotDotGEL: // 1 8 2 1 3 + { + nDotLen = 800; + nDashes = 2; + nDashLen = 100; + } + break; + + case mso_lineDotGEL: // 1 1 0 0 3 + { + nDotLen = 100; + } + break; + + case mso_lineDashSys: // 1 3 0 0 1 + { + nDistance = 100; + } + break; + + case mso_lineDashDotSys: // 1 3 1 1 1 + { + nDashes = 1; + nDashLen = 100; + nDistance = 100; + } + break; + + case mso_lineDashDotDotSys: // 1 3 2 1 1 + { + nDashes = 2; + nDashLen = 100; + nDistance = 100; + } + break; + } + rSet.Put( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECTRELATIVE, nDots, nDotLen, nDashes, nDashLen, nDistance ) ) ); + rSet.Put( XLineStyleItem( drawing::LineStyle_DASH ) ); + } + rSet.Put( XLineColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_lineColor, 0 ) ) ) ); + if ( IsProperty( DFF_Prop_lineOpacity ) ) + { + double nTrans = GetPropertyValue(DFF_Prop_lineOpacity, 0x10000); + nTrans = (nTrans * 100) / 65536; + rSet.Put(XLineTransparenceItem( + sal_uInt16(100 - ::rtl::math::round(nTrans)))); + } + + rManager.ScaleEmu( nLineWidth ); + rSet.Put( XLineWidthItem( nLineWidth ) ); + + // SJ: LineJoint (setting each time a line is set, because our internal joint type has another default) + MSO_LineJoin eLineJointDefault = mso_lineJoinMiter; + if ( eShapeType == mso_sptMin ) + eLineJointDefault = mso_lineJoinRound; + auto eLineJoint = GetPropertyValue(DFF_Prop_lineJoinStyle, eLineJointDefault); + css::drawing::LineJoint eXLineJoint( css::drawing::LineJoint_MITER ); + if ( eLineJoint == mso_lineJoinBevel ) + eXLineJoint = css::drawing::LineJoint_BEVEL; + else if ( eLineJoint == mso_lineJoinRound ) + eXLineJoint = css::drawing::LineJoint_ROUND; + rSet.Put( XLineJointItem( eXLineJoint ) ); + + if ( nLineFlags & 0x10 ) + { + bool bScaleArrows = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip; + + // LineStart + + if ( IsProperty( DFF_Prop_lineStartArrowhead ) ) + { + auto eLineEnd = GetPropertyValue(DFF_Prop_lineStartArrowhead, 0); + auto eWidth = GetPropertyValue(DFF_Prop_lineStartArrowWidth, mso_lineMediumWidthArrow); + auto eLength = GetPropertyValue(DFF_Prop_lineStartArrowLength, mso_lineMediumLenArrow); + + sal_Int32 nArrowWidth; + bool bArrowCenter; + OUString aArrowName; + basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows )); + + rSet.Put( XLineStartWidthItem( nArrowWidth ) ); + rSet.Put( XLineStartItem( aArrowName, aPolyPoly) ); + rSet.Put( XLineStartCenterItem( bArrowCenter ) ); + } + + // LineEnd + + if ( IsProperty( DFF_Prop_lineEndArrowhead ) ) + { + auto eLineEnd = GetPropertyValue(DFF_Prop_lineEndArrowhead, 0); + auto eWidth = GetPropertyValue(DFF_Prop_lineEndArrowWidth, mso_lineMediumWidthArrow); + auto eLength = GetPropertyValue(DFF_Prop_lineEndArrowLength, mso_lineMediumLenArrow); + + sal_Int32 nArrowWidth; + bool bArrowCenter; + OUString aArrowName; + basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows )); + + rSet.Put( XLineEndWidthItem( nArrowWidth ) ); + rSet.Put( XLineEndItem( aArrowName, aPolyPoly ) ); + rSet.Put( XLineEndCenterItem( bArrowCenter ) ); + } + } + } + else + rSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) ); +} + +namespace { + +struct ShadeColor +{ + Color aColor; + double fDist; + + ShadeColor( const Color& rC, double fR ) : aColor( rC ), fDist( fR ) {}; +}; + +} + +static void GetShadeColors( const SvxMSDffManager& rManager, const DffPropertyReader& rProperties, SvStream& rIn, std::vector< ShadeColor >& rShadeColors ) +{ + sal_uInt64 nPos = rIn.Tell(); + if ( rProperties.IsProperty( DFF_Prop_fillShadeColors ) ) + { + sal_uInt16 i = 0, nNumElem = 0; + bool bOk = false; + if (rProperties.SeekToContent(DFF_Prop_fillShadeColors, rIn)) + { + sal_uInt16 nNumElemReserved = 0, nSize = 0; + rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemReserved ).ReadUInt16( nSize ); + //sanity check that the stream is long enough to fulfill nNumElem * 2 sal_Int32s + bOk = rIn.remainingSize() / (2*sizeof(sal_Int32)) >= nNumElem; + } + if (bOk) + { + for ( ; i < nNumElem; i++ ) + { + sal_Int32 nColor(0); + sal_Int32 nDist(0); + + rIn.ReadInt32( nColor ).ReadInt32( nDist ); + rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( nColor, DFF_Prop_fillColor ), 1.0 - ( nDist / 65536.0 ) ); + } + } + } + if ( rShadeColors.empty() ) + { + rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ), 0 ); + rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ), 1 ); + } + rIn.Seek( nPos ); +} + +static void ApplyRectangularGradientAsBitmap( const SvxMSDffManager& rManager, SvStream& rIn, SfxItemSet& rSet, const std::vector< ShadeColor >& rShadeColors, const DffObjData& rObjData, Degree100 nFix16Angle ) +{ + Size aBitmapSizePixel( static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetWidth() / 2540.0 ) * 90.0 ), // we will create a bitmap with 90 dpi + static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetHeight() / 2540.0 ) * 90.0 ) ); + if (aBitmapSizePixel.IsEmpty() || aBitmapSizePixel.Width() > 1024 || aBitmapSizePixel.Height() > 1024) + return; + + double fFocusX = rManager.GetPropertyValue( DFF_Prop_fillToRight, 0 ) / 65536.0; + double fFocusY = rManager.GetPropertyValue( DFF_Prop_fillToBottom, 0 ) / 65536.0; + + vcl::bitmap::RawBitmap aBitmap(aBitmapSizePixel, 24); + + for ( tools::Long nY = 0; nY < aBitmapSizePixel.Height(); nY++ ) + { + for ( tools::Long nX = 0; nX < aBitmapSizePixel.Width(); nX++ ) + { + double fX = static_cast< double >( nX ) / aBitmapSizePixel.Width(); + double fY = static_cast< double >( nY ) / aBitmapSizePixel.Height(); + + double fD, fDist; + if ( fX < fFocusX ) + { + if ( fY < fFocusY ) + { + if ( fX > fY ) + { + fDist = fY; + fD = fFocusY; + } + else + { + fDist = fX; + fD = fFocusX; + } + } + else + { + if ( fX > ( 1 - fY ) ) + { + fDist = 1 - fY; + fD = 1 - fFocusY; + } + else + { + fDist = fX; + fD = fFocusX; + } + } + } + else + { + if ( fY < fFocusY ) + { + if ( ( 1 - fX ) > fY ) + { + fDist = fY; + fD = fFocusY; + } + else + { + fDist = 1 - fX; + fD = 1 - fFocusX; + } + } + else + { + if ( ( 1 - fX ) > ( 1 - fY ) ) + { + fDist = 1 - fY; + fD = 1 - fFocusY; + } + else + { + fDist = 1 - fX; + fD = 1 - fFocusX; + } + } + } + if ( fD != 0.0 ) + fDist /= fD; + + double fA = 0.0; + Color aColorA = rShadeColors.front().aColor; + double fB = 1.0; + Color aColorB( aColorA ); + for ( const auto& rShadeColor : rShadeColors ) + { + if ( fA <= rShadeColor.fDist && rShadeColor.fDist <= fDist ) + { + fA = rShadeColor.fDist; + aColorA = rShadeColor.aColor; + } + if ( fDist < rShadeColor.fDist && rShadeColor.fDist <= fB ) + { + fB = rShadeColor.fDist; + aColorB = rShadeColor.aColor; + } + } + double fRed = aColorA.GetRed(), fGreen = aColorA.GetGreen(), fBlue = aColorA.GetBlue(); + double fD1 = fB - fA; + if ( fD1 != 0.0 ) + { + fRed += ( ( ( fDist - fA ) * ( aColorB.GetRed() - aColorA.GetRed() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fRed; + fGreen += ( ( ( fDist - fA ) * ( aColorB.GetGreen() - aColorA.GetGreen() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fGreen; + fBlue += ( ( ( fDist - fA ) * ( aColorB.GetBlue() - aColorA.GetBlue() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fBlue; + } + sal_Int16 nRed = static_cast< sal_Int16 >( fRed + 0.5 ); + sal_Int16 nGreen = static_cast< sal_Int16 >( fGreen + 0.5 ); + sal_Int16 nBlue = static_cast< sal_Int16 >( fBlue + 0.5 ); + if ( nRed < 0 ) + nRed = 0; + if ( nRed > 255 ) + nRed = 255; + if ( nGreen < 0 ) + nGreen = 0; + if ( nGreen > 255 ) + nGreen = 255; + if ( nBlue < 0 ) + nBlue = 0; + if ( nBlue > 255 ) + nBlue = 255; + + aBitmap.SetPixel(nY, nX, Color(static_cast(nRed), static_cast(nGreen), static_cast(nBlue))); + } + } + BitmapEx aBitmapEx = vcl::bitmap::CreateFromData( std::move(aBitmap) ); + + if ( nFix16Angle ) + { + bool bRotateWithShape = true; // sal_True seems to be default + sal_uInt64 nPos = rIn.Tell(); + if ( const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.SeekToContent( rIn, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) ) + { + const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.Current()->SeekToBegOfRecord( rIn ); + DffPropertyReader aSecPropSet( rManager ); + aSecPropSet.ReadPropSet( rIn, nullptr ); + sal_Int32 nSecFillProperties = aSecPropSet.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0x200020 ); + bRotateWithShape = ( nSecFillProperties & 0x0020 ); + } + rIn.Seek( nPos ); + if ( bRotateWithShape ) + { + // convert from 100th to 10th degrees + aBitmapEx.Rotate( to(nFix16Angle), rShadeColors[ 0 ].aColor ); + + BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE; + if ( rObjData.nSpFlags & ShapeFlag::FlipV ) + nMirrorFlags |= BmpMirrorFlags::Vertical; + if ( rObjData.nSpFlags & ShapeFlag::FlipH ) + nMirrorFlags |= BmpMirrorFlags::Horizontal; + if ( nMirrorFlags != BmpMirrorFlags::NONE ) + aBitmapEx.Mirror( nMirrorFlags ); + } + } + + rSet.Put(XFillBmpTileItem(false)); + rSet.Put(XFillBitmapItem(OUString(), Graphic(aBitmapEx))); +} + +void DffPropertyReader::ApplyFillAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const +{ + sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 )); + + std::vector< ShadeColor > aShadeColors; + GetShadeColors( rManager, *this, rIn, aShadeColors ); + + if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType )) + { + nFillFlags &= ~0x10; + } + + if ( nFillFlags & 0x10 ) + { + auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid); + drawing::FillStyle eXFill = drawing::FillStyle_NONE; + switch( eMSO_FillType ) + { + case mso_fillSolid : // Fill with a solid color + eXFill = drawing::FillStyle_SOLID; + break; + case mso_fillPattern : // Fill with a pattern (bitmap) + case mso_fillTexture : // A texture (pattern with its own color map) + case mso_fillPicture : // Center a picture in the shape + eXFill = drawing::FillStyle_BITMAP; + break; + case mso_fillShadeCenter : // Shade from bounding rectangle to end point + { + //If it is imported as a bitmap, it will not work well with transparency especially 100 + //But the gradient look well comparing with imported as gradient. And rotate with shape + //also works better. So here just keep it. + if ( rObjData.aBoundRect.IsEmpty() )// size of object needed to be able + eXFill = drawing::FillStyle_GRADIENT; // to create a bitmap substitution + else + eXFill = drawing::FillStyle_BITMAP; + } + break; + case mso_fillShade : // Shade from start to end points + case mso_fillShadeShape : // Shade from shape outline to end point + case mso_fillShadeScale : // Similar to mso_fillShade, but the fillAngle + case mso_fillShadeTitle : // special type - shade to title --- for PP + eXFill = drawing::FillStyle_GRADIENT; + break; +// case mso_fillBackground : // Use the background fill color/pattern + default: break; + } + rSet.Put( XFillStyleItem( eXFill ) ); + + double dTrans = 1.0; + double dBackTrans = 1.0; + if (IsProperty(DFF_Prop_fillOpacity)) + { + dTrans = GetPropertyValue(DFF_Prop_fillOpacity, 0) / 65536.0; + if ( eXFill != drawing::FillStyle_GRADIENT ) + { + dTrans = dTrans * 100; + rSet.Put(XFillTransparenceItem( + sal_uInt16(100 - ::rtl::math::round(dTrans)))); + } + } + + if ( IsProperty(DFF_Prop_fillBackOpacity) ) + dBackTrans = GetPropertyValue(DFF_Prop_fillBackOpacity, 0) / 65536.0; + + if ( ( eMSO_FillType == mso_fillShadeCenter ) && ( eXFill == drawing::FillStyle_BITMAP ) ) + { + ApplyRectangularGradientAsBitmap( rManager, rIn, rSet, aShadeColors, rObjData, mnFix16Angle ); + } + else if ( eXFill == drawing::FillStyle_GRADIENT ) + { + ImportGradientColor ( rSet, eMSO_FillType, dTrans , dBackTrans ); + } + else if ( eXFill == drawing::FillStyle_BITMAP ) + { + if( IsProperty( DFF_Prop_fillBlip ) ) + { + Graphic aGraf; + // first try to get BLIP from cache + bool bOK = const_cast(rManager).GetBLIP( GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf ); + // then try directly from stream (i.e. Excel chart hatches/bitmaps) + if ( !bOK ) + bOK = SeekToContent( DFF_Prop_fillBlip, rIn ) && SvxMSDffManager::GetBLIPDirect( rIn, aGraf ); + if ( bOK ) + { + if ( eMSO_FillType == mso_fillPattern ) + { + Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() ); + if (aBmp.GetSizePixel().Width() == 8 && + aBmp.GetSizePixel().Height() == 8 && + aBmp.getPixelFormat() == vcl::PixelFormat::N1_BPP) + { + Color aCol1( COL_WHITE ), aCol2( COL_WHITE ); + + if ( IsProperty( DFF_Prop_fillColor ) ) + aCol1 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor ); + + if ( IsProperty( DFF_Prop_fillBackColor ) ) + aCol2 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, 0 ), DFF_Prop_fillBackColor ); + + // Create a bitmap for the pattern with expected colors + vcl::bitmap::RawBitmap aResult(Size(8, 8), 24); + { + Bitmap::ScopedReadAccess pRead(aBmp); + + for (tools::Long y = 0; y < aResult.Height(); ++y) + { + Scanline pScanlineRead = pRead->GetScanline( y ); + for (tools::Long x = 0; x < aResult.Width(); ++x) + { + Color aReadColor; + if (pRead->HasPalette()) + aReadColor = pRead->GetPaletteColor(pRead->GetIndexFromData(pScanlineRead, x)); + else + aReadColor = pRead->GetPixelFromData(pScanlineRead, x); + + if (aReadColor == Color(0)) + aResult.SetPixel(y, x, aCol2); + else + aResult.SetPixel(y, x, aCol1); + } + } + } + aGraf = Graphic(vcl::bitmap::CreateFromData(std::move(aResult))); + } + + rSet.Put(XFillBitmapItem(OUString(), aGraf)); + } + else if ( eMSO_FillType == mso_fillTexture ) + { + rSet.Put(XFillBmpTileItem(true)); + rSet.Put(XFillBitmapItem(OUString(), aGraf)); + rSet.Put(XFillBmpSizeXItem(GetPropertyValue(DFF_Prop_fillWidth, 0) / 360)); + rSet.Put(XFillBmpSizeYItem(GetPropertyValue(DFF_Prop_fillHeight, 0) / 360)); + rSet.Put(XFillBmpSizeLogItem(true)); + } + else + { + rSet.Put(XFillBitmapItem(OUString(), aGraf)); + rSet.Put(XFillBmpTileItem(false)); + } + } + } + } + } + else + rSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) ); +} + +void DffPropertyReader::ApplyCustomShapeTextAttributes( SfxItemSet& rSet ) const +{ + bool bVerticalText = false; + sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 ) / 360; // 0.25 cm (emu) + sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ) / 360; // 0.25 cm (emu) + sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 ) / 360; // 0.13 cm (emu) + sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 ) /360; // 0.13 cm (emu) + + SdrTextVertAdjust eTVA; + SdrTextHorzAdjust eTHA; + + if ( IsProperty( DFF_Prop_txflTextFlow ) ) + { + auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF; + switch( eTextFlow ) + { + case mso_txflTtoBA : /* #68110# */ // Top to Bottom @-font, oben -> unten + case mso_txflTtoBN : // Top to Bottom non-@, oben -> unten + case mso_txflVertN : // Vertical, non-@, oben -> unten + bVerticalText = true; // nTextRotationAngle += 27000; + break; + default: break; + } + } + sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 ); + if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) ) + bVerticalText = !bVerticalText; + + if ( bVerticalText ) + { + eTHA = SDRTEXTHORZADJUST_CENTER; + + // read text anchor + sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop ); + + switch( eTextAnchor ) + { + case mso_anchorTop: + case mso_anchorTopCentered: + case mso_anchorTopBaseline: + case mso_anchorTopCenteredBaseline: + eTHA = SDRTEXTHORZADJUST_RIGHT; + break; + + case mso_anchorMiddle : + case mso_anchorMiddleCentered: + eTHA = SDRTEXTHORZADJUST_CENTER; + break; + + case mso_anchorBottom: + case mso_anchorBottomCentered: + case mso_anchorBottomBaseline: + case mso_anchorBottomCenteredBaseline: + eTHA = SDRTEXTHORZADJUST_LEFT; + break; + } + // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction + switch ( eTextAnchor ) + { + case mso_anchorTopCentered : + case mso_anchorMiddleCentered : + case mso_anchorBottomCentered : + case mso_anchorTopCenteredBaseline: + case mso_anchorBottomCenteredBaseline: + eTVA = SDRTEXTVERTADJUST_CENTER; + break; + + default : + eTVA = SDRTEXTVERTADJUST_TOP; + break; + } + } + else + { + eTVA = SDRTEXTVERTADJUST_CENTER; + + // read text anchor + sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop ); + + switch( eTextAnchor ) + { + case mso_anchorTop: + case mso_anchorTopCentered: + case mso_anchorTopBaseline: + case mso_anchorTopCenteredBaseline: + eTVA = SDRTEXTVERTADJUST_TOP; + break; + + case mso_anchorMiddle : + case mso_anchorMiddleCentered: + eTVA = SDRTEXTVERTADJUST_CENTER; + break; + + case mso_anchorBottom: + case mso_anchorBottomCentered: + case mso_anchorBottomBaseline: + case mso_anchorBottomCenteredBaseline: + eTVA = SDRTEXTVERTADJUST_BOTTOM; + break; + } + // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction + switch ( eTextAnchor ) + { + case mso_anchorTopCentered : + case mso_anchorMiddleCentered : + case mso_anchorBottomCentered : + case mso_anchorTopCenteredBaseline: + case mso_anchorBottomCenteredBaseline: + eTHA = SDRTEXTHORZADJUST_CENTER; // the text has to be displayed using the full width; + break; + + default : + eTHA = SDRTEXTHORZADJUST_LEFT; + break; + } + } + rSet.Put( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) ); + + rSet.Put( SdrTextVertAdjustItem( eTVA ) ); + rSet.Put( SdrTextHorzAdjustItem( eTHA ) ); + + rSet.Put( makeSdrTextLeftDistItem( nTextLeft ) ); + rSet.Put( makeSdrTextRightDistItem( nTextRight ) ); + rSet.Put( makeSdrTextUpperDistItem( nTextTop ) ); + rSet.Put( makeSdrTextLowerDistItem( nTextBottom ) ); + + rSet.Put( makeSdrTextWordWrapItem( GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone ) ); + rSet.Put( makeSdrTextAutoGrowHeightItem( ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0 ) ); +} + +void DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const +{ + + sal_uInt32 nAdjustmentsWhichNeedsToBeConverted = 0; + + + // creating SdrCustomShapeGeometryItem + + typedef std::vector< beans::PropertyValue > PropVec; + + // aPropVec will be filled with all PropertyValues + PropVec aPropVec; + PropertyValue aProp; + + + // "Type" property, including the predefined CustomShape type name + + aProp.Name = "Type"; + aProp.Value <<= EnhancedCustomShapeTypeNames::Get( rObjData.eShapeType ); + aPropVec.push_back( aProp ); + + + // "ViewBox" + + + sal_Int32 nCoordWidth = 21600; // needed to replace handle type center with absolute value + sal_Int32 nCoordHeight= 21600; + if ( IsProperty( DFF_Prop_geoLeft ) || IsProperty( DFF_Prop_geoTop ) || IsProperty( DFF_Prop_geoRight ) || IsProperty( DFF_Prop_geoBottom ) ) + { + css::awt::Rectangle aViewBox; + aViewBox.X = GetPropertyValue( DFF_Prop_geoLeft, 0 ); + aViewBox.Y = GetPropertyValue( DFF_Prop_geoTop, 0 ); + aViewBox.Width = nCoordWidth = o3tl::saturating_sub(GetPropertyValue(DFF_Prop_geoRight, 21600), aViewBox.X); + aViewBox.Height = nCoordHeight = o3tl::saturating_sub(GetPropertyValue(DFF_Prop_geoBottom, 21600), aViewBox.Y); + aProp.Name = "ViewBox"; + aProp.Value <<= aViewBox; + aPropVec.push_back( aProp ); + } + + // TextRotateAngle + + if ( IsProperty( DFF_Prop_txflTextFlow ) || IsProperty( DFF_Prop_cdirFont ) ) + { + sal_Int32 nTextRotateAngle = 0; + auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF; + + if ( eTextFlow == mso_txflBtoT ) // Bottom to Top non-@ + nTextRotateAngle += 90; + switch( GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 ) ) // SJ: mso_cdir90 and mso_cdir270 will be simulated by + { // activating vertical writing for the text objects + case mso_cdir90 : + { + if ( eTextFlow == mso_txflTtoBA ) + nTextRotateAngle -= 180; + } + break; + case mso_cdir180: nTextRotateAngle -= 180; break; + case mso_cdir270: + { + if ( eTextFlow != mso_txflTtoBA ) + nTextRotateAngle -= 180; + } + break; + default: break; + } + if ( nTextRotateAngle ) + { + double fTextRotateAngle = nTextRotateAngle; + aProp.Name = "TextRotateAngle"; + aProp.Value <<= fTextRotateAngle; + aPropVec.push_back( aProp ); + } + } + + // "Extrusion" PropertySequence element + + bool bExtrusionOn = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) != 0; + if ( bExtrusionOn ) + { + PropVec aExtrusionPropVec; + + // "Extrusion" + aProp.Name = "Extrusion"; + aProp.Value <<= bExtrusionOn; + aExtrusionPropVec.push_back( aProp ); + + // "Brightness" + // MS Office default 0x00004E20 16.16 FixedPoint, 20000/65536=0.30517, ODF default 33%. + // Thus must set value even if default. + double fBrightness = 20000.0; + if ( IsProperty( DFF_Prop_c3DAmbientIntensity ) ) + { + // Value must be in range 0.0 to 1.0 in MS Office binary specification, but larger + // values are in fact interpreted. + fBrightness = GetPropertyValue( DFF_Prop_c3DAmbientIntensity, 0 ); + } + fBrightness /= 655.36; + aProp.Name = "Brightness"; + aProp.Value <<= fBrightness; + aExtrusionPropVec.push_back( aProp ); + + // "Depth" in 1/100mm + if ( IsProperty( DFF_Prop_c3DExtrudeBackward ) || IsProperty( DFF_Prop_c3DExtrudeForward ) ) + { + double fBackDepth = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DExtrudeBackward, 1270 * 360 ))) / 360.0; + double fForeDepth = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DExtrudeForward, 0 ))) / 360.0; + double fDepth = fBackDepth + fForeDepth; + double fFraction = fDepth != 0.0 ? fForeDepth / fDepth : 0; + EnhancedCustomShapeParameterPair aDepthParaPair; + aDepthParaPair.First.Value <<= fDepth; + aDepthParaPair.First.Type = EnhancedCustomShapeParameterType::NORMAL; + aDepthParaPair.Second.Value <<= fFraction; + aDepthParaPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL; + aProp.Name = "Depth"; + aProp.Value <<= aDepthParaPair; + aExtrusionPropVec.push_back( aProp ); + } + // "Diffusion" + // ODF default is 0%, MS Office default is 100%. Thus must set value even if default. + double fDiffusion = 100; + if ( IsProperty( DFF_Prop_c3DDiffuseAmt ) ) + { + fDiffusion = static_cast(GetPropertyValue( DFF_Prop_c3DDiffuseAmt, 0 )); + fDiffusion /= 655.36; + } + aProp.Name = "Diffusion"; + aProp.Value <<= fDiffusion; + aExtrusionPropVec.push_back( aProp ); + + // "NumberOfLineSegments" + if ( IsProperty( DFF_Prop_c3DTolerance ) ) + { + aProp.Name = "NumberOfLineSegments"; + aProp.Value <<= static_cast(GetPropertyValue( DFF_Prop_c3DTolerance, 0 )); + aExtrusionPropVec.push_back( aProp ); + } + // "LightFace" + bool bExtrusionLightFace = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 1 ) != 0; + aProp.Name = "LightFace"; + aProp.Value <<= bExtrusionLightFace; + aExtrusionPropVec.push_back( aProp ); + // "FirstLightHarsh" + bool bExtrusionFirstLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 2 ) != 0; + aProp.Name = "FirstLightHarsh"; + aProp.Value <<= bExtrusionFirstLightHarsh; + aExtrusionPropVec.push_back( aProp ); + // "SecondLightHarsh" + bool bExtrusionSecondLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 1 ) != 0; + aProp.Name = "SecondLightHarsh"; + aProp.Value <<= bExtrusionSecondLightHarsh; + aExtrusionPropVec.push_back( aProp ); + + // "FirstLightLevel" + // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%. + // Thus must set value even if default. + double fFirstLightLevel = 38000.0; + if ( IsProperty( DFF_Prop_c3DKeyIntensity ) ) + { + // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here. + fFirstLightLevel = static_cast(GetPropertyValue( DFF_Prop_c3DKeyIntensity, 0 )); + } + fFirstLightLevel /= 655.36; + aProp.Name = "FirstLightLevel"; + aProp.Value <<= fFirstLightLevel; + aExtrusionPropVec.push_back( aProp ); + + // "SecondLightLevel" + // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%. + // Thus must set value even if default. + double fSecondLightLevel = 38000.0; + if ( IsProperty( DFF_Prop_c3DFillIntensity ) ) + { + // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here. + fSecondLightLevel = static_cast(GetPropertyValue( DFF_Prop_c3DFillIntensity, 0 )); + } + fSecondLightLevel /= 655.36; + aProp.Name = "SecondLightLevel"; + aProp.Value <<= fSecondLightLevel; + aExtrusionPropVec.push_back( aProp ); + + // "FirstLightDirection" + if ( IsProperty( DFF_Prop_c3DKeyX ) || IsProperty( DFF_Prop_c3DKeyY ) || IsProperty( DFF_Prop_c3DKeyZ ) ) + { + double fLightX = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DKeyX, 50000 ))); + double fLightY = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DKeyY, 0 ))); + double fLightZ = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DKeyZ, 10000 ))); + css::drawing::Direction3D aExtrusionFirstLightDirection( fLightX, fLightY, fLightZ ); + aProp.Name = "FirstLightDirection"; + aProp.Value <<= aExtrusionFirstLightDirection; + aExtrusionPropVec.push_back( aProp ); + } + // "SecondLightDirection" + if ( IsProperty( DFF_Prop_c3DFillX ) || IsProperty( DFF_Prop_c3DFillY ) || IsProperty( DFF_Prop_c3DFillZ ) ) + { + double fLight2X = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DFillX, sal_uInt32(-50000) ))); + double fLight2Y = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DFillY, 0 ))); + double fLight2Z = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DFillZ, 10000 ))); + css::drawing::Direction3D aExtrusionSecondLightDirection( fLight2X, fLight2Y, fLight2Z ); + aProp.Name = "SecondLightDirection"; + aProp.Value <<= aExtrusionSecondLightDirection; + aExtrusionPropVec.push_back( aProp ); + } + + // "Metal" + bool bExtrusionMetal = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 4 ) != 0; + aProp.Name = "Metal"; + aProp.Value <<= bExtrusionMetal; + aExtrusionPropVec.push_back( aProp ); + aProp.Name = "MetalType"; + aProp.Value <<= css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible; + aExtrusionPropVec.push_back(aProp); + + // "ShadeMode" + if ( IsProperty( DFF_Prop_c3DRenderMode ) ) + { + sal_uInt32 nExtrusionRenderMode = GetPropertyValue( DFF_Prop_c3DRenderMode, 0 ); + css::drawing::ShadeMode eExtrusionShadeMode( css::drawing::ShadeMode_FLAT ); + if ( nExtrusionRenderMode == mso_Wireframe ) + eExtrusionShadeMode = css::drawing::ShadeMode_DRAFT; + + aProp.Name = "ShadeMode"; + aProp.Value <<= eExtrusionShadeMode; + aExtrusionPropVec.push_back( aProp ); + } + // "RotateAngle" in Degree + if ( IsProperty( DFF_Prop_c3DXRotationAngle ) || IsProperty( DFF_Prop_c3DYRotationAngle ) ) + { + double fAngleX = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DXRotationAngle, 0 ))) / 65536.0; + double fAngleY = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DYRotationAngle, 0 ))) / 65536.0; + EnhancedCustomShapeParameterPair aRotateAnglePair; + aRotateAnglePair.First.Value <<= fAngleX; + aRotateAnglePair.First.Type = EnhancedCustomShapeParameterType::NORMAL; + aRotateAnglePair.Second.Value <<= fAngleY; + aRotateAnglePair.Second.Type = EnhancedCustomShapeParameterType::NORMAL; + aProp.Name = "RotateAngle"; + aProp.Value <<= aRotateAnglePair; + aExtrusionPropVec.push_back( aProp ); + } + + // "AutoRotationCenter" + if ( ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 8 ) == 0 ) + { + // "RotationCenter" + if ( IsProperty( DFF_Prop_c3DRotationCenterX ) || IsProperty( DFF_Prop_c3DRotationCenterY ) || IsProperty( DFF_Prop_c3DRotationCenterZ ) ) + { + // tdf#145904 X- and Y-component is fraction, Z-component in EMU + css::drawing::Direction3D aRotationCenter( + static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DRotationCenterX, 0 ))) / 65536.0, + static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DRotationCenterY, 0 ))) / 65536.0, + static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DRotationCenterZ, 0 ))) / 360.0 ); + + aProp.Name = "RotationCenter"; + aProp.Value <<= aRotationCenter; + aExtrusionPropVec.push_back( aProp ); + } + } + // "Shininess" + // MS Office default 5, ODF default 50%. + if ( IsProperty( DFF_Prop_c3DShininess ) ) + { + double fShininess = static_cast(GetPropertyValue( DFF_Prop_c3DShininess, 0 )); + fShininess *= 10.0; // error in [MS ODRAW] (2021), type is not FixedPoint but long. + aProp.Name = "Shininess"; + aProp.Value <<= fShininess; + aExtrusionPropVec.push_back( aProp ); + } + + // "Skew" + // MS Office angle file value is 16.16 FixedPoint, default 0xFF790000, + // -8847360/65536=-135, ODF default 45. Thus must set value even if default. + double fSkewAngle = -135.0; + // MS Office amount file value is signed integer in range 0xFFFFFF9C to 0x00000064, + // default 0x00000032, ODF default 50.0 + double fSkewAmount = 50.0; + if ( IsProperty( DFF_Prop_c3DSkewAmount ) || IsProperty( DFF_Prop_c3DSkewAngle ) ) + { + fSkewAmount = static_cast(GetPropertyValue( DFF_Prop_c3DSkewAmount, 50 )); + fSkewAngle = static_cast(GetPropertyValue( DFF_Prop_c3DSkewAngle, sal::static_int_cast< sal_uInt32 >(-135 * 65536) )); + fSkewAngle /= 65536.0; + } + EnhancedCustomShapeParameterPair aSkewPair; + aSkewPair.First.Value <<= fSkewAmount; + aSkewPair.First.Type = EnhancedCustomShapeParameterType::NORMAL; + aSkewPair.Second.Value <<= fSkewAngle; + aSkewPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL; + aProp.Name = "Skew"; + aProp.Value <<= aSkewPair; + aExtrusionPropVec.push_back( aProp ); + + // "Specularity" + // Type Fixed point 16.16, percent in API + if ( IsProperty( DFF_Prop_c3DSpecularAmt ) ) + { + double fSpecularity = static_cast(GetPropertyValue( DFF_Prop_c3DSpecularAmt, 0 )); + fSpecularity /= 655.36; + aProp.Name = "Specularity"; + aProp.Value <<= fSpecularity; + aExtrusionPropVec.push_back( aProp ); + } + // "ProjectionMode" + ProjectionMode eProjectionMode = (GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 4) ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE; + aProp.Name = "ProjectionMode"; + aProp.Value <<= eProjectionMode; + aExtrusionPropVec.push_back( aProp ); + + // "ViewPoint" in 1/100mm + // MS Office default 1250000 EMU=3472.222 Hmm, ODF default 3.5cm + // Thus must set value even if default. + double fViewX = 1250000.0 / 360.0; + double fViewY = -1250000.0 / 360.0;; + double fViewZ = 9000000.0 / 360.0; + if ( IsProperty( DFF_Prop_c3DXViewpoint ) || IsProperty( DFF_Prop_c3DYViewpoint ) || IsProperty( DFF_Prop_c3DZViewpoint ) ) + { + fViewX = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DXViewpoint, 1250000 ))) / 360.0; + fViewY = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DYViewpoint, sal_uInt32(-1250000) )))/ 360.0; + fViewZ = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DZViewpoint, 9000000 ))) / 360.0; + } + css::drawing::Position3D aExtrusionViewPoint( fViewX, fViewY, fViewZ ); + aProp.Name = "ViewPoint"; + aProp.Value <<= aExtrusionViewPoint; + aExtrusionPropVec.push_back( aProp ); + + // "Origin" + if ( IsProperty( DFF_Prop_c3DOriginX ) || IsProperty( DFF_Prop_c3DOriginY ) ) + { + double fOriginX = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DOriginX, 32768 ))); + double fOriginY = static_cast(static_cast(GetPropertyValue( DFF_Prop_c3DOriginY, sal_uInt32(-32768) ))); + fOriginX /= 65536; + fOriginY /= 65536; + EnhancedCustomShapeParameterPair aOriginPair; + aOriginPair.First.Value <<= fOriginX; + aOriginPair.First.Type = EnhancedCustomShapeParameterType::NORMAL; + aOriginPair.Second.Value <<= fOriginY; + aOriginPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL; + aProp.Name = "Origin"; + aProp.Value <<= aOriginPair; + aExtrusionPropVec.push_back( aProp ); + } + // "ExtrusionColor" + bool bExtrusionColor = IsProperty( DFF_Prop_c3DExtrusionColor ); // ( GetPropertyValue( DFF_Prop_fc3DLightFace ) & 2 ) != 0; + aProp.Name = "Color"; + aProp.Value <<= bExtrusionColor; + aExtrusionPropVec.push_back( aProp ); + if ( IsProperty( DFF_Prop_c3DExtrusionColor ) ) + rSet.Put( XSecondaryFillColorItem( OUString(), rManager.MSO_CLR_ToColor( + GetPropertyValue( DFF_Prop_c3DExtrusionColor, 0 ), DFF_Prop_c3DExtrusionColor ) ) ); + // pushing the whole Extrusion element + aProp.Name = "Extrusion"; + aProp.Value <<= comphelper::containerToSequence(aExtrusionPropVec); + aPropVec.push_back( aProp ); + } + + + // "Equations" PropertySequence element + + if ( IsProperty( DFF_Prop_pFormulas ) ) + { + sal_uInt16 nNumElem = 0; + + if ( SeekToContent( DFF_Prop_pFormulas, rIn ) ) + { + sal_uInt16 nNumElemMem = 0; + sal_uInt16 nElemSize = 8; + rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize ); + } + if ( nNumElem <= 128 ) + { + uno::Sequence< OUString > aEquations( nNumElem ); + for ( auto& rEquation : asNonConstRange(aEquations) ) + { + sal_Int16 nP1(0), nP2(0), nP3(0); + sal_uInt16 nFlags(0); + rIn.ReadUInt16( nFlags ).ReadInt16( nP1 ).ReadInt16( nP2 ).ReadInt16( nP3 ); + rEquation = EnhancedCustomShape2d::GetEquation( nFlags, nP1, nP2, nP3 ); + } + // pushing the whole Equations element + aProp.Name = "Equations"; + aProp.Value <<= aEquations; + aPropVec.push_back( aProp ); + } + } + + + // "Handles" PropertySequence element + + if ( IsProperty( DFF_Prop_Handles ) ) + { + sal_uInt16 nNumElem = 0; + sal_uInt16 nElemSize = 36; + + if ( SeekToContent( DFF_Prop_Handles, rIn ) ) + { + sal_uInt16 nNumElemMem = 0; + rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize ); + } + bool bImport = false; + if (nElemSize == 36) + { + //sanity check that the stream is long enough to fulfill nNumElem * nElemSize; + bImport = rIn.remainingSize() / nElemSize >= nNumElem; + } + if (bImport) + { + uno::Sequence< beans::PropertyValues > aHandles( nNumElem ); + auto aHandlesRange = asNonConstRange(aHandles); + for (sal_uInt32 i = 0; i < nNumElem; ++i) + { + PropVec aHandlePropVec; + sal_uInt32 nFlagsTmp(0); + sal_Int32 nPositionX(0), nPositionY(0), nCenterX(0), nCenterY(0), nRangeXMin(0), nRangeXMax(0), nRangeYMin(0), nRangeYMax(0); + rIn.ReadUInt32( nFlagsTmp ) + .ReadInt32( nPositionX ) + .ReadInt32( nPositionY ) + .ReadInt32( nCenterX ) + .ReadInt32( nCenterY ) + .ReadInt32( nRangeXMin ) + .ReadInt32( nRangeXMax ) + .ReadInt32( nRangeYMin ) + .ReadInt32( nRangeYMax ); + SvxMSDffHandleFlags nFlags = static_cast(nFlagsTmp); + if ( nPositionX == 2 ) // replacing center position with absolute value + nPositionX = nCoordWidth / 2; + if ( nPositionY == 2 ) + nPositionY = nCoordHeight / 2; + EnhancedCustomShapeParameterPair aPosition; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, nPositionX, true, true ); + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, nPositionY, true, false ); + aProp.Name = "Position"; + aProp.Value <<= aPosition; + aHandlePropVec.push_back( aProp ); + + if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X ) + { + aProp.Name = "MirroredX"; + aProp.Value <<= true; + aHandlePropVec.push_back( aProp ); + } + if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y ) + { + aProp.Name = "MirroredY"; + aProp.Value <<= true; + aHandlePropVec.push_back( aProp ); + } + if ( nFlags & SvxMSDffHandleFlags::SWITCHED ) + { + aProp.Name = "Switched"; + aProp.Value <<= true; + aHandlePropVec.push_back( aProp ); + } + if ( nFlags & SvxMSDffHandleFlags::POLAR ) + { + if ( nCenterX == 2 ) + nCenterX = nCoordWidth / 2; + if ( nCenterY == 2 ) + nCenterY = nCoordHeight / 2; + if ((nPositionY >= 0x256 || nPositionY <= 0x107) && i < sizeof(sal_uInt32) * 8) // position y + nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i ); + EnhancedCustomShapeParameterPair aPolar; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true ); + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false ); + aProp.Name = "Polar"; + aProp.Value <<= aPolar; + aHandlePropVec.push_back( aProp ); + } + if ( nFlags & SvxMSDffHandleFlags::MAP ) + { + if ( nCenterX == 2 ) + nCenterX = nCoordWidth / 2; + if ( nCenterY == 2 ) + nCenterY = nCoordHeight / 2; + EnhancedCustomShapeParameterPair aMap; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true ); + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false ); + aProp.Name = "Map"; + aProp.Value <<= aMap; + aHandlePropVec.push_back( aProp ); + } + if ( nFlags & SvxMSDffHandleFlags::RANGE ) + { + if ( static_cast(nRangeXMin) != 0x80000000 ) + { + if ( nRangeXMin == 2 ) + nRangeXMin = nCoordWidth / 2; + EnhancedCustomShapeParameter aRangeXMinimum; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, nRangeXMin, + bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true ); + aProp.Name = "RangeXMinimum"; + aProp.Value <<= aRangeXMinimum; + aHandlePropVec.push_back( aProp ); + } + if ( static_cast(nRangeXMax) != 0x7fffffff ) + { + if ( nRangeXMax == 2 ) + nRangeXMax = nCoordWidth / 2; + EnhancedCustomShapeParameter aRangeXMaximum; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, nRangeXMax, + bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false ); + aProp.Name = "RangeXMaximum"; + aProp.Value <<= aRangeXMaximum; + aHandlePropVec.push_back( aProp ); + } + if ( static_cast(nRangeYMin) != 0x80000000 ) + { + if ( nRangeYMin == 2 ) + nRangeYMin = nCoordHeight / 2; + EnhancedCustomShapeParameter aRangeYMinimum; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, nRangeYMin, + bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL ), true ); + aProp.Name = "RangeYMinimum"; + aProp.Value <<= aRangeYMinimum; + aHandlePropVec.push_back( aProp ); + } + if ( static_cast(nRangeYMax) != 0x7fffffff ) + { + if ( nRangeYMax == 2 ) + nRangeYMax = nCoordHeight / 2; + EnhancedCustomShapeParameter aRangeYMaximum; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, nRangeYMax, + bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL ), false ); + aProp.Name = "RangeYMaximum"; + aProp.Value <<= aRangeYMaximum; + aHandlePropVec.push_back( aProp ); + } + } + if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE ) + { + if ( static_cast(nRangeXMin) != 0x7fffffff ) + { + if ( nRangeXMin == 2 ) + nRangeXMin = nCoordWidth / 2; + EnhancedCustomShapeParameter aRadiusRangeMinimum; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, nRangeXMin, + bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true ); + aProp.Name = "RadiusRangeMinimum"; + aProp.Value <<= aRadiusRangeMinimum; + aHandlePropVec.push_back( aProp ); + } + if ( static_cast(nRangeXMax) != 0x80000000 ) + { + if ( nRangeXMax == 2 ) + nRangeXMax = nCoordWidth / 2; + EnhancedCustomShapeParameter aRadiusRangeMaximum; + EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, nRangeXMax, + bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false ); + aProp.Name = "RadiusRangeMaximum"; + aProp.Value <<= aRadiusRangeMaximum; + aHandlePropVec.push_back( aProp ); + } + } + if ( !aHandlePropVec.empty() ) + { + aHandlesRange[ i ] = comphelper::containerToSequence(aHandlePropVec); + } + } + // pushing the whole Handles element + aProp.Name = "Handles"; + aProp.Value <<= aHandles; + aPropVec.push_back( aProp ); + } + } + else + { + const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( rObjData.eShapeType ); + if ( pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles ) + { + sal_uInt32 i, nCnt = pDefCustomShape->nHandles; + const SvxMSDffHandle* pData = pDefCustomShape->pHandles; + for ( i = 0; i < nCnt; i++, pData++ ) + { + if ( pData->nFlags & SvxMSDffHandleFlags::POLAR ) + { + if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) ) + nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i ); + } + } + } + } + + // "Path" PropertySequence element + + { + PropVec aPathPropVec; + + // "Path/ExtrusionAllowed" + if ( IsHardAttribute( DFF_Prop_f3DOK ) ) + { + bool bExtrusionAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 16 ) != 0; + aProp.Name = "ExtrusionAllowed"; + aProp.Value <<= bExtrusionAllowed; + aPathPropVec.push_back( aProp ); + } + // "Path/ConcentricGradientFillAllowed" + if ( IsHardAttribute( DFF_Prop_fFillShadeShapeOK ) ) + { + bool bConcentricGradientFillAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 2 ) != 0; + aProp.Name = "ConcentricGradientFillAllowed"; + aProp.Value <<= bConcentricGradientFillAllowed; + aPathPropVec.push_back( aProp ); + } + // "Path/TextPathAllowed" + if ( IsHardAttribute( DFF_Prop_fGtextOK ) || ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) ) + { + bool bTextPathAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 4 ) != 0; + aProp.Name = "TextPathAllowed"; + aProp.Value <<= bTextPathAllowed; + aPathPropVec.push_back( aProp ); + } + // Path/Coordinates + if ( IsProperty( DFF_Prop_pVertices ) ) + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates; + sal_uInt16 nNumElemVert = 0; + sal_uInt16 nElemSizeVert = 8; + + if ( SeekToContent( DFF_Prop_pVertices, rIn ) ) + { + sal_uInt16 nNumElemMemVert = 0; + rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert ); + // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4 + // low-order bytes are recorded + if (nElemSizeVert == 0xFFF0) + nElemSizeVert = 4; + } + //sanity check that the stream is long enough to fulfill nNumElem * nElemSize; + bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert); + if (bImport) + { + aCoordinates.realloc( nNumElemVert ); + for (auto& rCoordinate : asNonConstRange(aCoordinates)) + { + sal_Int32 nX(0), nY(0); + + if ( nElemSizeVert == 8 ) + { + rIn.ReadInt32( nX ) + .ReadInt32( nY ); + } + else + { + // The mso-spt19 (arc) uses this. But it needs unsigned integer. I don't + // know if other shape types also need it. They can be added as necessary. + bool bNeedsUnsigned = rObjData.eShapeType == mso_sptArc; + if (bNeedsUnsigned) + { + sal_uInt16 nTmpA(0), nTmpB(0); + rIn.ReadUInt16(nTmpA) + .ReadUInt16(nTmpB); + nX = nTmpA; + nY = nTmpB; + } + else + { + sal_Int16 nTmpA(0), nTmpB(0); + rIn.ReadInt16( nTmpA ) + .ReadInt16( nTmpB ); + nX = nTmpA; + nY = nTmpB; + } + } + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.First, nX ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.Second, nY ); + } + } + aProp.Name = "Coordinates"; + aProp.Value <<= aCoordinates; + aPathPropVec.push_back( aProp ); + } + // Path/Segments + if ( IsProperty( DFF_Prop_pSegmentInfo ) ) + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments; + + sal_uInt16 nNumElemSeg = 0; + + if ( SeekToContent( DFF_Prop_pSegmentInfo, rIn ) ) + { + sal_uInt16 nNumElemMemSeg = 0; + sal_uInt16 nElemSizeSeg = 2; + rIn.ReadUInt16( nNumElemSeg ).ReadUInt16( nNumElemMemSeg ).ReadUInt16( nElemSizeSeg ); + } + sal_uInt64 nMaxEntriesPossible = rIn.remainingSize() / sizeof(sal_uInt16); + if (nNumElemSeg > nMaxEntriesPossible) + { + SAL_WARN("filter.ms", "NumElem list is longer than remaining bytes, ppt or parser is wrong"); + nNumElemSeg = nMaxEntriesPossible; + } + if ( nNumElemSeg ) + { + aSegments.realloc( nNumElemSeg ); + for (auto& rSegment : asNonConstRange(aSegments)) + { + sal_uInt16 nTmp(0); + rIn.ReadUInt16( nTmp ); + sal_Int16 nCommand = EnhancedCustomShapeSegmentCommand::UNKNOWN; + sal_Int16 nCnt = static_cast( nTmp & 0x1fff );//Last 13 bits for segment points number + switch( nTmp >> 13 )//First 3 bits for command type + { + case 0x0: + nCommand = EnhancedCustomShapeSegmentCommand::LINETO; + if ( !nCnt ) nCnt = 1; + break; + case 0x1: + nCommand = EnhancedCustomShapeSegmentCommand::CURVETO; + if ( !nCnt ) nCnt = 1; + break; + case 0x2: + nCommand = EnhancedCustomShapeSegmentCommand::MOVETO; + if ( !nCnt ) nCnt = 1; + break; + case 0x3: + nCommand = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH; + nCnt = 0; + break; + case 0x4: + nCommand = EnhancedCustomShapeSegmentCommand::ENDSUBPATH; + nCnt = 0; + break; + case 0x5: + case 0x6: + { + switch ( ( nTmp >> 8 ) & 0x1f )//5 bits next to command type is for path escape type + { + case 0x0: + { + //It is msopathEscapeExtension which is transformed into LINETO. + //If issue happens, I think this part can be comment so that it will be taken as unknown command. + //When export, origin data will be export without any change. + nCommand = EnhancedCustomShapeSegmentCommand::LINETO; + if ( !nCnt ) + nCnt = 1; + } + break; + case 0x1: + { + nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO; + nCnt = ( nTmp & 0xff ) / 3; + } + break; + case 0x2: + { + nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE; + nCnt = ( nTmp & 0xff ) / 3; + } + break; + case 0x3: + { + nCommand = EnhancedCustomShapeSegmentCommand::ARCTO; + nCnt = ( nTmp & 0xff ) >> 2; + }; + break; + case 0x4: + { + nCommand = EnhancedCustomShapeSegmentCommand::ARC; + nCnt = ( nTmp & 0xff ) >> 2; + } + break; + case 0x5: + { + nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO; + nCnt = ( nTmp & 0xff ) >> 2; + } + break; + case 0x6: + { + nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC; + nCnt = ( nTmp & 0xff ) >> 2; + } + break; + case 0x7: + { + nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX; + nCnt = nTmp & 0xff; + } + break; + case 0x8: + { + nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY; + nCnt = nTmp & 0xff; + } + break; + case 0xa: nCommand = EnhancedCustomShapeSegmentCommand::NOFILL; nCnt = 0; break; + case 0xb: nCommand = EnhancedCustomShapeSegmentCommand::NOSTROKE; nCnt = 0; break; + } + } + break; + } + // if the command is unknown, we will store all the data in nCnt, so it will be possible to export without loss + if ( nCommand == EnhancedCustomShapeSegmentCommand::UNKNOWN ) + nCnt = static_cast(nTmp); + rSegment.Command = nCommand; + rSegment.Count = nCnt; + } + } + aProp.Name = "Segments"; + aProp.Value <<= aSegments; + aPathPropVec.push_back( aProp ); + } + // Path/StretchX + if ( IsProperty( DFF_Prop_stretchPointX ) ) + { + sal_Int32 nStretchX = GetPropertyValue( DFF_Prop_stretchPointX, 0 ); + aProp.Name = "StretchX"; + aProp.Value <<= nStretchX; + aPathPropVec.push_back( aProp ); + } + // Path/StretchX + if ( IsProperty( DFF_Prop_stretchPointY ) ) + { + sal_Int32 nStretchY = GetPropertyValue( DFF_Prop_stretchPointY, 0 ); + aProp.Name = "StretchY"; + aProp.Value <<= nStretchY; + aPathPropVec.push_back( aProp ); + } + // Path/TextFrames + if ( IsProperty( DFF_Prop_textRectangles ) ) + { + sal_uInt16 nNumElem = 0; + sal_uInt16 nElemSize = 16; + + if ( SeekToContent( DFF_Prop_textRectangles, rIn ) ) + { + sal_uInt16 nNumElemMem = 0; + rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize ); + } + bool bImport = false; + if (nElemSize == 16) + { + //sanity check that the stream is long enough to fulfill nNumElem * nElemSize; + bImport = rIn.remainingSize() / nElemSize >= nNumElem; + } + if (bImport) + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrames( nNumElem ); + for (auto& rTextFrame : asNonConstRange(aTextFrames)) + { + sal_Int32 nLeft(0), nTop(0), nRight(0), nBottom(0); + + rIn.ReadInt32( nLeft ) + .ReadInt32( nTop ) + .ReadInt32( nRight ) + .ReadInt32( nBottom ); + + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.First, nLeft ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.Second, nTop ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.First, nRight ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.Second, nBottom); + } + aProp.Name = "TextFrames"; + aProp.Value <<= aTextFrames; + aPathPropVec.push_back( aProp ); + } + } + //Path/GluePoints + if ( IsProperty( DFF_Prop_connectorPoints ) ) + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints; + sal_uInt16 nNumElemVert = 0; + sal_uInt16 nElemSizeVert = 8; + + if ( SeekToContent( DFF_Prop_connectorPoints, rIn ) ) + { + sal_uInt16 nNumElemMemVert = 0; + rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert ); + // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4 + // low-order bytes are recorded + if (nElemSizeVert == 0xFFF0) + nElemSizeVert = 4; + } + + // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert; + bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert); + if (bImport) + { + aGluePoints.realloc( nNumElemVert ); + for (auto& rGluePoint : asNonConstRange(aGluePoints)) + { + sal_Int32 nX(0), nY(0); + if ( nElemSizeVert == 8 ) + { + rIn.ReadInt32( nX ) + .ReadInt32( nY ); + } + else + { + sal_Int16 nTmpA(0), nTmpB(0); + + rIn.ReadInt16( nTmpA ) + .ReadInt16( nTmpB ); + + nX = nTmpA; + nY = nTmpB; + } + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.First, nX ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.Second, nY ); + } + } + aProp.Name = "GluePoints"; + aProp.Value <<= aGluePoints; + aPathPropVec.push_back( aProp ); + } + if ( IsProperty( DFF_Prop_connectorType ) ) + { + sal_Int16 nGluePointType = static_cast(GetPropertyValue( DFF_Prop_connectorType, 0 )); + aProp.Name = "GluePointType"; + aProp.Value <<= nGluePointType; + aPathPropVec.push_back( aProp ); + } + // pushing the whole Path element + if ( !aPathPropVec.empty() ) + { + aProp.Name = "Path"; + aProp.Value <<= comphelper::containerToSequence(aPathPropVec); + aPropVec.push_back( aProp ); + } + } + + // "TextPath" PropertySequence element + + bool bTextPathOn = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) != 0; + if ( bTextPathOn ) + { + PropVec aTextPathPropVec; + + // TextPath + aProp.Name = "TextPath"; + aProp.Value <<= bTextPathOn; + aTextPathPropVec.push_back( aProp ); + + // TextPathMode + bool bTextPathFitPath = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x100 ) != 0; + + bool bTextPathFitShape; + if ( IsHardAttribute( DFF_Prop_gtextFStretch ) ) + bTextPathFitShape = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x400 ) != 0; + else + { + bTextPathFitShape = true; + switch( rObjData.eShapeType ) + { + case mso_sptTextArchUpCurve : + case mso_sptTextArchDownCurve : + case mso_sptTextCircleCurve : + case mso_sptTextButtonCurve : + bTextPathFitShape = false; + break; + default : break; + } + } + EnhancedCustomShapeTextPathMode eTextPathMode( EnhancedCustomShapeTextPathMode_NORMAL ); + if ( bTextPathFitShape ) + eTextPathMode = EnhancedCustomShapeTextPathMode_SHAPE; + else if ( bTextPathFitPath ) + eTextPathMode = EnhancedCustomShapeTextPathMode_PATH; + aProp.Name = "TextPathMode"; + aProp.Value <<= eTextPathMode; + aTextPathPropVec.push_back( aProp ); + + // ScaleX + bool bTextPathScaleX = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x40 ) != 0; + aProp.Name = "ScaleX"; + aProp.Value <<= bTextPathScaleX; + aTextPathPropVec.push_back( aProp ); + // SameLetterHeights + bool bSameLetterHeight = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x80 ) != 0; + aProp.Name = "SameLetterHeights"; + aProp.Value <<= bSameLetterHeight; + aTextPathPropVec.push_back( aProp ); + + // pushing the whole TextPath element + aProp.Name = "TextPath"; + aProp.Value <<= comphelper::containerToSequence(aTextPathPropVec); + aPropVec.push_back( aProp ); + } + + // "AdjustmentValues" // The AdjustmentValues are imported at last, because depending to the type of the + //////////////////////// handle (POLAR) we will convert the adjustment value from a fixed float to double + + // checking the last used adjustment handle, so we can determine how many handles are to allocate + sal_uInt32 i = DFF_Prop_adjust10Value; + while ( ( i >= DFF_Prop_adjustValue ) && !IsProperty( i ) ) + i--; + sal_Int32 nAdjustmentValues = ( i - DFF_Prop_adjustValue ) + 1; + if ( nAdjustmentValues ) + { + uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq( nAdjustmentValues ); + auto pAdjustmentSeq = aAdjustmentSeq.getArray(); + while( --nAdjustmentValues >= 0 ) + { + sal_Int32 nValue = 0; + beans::PropertyState ePropertyState = beans::PropertyState_DEFAULT_VALUE; + if ( IsProperty( i ) ) + { + nValue = GetPropertyValue( i, 0 ); + ePropertyState = beans::PropertyState_DIRECT_VALUE; + } + if ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << ( i - DFF_Prop_adjustValue ) ) ) + { + double fValue = nValue; + fValue /= 65536; + pAdjustmentSeq[ nAdjustmentValues ].Value <<= fValue; + } + else + pAdjustmentSeq[ nAdjustmentValues ].Value <<= nValue; + pAdjustmentSeq[ nAdjustmentValues ].State = ePropertyState; + i--; + } + aProp.Name = "AdjustmentValues"; + aProp.Value <<= aAdjustmentSeq; + aPropVec.push_back( aProp ); + } + + // creating the whole property set + rSet.Put( SdrCustomShapeGeometryItem( comphelper::containerToSequence(aPropVec) ) ); +} + +void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet ) const +{ + DffRecordHeader aHdTemp; + DffObjData aDffObjTemp( aHdTemp, tools::Rectangle(), 0 ); + ApplyAttributes( rIn, rSet, aDffObjTemp ); +} + +void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const +{ + bool bHasShadow = false; + bool bNonZeroShadowOffset = false; + + if ( IsProperty( DFF_Prop_gtextSize ) ) + rSet.Put( SvxFontHeightItem( rManager.ScalePt( GetPropertyValue( DFF_Prop_gtextSize, 0 ) ), 100, EE_CHAR_FONTHEIGHT ) ); + sal_uInt32 nFontAttributes = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ); + if ( nFontAttributes & 0x20 ) + rSet.Put( SvxWeightItem( (nFontAttributes & 0x20) ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) ); + if ( nFontAttributes & 0x10 ) + rSet.Put( SvxPostureItem( (nFontAttributes & 0x10) ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) ); + if ( nFontAttributes & 0x08 ) + rSet.Put( SvxUnderlineItem( (nFontAttributes & 0x08) ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) ); + if ( nFontAttributes & 0x40 ) + rSet.Put( SvxShadowedItem( (nFontAttributes & 0x40) != 0, EE_CHAR_SHADOW ) ); +// if ( nFontAttributes & 0x02 ) +// rSet.Put( SvxCaseMapItem( nFontAttributes & 0x02 ? SvxCaseMap::SmallCaps : SvxCaseMap::NotMapped ) ); + if ( nFontAttributes & 0x01 ) + rSet.Put( SvxCrossedOutItem( (nFontAttributes & 0x01) ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) ); + if ( IsProperty( DFF_Prop_fillColor ) ) + rSet.Put( XFillColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor ) ) ); + if ( IsProperty( DFF_Prop_shadowColor ) ) + rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_shadowColor, 0 ), DFF_Prop_shadowColor ) ) ); + else + { + //The default value for this property is 0x00808080 + rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( 0x00808080, DFF_Prop_shadowColor ) ) ); + } + if ( IsProperty( DFF_Prop_shadowOpacity ) ) + rSet.Put( makeSdrShadowTransparenceItem( static_cast( ( 0x10000 - GetPropertyValue( DFF_Prop_shadowOpacity, 0 ) ) / 655 ) ) ); + if ( IsProperty( DFF_Prop_shadowOffsetX ) ) + { + sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetX, 0 ) ); + rManager.ScaleEmu( nVal ); + rSet.Put( makeSdrShadowXDistItem( nVal ) ); + bNonZeroShadowOffset = ( nVal > 0 ); + } + if ( IsProperty( DFF_Prop_shadowOffsetY ) ) + { + sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetY, 0 ) ); + rManager.ScaleEmu( nVal ); + rSet.Put( makeSdrShadowYDistItem( nVal ) ); + bNonZeroShadowOffset = ( nVal > 0 ); + } + if ( IsProperty( DFF_Prop_fshadowObscured ) ) + { + bHasShadow = ( GetPropertyValue( DFF_Prop_fshadowObscured, 0 ) & 2 ) != 0; + if ( bHasShadow ) + { + if ( !IsProperty( DFF_Prop_shadowOffsetX ) ) + rSet.Put( makeSdrShadowXDistItem( 35 ) ); + if ( !IsProperty( DFF_Prop_shadowOffsetY ) ) + rSet.Put( makeSdrShadowYDistItem( 35 ) ); + } + } + if ( IsProperty( DFF_Prop_shadowType ) ) + { + auto eShadowType = GetPropertyValue(DFF_Prop_shadowType, 0); + if( eShadowType != mso_shadowOffset && !bNonZeroShadowOffset ) + { + //0.12" == 173 twip == 302 100mm + sal_uInt32 nDist = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip ? 173: 302; + rSet.Put( makeSdrShadowXDistItem( nDist ) ); + rSet.Put( makeSdrShadowYDistItem( nDist ) ); + } + } + if ( bHasShadow ) + { + static bool bCheckShadow(false); // loplugin:constvars:ignore + + // #i124477# Found no reason not to set shadow, esp. since it is applied to evtl. existing text + // and will lead to an error if in PPT someone used text and added the object shadow to the + // object carrying that text. I found no cases where this leads to problems (the old bugtracker + // task #160376# from sj is unfortunately no longer available). Keeping the code for now + // to allow easy fallback when this shows problems in the future + if(bCheckShadow) + { + // #160376# sj: activating shadow only if fill and or linestyle is used + // this is required because of the latest drawing layer core changes. + // #i104085# is related to this. + sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 )); + if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( rObjData.eShapeType )) + nLineFlags &= ~0x08; + sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 )); + if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType )) + nFillFlags &= ~0x10; + if ( nFillFlags & 0x10 ) + { + auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid); + switch( eMSO_FillType ) + { + case mso_fillSolid : + case mso_fillPattern : + case mso_fillTexture : + case mso_fillPicture : + case mso_fillShade : + case mso_fillShadeCenter : + case mso_fillShadeShape : + case mso_fillShadeScale : + case mso_fillShadeTitle : + break; + default: + nFillFlags &=~0x10; // no fillstyle used + break; + } + } + if ( ( ( nLineFlags & 0x08 ) == 0 ) && ( ( nFillFlags & 0x10 ) == 0 ) && ( rObjData.eShapeType != mso_sptPictureFrame )) // if there is no fillstyle and linestyle + bHasShadow = false; // we are turning shadow off. + } + + if ( bHasShadow ) + rSet.Put( makeSdrShadowItem( bHasShadow ) ); + } + ApplyLineAttributes( rSet, rObjData.eShapeType ); // #i28269# + ApplyFillAttributes( rIn, rSet, rObjData ); + if ( rObjData.eShapeType != mso_sptNil || IsProperty( DFF_Prop_pVertices ) ) + { + ApplyCustomShapeGeometryAttributes( rIn, rSet, rObjData ); + ApplyCustomShapeTextAttributes( rSet ); + if ( rManager.GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL ) + { + if ( mnFix16Angle || ( rObjData.nSpFlags & ShapeFlag::FlipV ) ) + CheckAndCorrectExcelTextRotation( rIn, rSet, rObjData ); + } + } +} + +void DffPropertyReader::CheckAndCorrectExcelTextRotation( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const +{ + bool bRotateTextWithShape = rObjData.bRotateTextWithShape; + if ( rObjData.bOpt2 ) // sj: #158494# is the second property set available ? if then we have to check the xml data of + { // the shape, because the textrotation of Excel 2003 and greater versions is stored there + // (upright property of the textbox) + if ( rManager.pSecPropSet->SeekToContent( DFF_Prop_metroBlob, rIn ) ) + { + sal_uInt32 nLen = rManager.pSecPropSet->GetPropertyValue( DFF_Prop_metroBlob, 0 ); + if ( nLen ) + { + css::uno::Sequence< sal_Int8 > aXMLDataSeq( nLen ); + rIn.ReadBytes(aXMLDataSeq.getArray(), nLen); + css::uno::Reference< css::io::XInputStream > xInputStream + ( new ::comphelper::SequenceInputStream( aXMLDataSeq ) ); + try + { + css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + css::uno::Reference< css::embed::XStorage > xStorage + ( ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( + OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, true ) ); + if ( xStorage.is() ) + { + css::uno::Reference< css::embed::XStorage > + xStorageDRS( xStorage->openStorageElement( "drs", css::embed::ElementModes::SEEKABLEREAD ) ); + if ( xStorageDRS.is() ) + { + css::uno::Reference< css::io::XStream > xShapeXMLStream( xStorageDRS->openStreamElement( "shapexml.xml", css::embed::ElementModes::SEEKABLEREAD ) ); + if ( xShapeXMLStream.is() ) + { + css::uno::Reference< css::io::XInputStream > xShapeXMLInputStream( xShapeXMLStream->getInputStream() ); + if ( xShapeXMLInputStream.is() ) + { + css::uno::Sequence< sal_Int8 > aSeq; + sal_Int32 nBytesRead = xShapeXMLInputStream->readBytes( aSeq, 0x7fffffff ); + if ( nBytesRead ) + { // for only one property I spare to use a XML parser at this point, this + // should be enhanced if needed + + bRotateTextWithShape = true; // using the correct xml default + const char* pArry = reinterpret_cast< char* >( aSeq.getArray() ); + const char* const pUpright = "upright="; + const char* pEnd = pArry + nBytesRead; + const char* pPtr = pArry; + while( ( pPtr + 12 ) < pEnd ) + { + if ( !memcmp( pUpright, pPtr, 8 ) ) + { + bRotateTextWithShape = ( pPtr[ 9 ] != '1' ) && ( pPtr[ 9 ] != 't' ); + break; + } + else + pPtr++; + } + } + } + } + } + } + } + catch( css::uno::Exception& ) + { + } + } + } + } + if ( bRotateTextWithShape ) + return; + + const css::uno::Any* pAny; + SdrCustomShapeGeometryItem aGeometryItem(rSet.Get( SDRATTR_CUSTOMSHAPE_GEOMETRY )); + static const OUStringLiteral sTextRotateAngle( u"TextRotateAngle" ); + pAny = aGeometryItem.GetPropertyValueByName( sTextRotateAngle ); + double fExtraTextRotateAngle = 0.0; + if ( pAny ) + *pAny >>= fExtraTextRotateAngle; + + if ( rManager.mnFix16Angle ) + fExtraTextRotateAngle += toDegrees(mnFix16Angle); + if ( rObjData.nSpFlags & ShapeFlag::FlipV ) + fExtraTextRotateAngle -= 180.0; + + css::beans::PropertyValue aTextRotateAngle; + aTextRotateAngle.Name = sTextRotateAngle; + aTextRotateAngle.Value <<= fExtraTextRotateAngle; + aGeometryItem.SetPropertyValue( aTextRotateAngle ); + rSet.Put( aGeometryItem ); +} + + +void DffPropertyReader::ImportGradientColor( SfxItemSet& aSet, sal_uInt32 eMSO_FillType, double dTrans , double dBackTrans) const +{ + //MS Focus prop will impact the start and end color position. And AOO does not + //support this prop. So need some swap for the two color to keep fidelity with AOO and MS shape. + //So below var is defined. + sal_Int32 nChgColors = 0; + sal_Int32 nAngleFix16 = GetPropertyValue( DFF_Prop_fillAngle, 0 ); + if(nAngleFix16 >= 0) + nChgColors ^= 1; + + //Translate a MS clockwise(+) or count clockwise angle(-) into an AOO count clock wise angle + Degree10 nAngle( 3600_deg10 - to( Fix16ToAngle(nAngleFix16) ) ); + //Make sure this angle belongs to 0~3600 + while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10; + while ( nAngle < 0_deg10 ) nAngle += 3600_deg10; + + //Rotate angle + if ( mbRotateGranientFillWithAngle ) + { + sal_Int32 nRotateAngle = GetPropertyValue( DFF_Prop_Rotation, 0 ); + //nAngle is a clockwise angle. If nRotateAngle is a clockwise angle, then gradient needs to be rotated a little less + //or it needs to be rotated a little more + nAngle -= to(Fix16ToAngle(nRotateAngle)); + } + while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10; + while ( nAngle < 0_deg10 ) nAngle += 3600_deg10; + + css::awt::GradientStyle eGrad = css::awt::GradientStyle_LINEAR; + + sal_Int32 nFocus = GetPropertyValue( DFF_Prop_fillFocus, 0 ); + if ( !nFocus ) + nChgColors ^= 1; + else if ( nFocus < 0 )//If it is a negative focus, the color will be swapped + { + nFocus = o3tl::saturating_toggle_sign(nFocus); + nChgColors ^= 1; + } + + if( nFocus > 40 && nFocus < 60 ) + { + eGrad = css::awt::GradientStyle_AXIAL;//A axial gradient other than linear + nChgColors ^= 1; + } + //if the type is linear or axial, just save focus to nFocusX and nFocusY for export + //Core function does no need them. They serve for rect gradient(CenterXY). + sal_uInt16 nFocusX = static_cast(nFocus); + sal_uInt16 nFocusY = static_cast(nFocus); + + switch( eMSO_FillType ) + { + case mso_fillShadeShape : + { + eGrad = css::awt::GradientStyle_RECT; + nFocusY = nFocusX = 50; + nChgColors ^= 1; + } + break; + case mso_fillShadeCenter : + { + eGrad = css::awt::GradientStyle_RECT; + //A MS fillTo prop specifies the relative position of the left boundary + //of the center rectangle in a concentric shaded fill. Use 100 or 0 to keep fidelity + nFocusX=(GetPropertyValue( DFF_Prop_fillToRight, 0 )==0x10000) ? 100 : 0; + nFocusY=(GetPropertyValue( DFF_Prop_fillToBottom,0 )==0x10000) ? 100 : 0; + nChgColors ^= 1; + } + break; + default: break; + } + + Color aCol1( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ) ); + Color aCol2( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ) ); + if ( nChgColors ) + { + //Swap start and end color + Color aZwi( aCol1 ); + aCol1 = aCol2; + aCol2 = aZwi; + //Swap two colors' transparency + double dTemp = dTrans; + dTrans = dBackTrans; + dBackTrans = dTemp; + } + + //Construct gradient item + XGradient aGrad( aCol2, aCol1, eGrad, nAngle, nFocusX, nFocusY ); + //Intensity has been merged into color. So here just set is as 100 + aGrad.SetStartIntens( 100 ); + aGrad.SetEndIntens( 100 ); + aSet.Put( XFillGradientItem( OUString(), aGrad ) ); + //Construct transparency item. This item can coordinate with both solid and gradient. + if ( dTrans < 1.0 || dBackTrans < 1.0 ) + { + sal_uInt8 nStartCol = static_cast( (1 - dTrans )* 255 ); + sal_uInt8 nEndCol = static_cast( ( 1- dBackTrans ) * 255 ); + aCol1 = Color(nStartCol, nStartCol, nStartCol); + aCol2 = Color(nEndCol, nEndCol, nEndCol); + + XGradient aGrad2( aCol2 , aCol1 , eGrad, nAngle, nFocusX, nFocusY ); + aSet.Put( XFillFloatTransparenceItem( OUString(), aGrad2 ) ); + } +} + + +//- Record Manager ---------------------------------------------------------- + + +DffRecordList::DffRecordList( DffRecordList* pList ) : + nCount ( 0 ), + nCurrent ( 0 ), + pPrev ( pList ) +{ + if ( pList ) + pList->pNext.reset( this ); +} + +DffRecordList::~DffRecordList() +{ +} + +DffRecordManager::DffRecordManager() : + DffRecordList ( nullptr ), + pCList ( static_cast(this) ) +{ +} + +DffRecordManager::DffRecordManager( SvStream& rIn ) : + DffRecordList ( nullptr ), + pCList ( static_cast(this) ) +{ + Consume( rIn ); +} + +void DffRecordManager::Consume( SvStream& rIn, sal_uInt32 nStOfs ) +{ + Clear(); + sal_uInt64 nOldPos = rIn.Tell(); + if ( !nStOfs ) + { + DffRecordHeader aHd; + bool bOk = ReadDffRecordHeader( rIn, aHd ); + if (bOk && aHd.nRecVer == DFF_PSFLAG_CONTAINER) + nStOfs = aHd.GetRecEndFilePos(); + } + if ( !nStOfs ) + return; + + pCList = this; + while ( pCList->pNext ) + pCList = pCList->pNext.get(); + while (rIn.good() && ( ( rIn.Tell() + 8 ) <= nStOfs )) + { + if ( pCList->nCount == DFF_RECORD_MANAGER_BUF_SIZE ) + pCList = new DffRecordList( pCList ); + if (!ReadDffRecordHeader(rIn, pCList->mHd[ pCList->nCount ])) + break; + bool bSeekSucceeded = pCList->mHd[ pCList->nCount++ ].SeekToEndOfRecord(rIn); + if (!bSeekSucceeded) + break; + } + rIn.Seek( nOldPos ); +} + +void DffRecordManager::Clear() +{ + pCList = this; + pNext.reset(); + nCurrent = 0; + nCount = 0; +} + +DffRecordHeader* DffRecordManager::Current() +{ + DffRecordHeader* pRet = nullptr; + if ( pCList->nCurrent < pCList->nCount ) + pRet = &pCList->mHd[ pCList->nCurrent ]; + return pRet; +} + +DffRecordHeader* DffRecordManager::First() +{ + DffRecordHeader* pRet = nullptr; + pCList = this; + if ( pCList->nCount ) + { + pCList->nCurrent = 0; + pRet = &pCList->mHd[ 0 ]; + } + return pRet; +} + +DffRecordHeader* DffRecordManager::Next() +{ + DffRecordHeader* pRet = nullptr; + sal_uInt32 nC = pCList->nCurrent + 1; + if ( nC < pCList->nCount ) + { + pCList->nCurrent++; + pRet = &pCList->mHd[ nC ]; + } + else if ( pCList->pNext ) + { + pCList = pCList->pNext.get(); + pCList->nCurrent = 0; + pRet = &pCList->mHd[ 0 ]; + } + return pRet; +} + +DffRecordHeader* DffRecordManager::Prev() +{ + DffRecordHeader* pRet = nullptr; + sal_uInt32 nCur = pCList->nCurrent; + if ( !nCur && pCList->pPrev ) + { + pCList = pCList->pPrev; + nCur = pCList->nCount; + } + if ( nCur-- ) + { + pCList->nCurrent = nCur; + pRet = &pCList->mHd[ nCur ]; + } + return pRet; +} + +DffRecordHeader* DffRecordManager::Last() +{ + DffRecordHeader* pRet = nullptr; + while ( pCList->pNext ) + pCList = pCList->pNext.get(); + sal_uInt32 nCnt = pCList->nCount; + if ( nCnt-- ) + { + pCList->nCurrent = nCnt; + pRet = &pCList->mHd[ nCnt ]; + } + return pRet; +} + +bool DffRecordManager::SeekToContent( SvStream& rIn, sal_uInt16 nRecId, DffSeekToContentMode eMode ) +{ + DffRecordHeader* pHd = GetRecordHeader( nRecId, eMode ); + if ( pHd ) + { + pHd->SeekToContent( rIn ); + return true; + } + else + return false; +} + +DffRecordHeader* DffRecordManager::GetRecordHeader( sal_uInt16 nRecId, DffSeekToContentMode eMode ) +{ + sal_uInt32 nOldCurrent = pCList->nCurrent; + DffRecordList* pOldList = pCList; + DffRecordHeader* pHd; + + if ( eMode == SEEK_FROM_BEGINNING ) + pHd = First(); + else + pHd = Next(); + + while ( pHd ) + { + if ( pHd->nRecType == nRecId ) + break; + pHd = Next(); + } + if ( !pHd && eMode == SEEK_FROM_CURRENT_AND_RESTART ) + { + DffRecordHeader* pBreak = &pOldList->mHd[ nOldCurrent ]; + pHd = First(); + if ( pHd ) + { + while ( pHd != pBreak ) + { + if ( pHd->nRecType == nRecId ) + break; + pHd = Next(); + } + if ( pHd->nRecType != nRecId ) + pHd = nullptr; + } + } + if ( !pHd ) + { + pCList = pOldList; + pOldList->nCurrent = nOldCurrent; + } + return pHd; +} + + +// private methods + + +bool CompareSvxMSDffShapeInfoById::operator() ( + std::shared_ptr const& lhs, + std::shared_ptr const& rhs) const +{ + return lhs->nShapeId < rhs->nShapeId; +} + +bool CompareSvxMSDffShapeInfoByTxBxComp::operator() ( + std::shared_ptr const& lhs, + std::shared_ptr const& rhs) const +{ + return lhs->nTxBxComp < rhs->nTxBxComp; +} + +void SvxMSDffManager::Scale( sal_Int32& rVal ) const +{ + if ( bNeedMap ) + rVal = BigMulDiv( rVal, nMapMul, nMapDiv ); +} + +void SvxMSDffManager::Scale( Point& rPos ) const +{ + rPos.AdjustX(nMapXOfs ); + rPos.AdjustY(nMapYOfs ); + if ( bNeedMap ) + { + rPos.setX( BigMulDiv( rPos.X(), nMapMul, nMapDiv ) ); + rPos.setY( BigMulDiv( rPos.Y(), nMapMul, nMapDiv ) ); + } +} + +void SvxMSDffManager::Scale( Size& rSiz ) const +{ + if ( bNeedMap ) + { + rSiz.setWidth( BigMulDiv( rSiz.Width(), nMapMul, nMapDiv ) ); + rSiz.setHeight( BigMulDiv( rSiz.Height(), nMapMul, nMapDiv ) ); + } +} + +void SvxMSDffManager::ScaleEmu( sal_Int32& rVal ) const +{ + rVal = BigMulDiv( rVal, nEmuMul, nEmuDiv ); +} + +sal_uInt32 SvxMSDffManager::ScalePt( sal_uInt32 nVal ) const +{ + MapUnit eMap = pSdrModel->GetScaleUnit(); + Fraction aFact( GetMapFactor( MapUnit::MapPoint, eMap ).X() ); + tools::Long aMul = aFact.GetNumerator(); + tools::Long aDiv = aFact.GetDenominator() * 65536; + aFact = Fraction( aMul, aDiv ); // try again to shorten it + return BigMulDiv( nVal, aFact.GetNumerator(), aFact.GetDenominator() ); +} + +sal_Int32 SvxMSDffManager::ScalePoint( sal_Int32 nVal ) const +{ + return BigMulDiv( nVal, nPntMul, nPntDiv ); +}; + +void SvxMSDffManager::SetModel(SdrModel* pModel, tools::Long nApplicationScale) +{ + pSdrModel = pModel; + if( pModel && (0 < nApplicationScale) ) + { + // PPT works in units of 576DPI + // WW on the other side uses twips, i.e. 1440DPI. + MapUnit eMap = pSdrModel->GetScaleUnit(); + Fraction aFact( GetMapFactor(MapUnit::MapInch, eMap).X() ); + tools::Long nMul=aFact.GetNumerator(); + tools::Long nDiv=aFact.GetDenominator()*nApplicationScale; + aFact=Fraction(nMul,nDiv); // try again to shorten it + // For 100TH_MM -> 2540/576=635/144 + // For Twip -> 1440/576=5/2 + nMapMul = aFact.GetNumerator(); + nMapDiv = aFact.GetDenominator(); + bNeedMap = nMapMul!=nMapDiv; + + // MS-DFF-Properties are mostly given in EMU (English Metric Units) + // 1mm=36000emu, 1twip=635emu + aFact=GetMapFactor(MapUnit::Map100thMM,eMap).X(); + nMul=aFact.GetNumerator(); + nDiv=aFact.GetDenominator()*360; + aFact=Fraction(nMul,nDiv); // try again to shorten it + // For 100TH_MM -> 1/360 + // For Twip -> 14,40/(25,4*360)=144/91440=1/635 + nEmuMul=aFact.GetNumerator(); + nEmuDiv=aFact.GetDenominator(); + + // And something for typographic Points + aFact=GetMapFactor(MapUnit::MapPoint,eMap).X(); + nPntMul=aFact.GetNumerator(); + nPntDiv=aFact.GetDenominator(); + } + else + { + pModel = nullptr; + nMapMul = nMapDiv = nMapXOfs = nMapYOfs = nEmuMul = nEmuDiv = nPntMul = nPntDiv = 0; + bNeedMap = false; + } +} + +bool SvxMSDffManager::SeekToShape( SvStream& rSt, SvxMSDffClientData* /* pClientData */, sal_uInt32 nId ) const +{ + bool bRet = false; + if ( !maFidcls.empty() ) + { + sal_uInt64 nOldPos = rSt.Tell(); + sal_uInt32 nSec = ( nId >> 10 ) - 1; + if ( nSec < mnIdClusters ) + { + OffsetMap::const_iterator it = maDgOffsetTable.find( maFidcls[ nSec ].dgid ); + if ( it != maDgOffsetTable.end() ) + { + sal_uInt64 nOfs = it->second; + rSt.Seek( nOfs ); + DffRecordHeader aEscherF002Hd; + bool bOk = ReadDffRecordHeader( rSt, aEscherF002Hd ); + sal_uLong nEscherF002End = bOk ? aEscherF002Hd.GetRecEndFilePos() : 0; + while (rSt.good() && rSt.Tell() < nEscherF002End) + { + DffRecordHeader aEscherObjListHd; + if (!ReadDffRecordHeader(rSt, aEscherObjListHd)) + break; + if ( aEscherObjListHd.nRecVer != 0xf ) + { + bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt); + if (!bSeekSuccess) + break; + } + else if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer ) + { + DffRecordHeader aShapeHd; + if ( SeekToRec( rSt, DFF_msofbtSp, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) ) + { + sal_uInt32 nShapeId(0); + rSt.ReadUInt32( nShapeId ); + if ( nId == nShapeId ) + { + aEscherObjListHd.SeekToBegOfRecord( rSt ); + bRet = true; + break; + } + } + bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt); + if (!bSeekSuccess) + break; + } + } + } + } + if ( !bRet ) + rSt.Seek( nOldPos ); + } + return bRet; +} + +bool SvxMSDffManager::SeekToRec( SvStream& rSt, sal_uInt16 nRecId, sal_uLong nMaxFilePos, DffRecordHeader* pRecHd, sal_uLong nSkipCount ) +{ + bool bRet = false; + sal_uInt64 nOldFPos = rSt.Tell(); // store FilePos to restore it later if necessary + do + { + DffRecordHeader aHd; + if (!ReadDffRecordHeader(rSt, aHd)) + break; + if (aHd.nRecLen > nMaxLegalDffRecordLength) + break; + if ( aHd.nRecType == nRecId ) + { + if ( nSkipCount ) + nSkipCount--; + else + { + bRet = true; + if ( pRecHd != nullptr ) + *pRecHd = aHd; + else + { + bool bSeekSuccess = aHd.SeekToBegOfRecord(rSt); + if (!bSeekSuccess) + { + bRet = false; + break; + } + } + } + } + if ( !bRet ) + { + bool bSeekSuccess = aHd.SeekToEndOfRecord(rSt); + if (!bSeekSuccess) + break; + } + } + while ( rSt.good() && rSt.Tell() < nMaxFilePos && !bRet ); + if ( !bRet ) + rSt.Seek( nOldFPos ); // restore original FilePos + return bRet; +} + +bool SvxMSDffManager::SeekToRec2( sal_uInt16 nRecId1, sal_uInt16 nRecId2, sal_uLong nMaxFilePos ) const +{ + bool bRet = false; + sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for conditionally later restoration + do + { + DffRecordHeader aHd; + if (!ReadDffRecordHeader(rStCtrl, aHd)) + break; + if ( aHd.nRecType == nRecId1 || aHd.nRecType == nRecId2 ) + { + bRet = true; + bool bSeekSuccess = aHd.SeekToBegOfRecord(rStCtrl); + if (!bSeekSuccess) + { + bRet = false; + break; + } + } + if ( !bRet ) + { + bool bSeekSuccess = aHd.SeekToEndOfRecord(rStCtrl); + if (!bSeekSuccess) + break; + } + } + while ( rStCtrl.good() && rStCtrl.Tell() < nMaxFilePos && !bRet ); + if ( !bRet ) + rStCtrl.Seek( nOldFPos ); // restore FilePos + return bRet; +} + + +bool SvxMSDffManager::GetColorFromPalette( sal_uInt16 /* nNum */, Color& rColor ) const +{ + // This method has to be overwritten in the class + // derived for the excel export + rColor = COL_WHITE; + return true; +} + +// sj: the documentation is not complete, especially in ppt the normal rgb for text +// color is written as 0xfeRRGGBB, this can't be explained by the documentation, nearly +// every bit in the upper code is set -> so there seems to be a special handling for +// ppt text colors, i decided not to fix this in MSO_CLR_ToColor because of possible +// side effects, instead MSO_TEXT_CLR_ToColor is called for PPT text colors, to map +// the color code to something that behaves like the other standard color codes used by +// fill and line color +Color SvxMSDffManager::MSO_TEXT_CLR_ToColor( sal_uInt32 nColorCode ) const +{ + // for text colors: Header is 0xfeRRGGBB + if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 ) + nColorCode &= 0x00ffffff; + else + { + // for colorscheme colors the color index are the lower three bits of the upper byte + if ( ( nColorCode & 0xf8000000 ) == 0 ) // this must be a colorscheme index + { + nColorCode >>= 24; + nColorCode |= 0x8000000; + } + } + return MSO_CLR_ToColor( nColorCode ); +} + +Color SvxMSDffManager::MSO_CLR_ToColor( sal_uInt32 nColorCode, sal_uInt16 nContentProperty ) const +{ + Color aColor( mnDefaultColor ); + + // for text colors: Header is 0xfeRRGGBB + if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 ) // sj: it needs to be checked if 0xfe is used in + nColorCode &= 0x00ffffff; // other cases than ppt text -> if not this code can be removed + + sal_uInt8 nUpper = static_cast( nColorCode >> 24 ); + + // sj: below change from 0x1b to 0x19 was done because of i84812 (0x02 -> rgb color), + // now I have some problems to fix i104685 (there the color value is 0x02000000 which requires + // a 0x2 scheme color to be displayed properly), the color docu seems to be incomplete + if( nUpper & 0x19 ) // if( nUpper & 0x1f ) + { + if( ( nUpper & 0x08 ) || ( ( nUpper & 0x10 ) == 0 ) ) + { + // SCHEMECOLOR + if ( !GetColorFromPalette( ( nUpper & 8 ) ? static_cast(nColorCode) : nUpper, aColor ) ) + { + switch( nContentProperty ) + { + case DFF_Prop_pictureTransparent : + case DFF_Prop_shadowColor : + case DFF_Prop_fillBackColor : + case DFF_Prop_fillColor : + aColor = COL_WHITE; + break; + case DFF_Prop_lineColor : + { + aColor = COL_BLACK; + } + break; + } + } + } + else // SYSCOLOR + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + sal_uInt16 nParameter = sal_uInt16(( nColorCode >> 16 ) & 0x00ff); // the HiByte of nParameter is not zero, an exclusive AND is helping :o + sal_uInt16 nFunctionBits = static_cast( ( nColorCode & 0x00000f00 ) >> 8 ); + sal_uInt16 nAdditionalFlags = static_cast( ( nColorCode & 0x0000f000) >> 8 ); + sal_uInt16 nColorIndex = sal_uInt16(nColorCode & 0x00ff); + sal_uInt32 nPropColor = 0; + + sal_uInt16 nCProp = 0; + + switch ( nColorIndex ) + { + case mso_syscolorButtonFace : aColor = rStyleSettings.GetFaceColor(); break; + case mso_syscolorWindowText : aColor = rStyleSettings.GetWindowTextColor(); break; + case mso_syscolorMenu : aColor = rStyleSettings.GetMenuColor(); break; + case mso_syscolor3DLight : + case mso_syscolorButtonHighlight : + case mso_syscolorHighlight : aColor = rStyleSettings.GetHighlightColor(); break; + case mso_syscolorHighlightText : aColor = rStyleSettings.GetHighlightTextColor(); break; + case mso_syscolorCaptionText : aColor = rStyleSettings.GetMenuTextColor(); break; + case mso_syscolorActiveCaption : aColor = rStyleSettings.GetHighlightColor(); break; + case mso_syscolorButtonShadow : aColor = rStyleSettings.GetShadowColor(); break; + case mso_syscolorButtonText : aColor = rStyleSettings.GetButtonTextColor(); break; + case mso_syscolorGrayText : aColor = rStyleSettings.GetDeactiveColor(); break; + case mso_syscolorInactiveCaption : aColor = rStyleSettings.GetDeactiveColor(); break; + case mso_syscolorInactiveCaptionText : aColor = rStyleSettings.GetDeactiveColor(); break; + case mso_syscolorInfoBackground : aColor = rStyleSettings.GetFaceColor(); break; + case mso_syscolorInfoText : aColor = rStyleSettings.GetLabelTextColor(); break; + case mso_syscolorMenuText : aColor = rStyleSettings.GetMenuTextColor(); break; + case mso_syscolorScrollbar : aColor = rStyleSettings.GetFaceColor(); break; + case mso_syscolorWindow : aColor = rStyleSettings.GetWindowColor(); break; + case mso_syscolorWindowFrame : aColor = rStyleSettings.GetWindowColor(); break; + + case mso_colorFillColor : + { + nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); + nCProp = DFF_Prop_fillColor; + } + break; + case mso_colorLineOrFillColor : // ( use the line color only if there is a line ) + { + if ( GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ) & 8 ) + { + nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 ); + nCProp = DFF_Prop_lineColor; + } + else + { + nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); + nCProp = DFF_Prop_fillColor; + } + } + break; + case mso_colorLineColor : + { + nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 ); + nCProp = DFF_Prop_lineColor; + } + break; + case mso_colorShadowColor : + { + nPropColor = GetPropertyValue( DFF_Prop_shadowColor, 0x808080 ); + nCProp = DFF_Prop_shadowColor; + } + break; + case mso_colorThis : // ( use this color ... ) + { + nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //????????????? + nCProp = DFF_Prop_fillColor; + } + break; + case mso_colorFillBackColor : + { + nPropColor = GetPropertyValue( DFF_Prop_fillBackColor, 0xffffff ); + nCProp = DFF_Prop_fillBackColor; + } + break; + case mso_colorLineBackColor : + { + nPropColor = GetPropertyValue( DFF_Prop_lineBackColor, 0xffffff ); + nCProp = DFF_Prop_lineBackColor; + } + break; + case mso_colorFillThenLine : // ( use the fillcolor unless no fill and line ) + { + nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //????????????? + nCProp = DFF_Prop_fillColor; + } + break; + case mso_colorIndexMask : // ( extract the color index ) ? + { + nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //????????????? + nCProp = DFF_Prop_fillColor; + } + break; + } + if ( nCProp && ( nPropColor & 0x10000000 ) == 0 ) // beware of looping recursive + aColor = MSO_CLR_ToColor( nPropColor, nCProp ); + + if( nAdditionalFlags & 0x80 ) // make color gray + { + sal_uInt8 nZwi = aColor.GetLuminance(); + aColor = Color( nZwi, nZwi, nZwi ); + } + switch( nFunctionBits ) + { + case 0x01 : // darken color by parameter + { + aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetRed() ) >> 8 ) ); + aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetGreen() ) >> 8 ) ); + aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetBlue() ) >> 8 ) ); + } + break; + case 0x02 : // lighten color by parameter + { + sal_uInt16 nInvParameter = ( 0x00ff - nParameter ) * 0xff; + aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetRed() ) ) >> 8 ) ); + aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetGreen() ) ) >> 8 ) ); + aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetBlue() ) ) >> 8 ) ); + } + break; + case 0x03 : // add grey level RGB(p,p,p) + { + sal_Int16 nR = static_cast(aColor.GetRed()) + static_cast(nParameter); + sal_Int16 nG = static_cast(aColor.GetGreen()) + static_cast(nParameter); + sal_Int16 nB = static_cast(aColor.GetBlue()) + static_cast(nParameter); + if ( nR > 0x00ff ) + nR = 0x00ff; + if ( nG > 0x00ff ) + nG = 0x00ff; + if ( nB > 0x00ff ) + nB = 0x00ff; + aColor = Color( static_cast(nR), static_cast(nG), static_cast(nB) ); + } + break; + case 0x04 : // subtract grey level RGB(p,p,p) + { + sal_Int16 nR = static_cast(aColor.GetRed()) - static_cast(nParameter); + sal_Int16 nG = static_cast(aColor.GetGreen()) - static_cast(nParameter); + sal_Int16 nB = static_cast(aColor.GetBlue()) - static_cast(nParameter); + if ( nR < 0 ) + nR = 0; + if ( nG < 0 ) + nG = 0; + if ( nB < 0 ) + nB = 0; + aColor = Color( static_cast(nR), static_cast(nG), static_cast(nB) ); + } + break; + case 0x05 : // subtract from gray level RGB(p,p,p) + { + sal_Int16 nR = static_cast(nParameter) - static_cast(aColor.GetRed()); + sal_Int16 nG = static_cast(nParameter) - static_cast(aColor.GetGreen()); + sal_Int16 nB = static_cast(nParameter) - static_cast(aColor.GetBlue()); + if ( nR < 0 ) + nR = 0; + if ( nG < 0 ) + nG = 0; + if ( nB < 0 ) + nB = 0; + aColor = Color( static_cast(nR), static_cast(nG), static_cast(nB) ); + } + break; + case 0x06 : // per component: black if < p, white if >= p + { + aColor.SetRed( aColor.GetRed() < nParameter ? 0x00 : 0xff ); + aColor.SetGreen( aColor.GetGreen() < nParameter ? 0x00 : 0xff ); + aColor.SetBlue( aColor.GetBlue() < nParameter ? 0x00 : 0xff ); + } + break; + } + if ( nAdditionalFlags & 0x40 ) // top-bit invert + aColor = Color( aColor.GetRed() ^ 0x80, aColor.GetGreen() ^ 0x80, aColor.GetBlue() ^ 0x80 ); + + if ( nAdditionalFlags & 0x20 ) // invert color + aColor = Color(0xff - aColor.GetRed(), 0xff - aColor.GetGreen(), 0xff - aColor.GetBlue()); + } + } + else if ( ( nUpper & 4 ) && ( ( nColorCode & 0xfffff8 ) == 0 ) ) + { // case of nUpper == 4 powerpoint takes this as argument for a colorschemecolor + GetColorFromPalette( nUpper, aColor ); + } + else // attributed hard, maybe with hint to SYSTEMRGB + aColor = Color( static_cast(nColorCode), static_cast( nColorCode >> 8 ), static_cast( nColorCode >> 16 ) ); + return aColor; +} + +void SvxMSDffManager::ReadObjText( SvStream& rStream, SdrObject* pObj ) +{ + DffRecordHeader aRecHd; + if (!ReadDffRecordHeader(rStream, aRecHd)) + return; + if( aRecHd.nRecType != DFF_msofbtClientTextbox && aRecHd.nRecType != 0x1022 ) + return; + + while (rStream.good() && rStream.Tell() < aRecHd.GetRecEndFilePos()) + { + DffRecordHeader aHd; + if (!ReadDffRecordHeader(rStream, aHd)) + break; + switch( aHd.nRecType ) + { + case DFF_PST_TextBytesAtom: + case DFF_PST_TextCharsAtom: + { + bool bUniCode = ( aHd.nRecType == DFF_PST_TextCharsAtom ); + sal_uInt32 nBytes = aHd.nRecLen; + OUString aStr = MSDFFReadZString( rStream, nBytes, bUniCode ); + ReadObjText( aStr, pObj ); + } + break; + default: + break; + } + bool bSeekSuccess = aHd.SeekToEndOfRecord(rStream); + if (!bSeekSuccess) + break; + } +} + +// sj: I just want to set a string for a text object that may contain multiple +// paragraphs. If I now take a look at the following code I get the impression that +// our outliner is too complicate to be used properly, +void SvxMSDffManager::ReadObjText( const OUString& rText, SdrObject* pObj ) +{ + SdrTextObj* pText = dynamic_cast( pObj ); + if ( !pText ) + return; + + SdrOutliner& rOutliner = pText->ImpGetDrawOutliner(); + rOutliner.Init( OutlinerMode::TextObject ); + + bool bOldUpdateMode = rOutliner.SetUpdateLayout( false ); + rOutliner.SetVertical( pText->IsVerticalWriting() ); + + sal_Int32 nParaIndex = 0; + sal_Int32 nParaSize; + const sal_Unicode* pBuf = rText.getStr(); + const sal_Unicode* pEnd = rText.getStr() + rText.getLength(); + + while( pBuf < pEnd ) + { + const sal_Unicode* pCurrent = pBuf; + + for ( nParaSize = 0; pBuf < pEnd; ) + { + sal_Unicode nChar = *pBuf++; + if ( nChar == 0xa ) + { + if ( ( pBuf < pEnd ) && ( *pBuf == 0xd ) ) + pBuf++; + break; + } + else if ( nChar == 0xd ) + { + if ( ( pBuf < pEnd ) && ( *pBuf == 0xa ) ) + pBuf++; + break; + } + else + ++nParaSize; + } + ESelection aSelection( nParaIndex, 0, nParaIndex, 0 ); + OUString aParagraph( pCurrent, nParaSize ); + if ( !nParaIndex && aParagraph.isEmpty() ) // SJ: we are crashing if the first paragraph is empty ? + aParagraph += " "; // otherwise these two lines can be removed. + rOutliner.Insert( aParagraph, nParaIndex ); + rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() ); + + SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() ); + if ( !aSelection.nStartPos ) + aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) ); + aSelection.nStartPos = 0; + rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection ); + nParaIndex++; + } + std::optional pNewText = rOutliner.CreateParaObject(); + rOutliner.Clear(); + rOutliner.SetUpdateLayout( bOldUpdateMode ); + pText->SetOutlinerParaObject( std::move(pNewText) ); + // tdf#143315: restore stylesheet applied to Outliner's nodes when SdrTextObj initializes + // its attributes, but removed by Outliner::Init, which calls Outliner::Clear. + pText->SetStyleSheet(pText->GetStyleSheet(), true); +} + +//static +OUString SvxMSDffManager::MSDFFReadZString(SvStream& rIn, + sal_uInt32 nLen, bool bUniCode) +{ + if (!nLen) + return OUString(); + + OUString sBuf; + + if( bUniCode ) + sBuf = read_uInt16s_ToOUString(rIn, nLen/2); + else + sBuf = read_uInt8s_ToOUString(rIn, nLen, RTL_TEXTENCODING_MS_1252); + + return comphelper::string::stripEnd(sBuf, 0); +} + +static Size lcl_GetPrefSize(const Graphic& rGraf, const MapMode& aWanted) +{ + MapMode aPrefMapMode(rGraf.GetPrefMapMode()); + if (aPrefMapMode == aWanted) + return rGraf.GetPrefSize(); + Size aRetSize; + if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel) + { + aRetSize = Application::GetDefaultDevice()->PixelToLogic( + rGraf.GetPrefSize(), aWanted); + } + else + { + aRetSize = OutputDevice::LogicToLogic( + rGraf.GetPrefSize(), rGraf.GetPrefMapMode(), aWanted); + } + return aRetSize; +} + +// sj: if the parameter pSet is null, then the resulting crop bitmap will be stored in rGraf, +// otherwise rGraf is untouched and pSet is used to store the corresponding SdrGrafCropItem +static void lcl_ApplyCropping( const DffPropSet& rPropSet, SfxItemSet* pSet, Graphic& rGraf ) +{ + sal_Int32 nCropTop = static_cast(rPropSet.GetPropertyValue( DFF_Prop_cropFromTop, 0 )); + sal_Int32 nCropBottom = static_cast(rPropSet.GetPropertyValue( DFF_Prop_cropFromBottom, 0 )); + sal_Int32 nCropLeft = static_cast(rPropSet.GetPropertyValue( DFF_Prop_cropFromLeft, 0 )); + sal_Int32 nCropRight = static_cast(rPropSet.GetPropertyValue( DFF_Prop_cropFromRight, 0 )); + + if( !(nCropTop || nCropBottom || nCropLeft || nCropRight) ) + return; + + double fFactor; + Size aCropSize; + BitmapEx aCropBitmap; + sal_uInt32 nTop( 0 ), nBottom( 0 ), nLeft( 0 ), nRight( 0 ); + + // Cropping has to be applied on a loaded graphic. + rGraf.makeAvailable(); + + if ( pSet ) // use crop attributes ? + aCropSize = lcl_GetPrefSize(rGraf, MapMode(MapUnit::Map100thMM)); + else + { + aCropBitmap = rGraf.GetBitmapEx(); + aCropSize = aCropBitmap.GetSizePixel(); + } + if ( nCropTop ) + { + fFactor = static_cast(nCropTop) / 65536.0; + nTop = static_cast( ( static_cast( aCropSize.Height() + 1 ) * fFactor ) + 0.5 ); + } + if ( nCropBottom ) + { + fFactor = static_cast(nCropBottom) / 65536.0; + nBottom = static_cast( ( static_cast( aCropSize.Height() + 1 ) * fFactor ) + 0.5 ); + } + if ( nCropLeft ) + { + fFactor = static_cast(nCropLeft) / 65536.0; + nLeft = static_cast( ( static_cast( aCropSize.Width() + 1 ) * fFactor ) + 0.5 ); + } + if ( nCropRight ) + { + fFactor = static_cast(nCropRight) / 65536.0; + nRight = static_cast( ( static_cast( aCropSize.Width() + 1 ) * fFactor ) + 0.5 ); + } + if ( pSet ) // use crop attributes ? + pSet->Put( SdrGrafCropItem( nLeft, nTop, nRight, nBottom ) ); + else + { + tools::Rectangle aCropRect( nLeft, nTop, aCropSize.Width() - nRight, aCropSize.Height() - nBottom ); + aCropBitmap.Crop( aCropRect ); + rGraf = aCropBitmap; + } +} + +SdrObject* SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, const DffObjData& rObjData ) +{ + SdrObject* pRet = nullptr; + OUString aLinkFileName; + tools::Rectangle aVisArea; + + auto eFlags = GetPropertyValue(DFF_Prop_pibFlags, mso_blipflagDefault); + sal_uInt32 nBlipId = GetPropertyValue( DFF_Prop_pib, 0 ); + bool bGrfRead = false, + + // Graphic linked + bLinkGrf = 0 != ( eFlags & mso_blipflagLinkToFile ); + { + OUString aFileName; + Graphic aGraf; // be sure this graphic is deleted before swapping out + if( SeekToContent( DFF_Prop_pibName, rSt ) ) + aFileName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_pibName, 0 ), true ); + + // AND, OR the following: + if( !( eFlags & mso_blipflagDoNotSave ) ) // Graphic embedded + { + bGrfRead = GetBLIP( nBlipId, aGraf, &aVisArea ); + if ( !bGrfRead ) + { + /* + Still no luck, lets look at the end of this record for a FBSE pool, + this fallback is a specific case for how word does it sometimes + */ + bool bOk = rObjData.rSpHd.SeekToEndOfRecord( rSt ); + DffRecordHeader aHd; + if (bOk) + { + bOk = ReadDffRecordHeader(rSt, aHd); + } + if (bOk && DFF_msofbtBSE == aHd.nRecType) + { + const sal_uLong nSkipBLIPLen = 20; + const sal_uLong nSkipShapePos = 4; + const sal_uLong nSkipBLIP = 4; + const sal_uLong nSkip = + nSkipBLIPLen + 4 + nSkipShapePos + 4 + nSkipBLIP; + + if (nSkip <= aHd.nRecLen) + { + rSt.SeekRel(nSkip); + if (ERRCODE_NONE == rSt.GetError()) + bGrfRead = GetBLIPDirect( rSt, aGraf, &aVisArea ); + } + } + } + } + if ( bGrfRead ) + { + // the writer is doing its own cropping, so this part affects only impress and calc, + // unless we're inside a group, in which case writer doesn't crop either + if (( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_CROP_BITMAPS ) || rObjData.nCalledByGroup != 0 ) + lcl_ApplyCropping( *this, !bool( rObjData.nSpFlags & ShapeFlag::OLEShape ) ? &rSet : nullptr, aGraf ); + + if ( IsProperty( DFF_Prop_pictureTransparent ) ) + { + sal_uInt32 nTransColor = GetPropertyValue( DFF_Prop_pictureTransparent, 0 ); + + if ( aGraf.GetType() == GraphicType::Bitmap ) + { + BitmapEx aBitmapEx( aGraf.GetBitmapEx() ); + aBitmapEx.CombineMaskOr( MSO_CLR_ToColor( nTransColor, DFF_Prop_pictureTransparent ), 9 ); + aGraf = aBitmapEx; + } + } + + sal_Int32 nContrast = GetPropertyValue( DFF_Prop_pictureContrast, 0x10000 ); + /* + 0x10000 is msoffice 50% + < 0x10000 is in units of 1/50th of 0x10000 per 1% + > 0x10000 is in units where + a msoffice x% is stored as 50/(100-x) * 0x10000 + + plus, a (ui) microsoft % ranges from 0 to 100, OOO + from -100 to 100, so also normalize into that range + */ + if ( nContrast > 0x10000 ) + { + double fX = nContrast; + fX /= 0x10000; + fX /= 51; // 50 + 1 to round + fX = 1/fX; + nContrast = static_cast(fX); + nContrast -= 100; + nContrast = -nContrast; + nContrast = (nContrast-50)*2; + } + else if ( nContrast == 0x10000 ) + nContrast = 0; + else + { + if (o3tl::checked_multiply(nContrast, 101, nContrast)) //100 + 1 to round + { + SAL_WARN("filter.ms", "bad Contrast value:" << nContrast); + nContrast = 0; + } + else + { + nContrast /= 0x10000; + nContrast -= 100; + } + } + sal_Int16 nBrightness = static_cast( static_cast(GetPropertyValue( DFF_Prop_pictureBrightness, 0 )) / 327 ); + sal_Int32 nGamma = GetPropertyValue( DFF_Prop_pictureGamma, 0x10000 ); + GraphicDrawMode eDrawMode = GraphicDrawMode::Standard; + switch ( GetPropertyValue( DFF_Prop_pictureActive, 0 ) & 6 ) + { + case 4 : eDrawMode = GraphicDrawMode::Greys; break; + case 6 : eDrawMode = GraphicDrawMode::Mono; break; + case 0 : + { + //office considers the converted values of (in OOo) 70 to be the + //"watermark" values, which can vary slightly due to rounding from the + //above values + if (( nContrast == -70 ) && ( nBrightness == 70 )) + { + nContrast = 0; + nBrightness = 0; + eDrawMode = GraphicDrawMode::Watermark; + }; + } + break; + } + + if ( nContrast || nBrightness || ( nGamma != 0x10000 ) || ( eDrawMode != GraphicDrawMode::Standard ) ) + { + // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness, + // while MSO apparently applies half of brightness before contrast and half after. So if only + // contrast or brightness need to be altered, the result is the same, but if both are involved, + // there's no way to map that, so just force a conversion of the image. + bool needsConversion = nContrast != 0 && nBrightness != 0; + if ( !bool(rObjData.nSpFlags & ShapeFlag::OLEShape) && !needsConversion ) + { + if ( nBrightness ) + rSet.Put( SdrGrafLuminanceItem( nBrightness ) ); + if ( nContrast ) + rSet.Put( SdrGrafContrastItem( static_cast(nContrast) ) ); + if ( nGamma != 0x10000 ) + rSet.Put( SdrGrafGamma100Item( nGamma / 655 ) ); + if ( eDrawMode != GraphicDrawMode::Standard ) + rSet.Put( SdrGrafModeItem( eDrawMode ) ); + } + else + { + if ( eDrawMode == GraphicDrawMode::Watermark ) + { + nContrast = 60; + nBrightness = 70; + eDrawMode = GraphicDrawMode::Standard; + } + switch ( aGraf.GetType() ) + { + case GraphicType::Bitmap : + { + BitmapEx aBitmapEx( aGraf.GetBitmapEx() ); + if ( nBrightness || nContrast || ( nGamma != 0x10000 ) ) + aBitmapEx.Adjust( nBrightness, static_cast(nContrast), 0, 0, 0, static_cast(nGamma) / 0x10000, false, true ); + if ( eDrawMode == GraphicDrawMode::Greys ) + aBitmapEx.Convert( BmpConversion::N8BitGreys ); + else if ( eDrawMode == GraphicDrawMode::Mono ) + aBitmapEx.Convert( BmpConversion::N1BitThreshold ); + aGraf = aBitmapEx; + + } + break; + + case GraphicType::GdiMetafile : + { + GDIMetaFile aGdiMetaFile( aGraf.GetGDIMetaFile() ); + if ( nBrightness || nContrast || ( nGamma != 0x10000 ) ) + aGdiMetaFile.Adjust( nBrightness, static_cast(nContrast), 0, 0, 0, static_cast(nGamma) / 0x10000, false, true ); + if ( eDrawMode == GraphicDrawMode::Greys ) + aGdiMetaFile.Convert( MtfConversion::N8BitGreys ); + else if ( eDrawMode == GraphicDrawMode::Mono ) + aGdiMetaFile.Convert( MtfConversion::N1BitThreshold ); + aGraf = aGdiMetaFile; + } + break; + default: break; + } + } + } + } + + // should it be an OLE object? + if( bGrfRead && !bLinkGrf && IsProperty( DFF_Prop_pictureId ) ) + { + // TODO/LATER: in future probably the correct aspect should be provided here + // #i32596# - pass to method + pRet = ImportOLE( GetPropertyValue( DFF_Prop_pictureId, 0 ), aGraf, rObjData.aBoundRect, aVisArea, rObjData.nCalledByGroup ); + } + if( !pRet ) + { + pRet = new SdrGrafObj(*pSdrModel); + if( bGrfRead ) + static_cast(pRet)->SetGraphic( aGraf ); + + if( bLinkGrf && !bGrfRead ) // sj: #i55484# if the graphic was embedded ( bGrfRead == true ) then + { // we do not need to set a link. TODO: not to lose the information where the graphic is linked from + INetURLObject aAbsURL; + if ( !INetURLObject( maBaseURL ).GetNewAbsURL( aFileName, &aAbsURL ) ) + { + OUString aValidURL; + if( osl::FileBase::getFileURLFromSystemPath( aFileName, aValidURL ) == osl::FileBase::E_None ) + aAbsURL = INetURLObject( aValidURL ); + } + if( aAbsURL.GetProtocol() != INetProtocol::NotValid ) + { + aLinkFileName = aAbsURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ); + } + else + aLinkFileName = aFileName; + } + } + + // set the size from BLIP if there is one + if ( bGrfRead && !aVisArea.IsEmpty() ) + pRet->SetBLIPSizeRectangle( aVisArea ); + + if (pRet->GetName().isEmpty()) // SJ 22.02.00 : PPT OLE IMPORT: + { // name is already set in ImportOLE !! + // JP 01.12.99: SetName before SetModel - because in the other order the Bug 70098 is active + if ( ( eFlags & mso_blipflagType ) != mso_blipflagComment ) + { + INetURLObject aURL; + aURL.SetSmartURL( aFileName ); + pRet->SetName( aURL.getBase() ); + } + else + pRet->SetName( aFileName ); + } + } + pRet->NbcSetLogicRect( rObjData.aBoundRect ); + + if (SdrGrafObj* pGrafObj = dynamic_cast(pRet)) + { + if( aLinkFileName.getLength() ) + { + pGrafObj->SetGraphicLink( aLinkFileName ); + Graphic aGraphic(pGrafObj->GetGraphic()); + aGraphic.setOriginURL(aLinkFileName); + } + + if ( bLinkGrf && !bGrfRead ) + { + Graphic aGraf(pGrafObj->GetGraphic()); + lcl_ApplyCropping( *this, &rSet, aGraf ); + } + } + + return pRet; +} + +// PptSlidePersistEntry& rPersistEntry, SdPage* pPage +SdrObject* SvxMSDffManager::ImportObj( SvStream& rSt, SvxMSDffClientData& rClientData, + tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect, int nCalledByGroup, sal_Int32* pShapeId ) +{ + SdrObject* pRet = nullptr; + DffRecordHeader aObjHd; + bool bOk = ReadDffRecordHeader(rSt, aObjHd); + if (bOk && aObjHd.nRecType == DFF_msofbtSpgrContainer) + { + pRet = ImportGroup( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId ); + } + else if (bOk && aObjHd.nRecType == DFF_msofbtSpContainer) + { + pRet = ImportShape( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId ); + } + aObjHd.SeekToBegOfRecord( rSt ); // restore FilePos + return pRet; +} + +SdrObject* SvxMSDffManager::ImportGroup( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData, + tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect, + int nCalledByGroup, sal_Int32* pShapeId ) +{ + SdrObject* pRet = nullptr; + + if( pShapeId ) + *pShapeId = 0; + + if (!rHd.SeekToContent(rSt)) + return pRet; + + DffRecordHeader aRecHd; // the first atom has to be the SpContainer for the GroupObject + bool bOk = ReadDffRecordHeader(rSt, aRecHd); + if (bOk && aRecHd.nRecType == DFF_msofbtSpContainer) + { + mnFix16Angle = 0_deg100; + if (!aRecHd.SeekToBegOfRecord(rSt)) + return pRet; + pRet = ImportObj( rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup + 1, pShapeId ); + if ( pRet ) + { + Degree100 nGroupRotateAngle(0); + ShapeFlag nSpFlags = nGroupShapeFlags; + nGroupRotateAngle = mnFix16Angle; + + tools::Rectangle aClientRect( rClientRect ); + + tools::Rectangle aGlobalChildRect; + if ( !nCalledByGroup || rGlobalChildRect.IsEmpty() ) + aGlobalChildRect = GetGlobalChildAnchor( rHd, rSt, aClientRect ); + else + aGlobalChildRect = rGlobalChildRect; + + if ( ( nGroupRotateAngle > 4500_deg100 && nGroupRotateAngle <= 13500_deg100 ) + || ( nGroupRotateAngle > 22500_deg100 && nGroupRotateAngle <= 31500_deg100 ) ) + { + sal_Int32 nHalfWidth = ( aClientRect.GetWidth() + 1 ) >> 1; + sal_Int32 nHalfHeight = ( aClientRect.GetHeight() + 1 ) >> 1; + Point aTopLeft( aClientRect.Left() + nHalfWidth - nHalfHeight, + aClientRect.Top() + nHalfHeight - nHalfWidth ); + const tools::Long nRotatedWidth = aClientRect.GetHeight(); + const tools::Long nRotatedHeight = aClientRect.GetWidth(); + Size aNewSize(nRotatedWidth, nRotatedHeight); + tools::Rectangle aNewRect( aTopLeft, aNewSize ); + aClientRect = aNewRect; + } + + // now importing the inner objects of the group + if (!aRecHd.SeekToEndOfRecord(rSt)) + return pRet; + + while (rSt.good() && ( rSt.Tell() < rHd.GetRecEndFilePos())) + { + DffRecordHeader aRecHd2; + if (!ReadDffRecordHeader(rSt, aRecHd2)) + break; + if ( aRecHd2.nRecType == DFF_msofbtSpgrContainer ) + { + tools::Rectangle aGroupClientAnchor, aGroupChildAnchor; + GetGroupAnchors( aRecHd2, rSt, aGroupClientAnchor, aGroupChildAnchor, aClientRect, aGlobalChildRect ); + if (!aRecHd2.SeekToBegOfRecord(rSt)) + return pRet; + sal_Int32 nShapeId; + SdrObject* pTmp = ImportGroup( aRecHd2, rSt, rClientData, aGroupClientAnchor, aGroupChildAnchor, nCalledByGroup + 1, &nShapeId ); + if (pTmp) + { + SdrObjGroup* pGroup = dynamic_cast(pRet); + if (pGroup && pGroup->GetSubList()) + { + pGroup->GetSubList()->NbcInsertObject(pTmp); + if (nShapeId) + insertShapeId(nShapeId, pTmp); + } + else + FreeObj(rClientData, pTmp); + } + } + else if ( aRecHd2.nRecType == DFF_msofbtSpContainer ) + { + if (!aRecHd2.SeekToBegOfRecord(rSt)) + return pRet; + sal_Int32 nShapeId; + SdrObject* pTmp = ImportShape( aRecHd2, rSt, rClientData, aClientRect, aGlobalChildRect, nCalledByGroup + 1, &nShapeId ); + if (pTmp) + { + SdrObjGroup* pGroup = dynamic_cast(pRet); + if (pGroup && pGroup->GetSubList()) + { + pGroup->GetSubList()->NbcInsertObject(pTmp); + if (nShapeId) + insertShapeId(nShapeId, pTmp); + } + else + FreeObj(rClientData, pTmp); + } + } + if (!aRecHd2.SeekToEndOfRecord(rSt)) + return pRet; + } + + if ( nGroupRotateAngle ) + pRet->NbcRotate( aClientRect.Center(), nGroupRotateAngle ); + if ( nSpFlags & ShapeFlag::FlipV ) + { // BoundRect in aBoundRect + Point aLeft( aClientRect.Left(), ( aClientRect.Top() + aClientRect.Bottom() ) >> 1 ); + Point aRight( aLeft.X() + 1000, aLeft.Y() ); + pRet->NbcMirror( aLeft, aRight ); + } + if ( nSpFlags & ShapeFlag::FlipH ) + { // BoundRect in aBoundRect + Point aTop( ( aClientRect.Left() + aClientRect.Right() ) >> 1, aClientRect.Top() ); + Point aBottom( aTop.X(), aTop.Y() + 1000 ); + pRet->NbcMirror( aTop, aBottom ); + } + } + } + if (o3tl::make_unsigned(nCalledByGroup) < maPendingGroupData.size()) + { + // finalization for this group is pending, do it now + pRet = FinalizeObj(maPendingGroupData.back().first, pRet); + maPendingGroupData.pop_back(); + } + return pRet; +} + +SdrObject* SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData, + tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect, + int nCalledByGroup, sal_Int32* pShapeId ) +{ + if( pShapeId ) + *pShapeId = 0; + + if (!rHd.SeekToBegOfRecord(rSt)) + return nullptr; + + DffObjData aObjData( rHd, rClientRect, nCalledByGroup ); + + aObjData.bRotateTextWithShape = ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL ) == 0; + maShapeRecords.Consume( rSt ); + if( maShapeRecords.SeekToContent( rSt, + DFF_msofbtUDefProp ) ) + { + sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen; + while( 5 < nBytesLeft ) + { + sal_uInt16 nPID(0); + rSt.ReadUInt16(nPID); + if (!rSt.good()) + break; + sal_uInt32 nUDData(0); + rSt.ReadUInt32(nUDData); + if (!rSt.good()) + break; + if (nPID == 447) + { + mbRotateGranientFillWithAngle = nUDData & 0x20; + break; + } + nBytesLeft -= 6; + } + } + aObjData.bShapeType = maShapeRecords.SeekToContent( rSt, DFF_msofbtSp ); + if ( aObjData.bShapeType ) + { + sal_uInt32 temp(0); + rSt.ReadUInt32( aObjData.nShapeId ) + .ReadUInt32( temp ); + aObjData.nSpFlags = ShapeFlag(temp); + aObjData.eShapeType = static_cast(maShapeRecords.Current()->nRecInstance); + } + else + { + aObjData.nShapeId = 0; + aObjData.nSpFlags = ShapeFlag::NONE; + aObjData.eShapeType = mso_sptNil; + } + + if( pShapeId ) + *pShapeId = aObjData.nShapeId; + + aObjData.bOpt = maShapeRecords.SeekToContent( rSt, DFF_msofbtOPT, SEEK_FROM_CURRENT_AND_RESTART ); + if ( aObjData.bOpt ) + { + if (!maShapeRecords.Current()->SeekToBegOfRecord(rSt)) + return nullptr; +#ifdef DBG_AUTOSHAPE + ReadPropSet( rSt, &rClientData, (sal_uInt32)aObjData.eShapeType ); +#else + ReadPropSet( rSt, &rClientData ); +#endif + } + else + { + InitializePropSet( DFF_msofbtOPT ); // get the default PropSet + static_cast(this)->mnFix16Angle = 0_deg100; + } + + aObjData.bOpt2 = maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ); + if ( aObjData.bOpt2 ) + { + maShapeRecords.Current()->SeekToBegOfRecord( rSt ); + pSecPropSet.reset( new DffPropertyReader( *this ) ); + pSecPropSet->ReadPropSet( rSt, nullptr ); + } + + aObjData.bChildAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtChildAnchor, SEEK_FROM_CURRENT_AND_RESTART ); + if ( aObjData.bChildAnchor ) + { + sal_Int32 l(0), o(0), r(0), u(0); + rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u ); + Scale( l ); + Scale( o ); + Scale( r ); + Scale( u ); + aObjData.aChildAnchor = tools::Rectangle( l, o, r, u ); + sal_Int32 nWidth, nHeight; + if (!rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() && + !o3tl::checked_sub(r, l, nWidth) && !o3tl::checked_sub(u, o, nHeight)) + { + double fXScale = static_cast(rClientRect.GetWidth()) / static_cast(rGlobalChildRect.GetWidth()); + double fYScale = static_cast(rClientRect.GetHeight()) / static_cast(rGlobalChildRect.GetHeight()); + double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left(); + double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top(); + double fWidth = nWidth * fXScale; + double fHeight = nHeight * fYScale; + aObjData.aChildAnchor = tools::Rectangle( Point( fl, fo ), Size( fWidth + 1, fHeight + 1 ) ); + } + } + + aObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtClientAnchor, SEEK_FROM_CURRENT_AND_RESTART ); + if ( aObjData.bClientAnchor ) + ProcessClientAnchor2( rSt, *maShapeRecords.Current(), aObjData ); + + if ( aObjData.bChildAnchor ) + aObjData.aBoundRect = aObjData.aChildAnchor; + + if ( aObjData.nSpFlags & ShapeFlag::Background ) + aObjData.aBoundRect = tools::Rectangle( Point(), Size( 1, 1 ) ); + + SdrObjectUniquePtr xRet; + + tools::Rectangle aTextRect; + if ( !aObjData.aBoundRect.IsEmpty() ) + { // apply rotation to the BoundingBox BEFORE an object has been generated + if( mnFix16Angle ) + { + Degree100 nAngle = mnFix16Angle; + if ( ( nAngle > 4500_deg100 && nAngle <= 13500_deg100 ) || ( nAngle > 22500_deg100 && nAngle <= 31500_deg100 ) ) + { + sal_Int32 nHalfWidth = ( aObjData.aBoundRect.GetWidth() + 1 ) >> 1; + sal_Int32 nHalfHeight = ( aObjData.aBoundRect.GetHeight() + 1 ) >> 1; + Point aTopLeft( aObjData.aBoundRect.Left() + nHalfWidth - nHalfHeight, + aObjData.aBoundRect.Top() + nHalfHeight - nHalfWidth ); + Size aNewSize( aObjData.aBoundRect.GetHeight(), aObjData.aBoundRect.GetWidth() ); + tools::Rectangle aNewRect( aTopLeft, aNewSize ); + aObjData.aBoundRect = aNewRect; + } + } + aTextRect = aObjData.aBoundRect; + bool bGraphic = IsProperty( DFF_Prop_pib ) || + IsProperty( DFF_Prop_pibName ) || + IsProperty( DFF_Prop_pibFlags ); + + if ( aObjData.nSpFlags & ShapeFlag::Group ) + { + xRet.reset(new SdrObjGroup(*pSdrModel)); + /* After CWS aw033 has been integrated, an empty group object + cannot store its resulting bounding rectangle anymore. We have + to return this rectangle via rClientRect now, but only, if + caller has not passed an own bounding ractangle. */ + if ( rClientRect.IsEmpty() ) + rClientRect = aObjData.aBoundRect; + nGroupShapeFlags = aObjData.nSpFlags; + } + else if ( ( aObjData.eShapeType != mso_sptNil ) || IsProperty( DFF_Prop_pVertices ) || bGraphic ) + { + SfxItemSet aSet( pSdrModel->GetItemPool() ); + + bool bIsConnector = ( ( aObjData.eShapeType >= mso_sptStraightConnector1 ) && ( aObjData.eShapeType <= mso_sptCurvedConnector5 ) ); + Degree100 nObjectRotation = mnFix16Angle; + ShapeFlag nSpFlags = aObjData.nSpFlags; + + if ( bGraphic ) + { + if (!mbSkipImages) { + xRet.reset(ImportGraphic(rSt, aSet, aObjData)); // SJ: #68396# is no longer true (fixed in ppt2000) + ApplyAttributes( rSt, aSet, aObjData ); + xRet->SetMergedItemSet(aSet); + } + } + else if ( aObjData.eShapeType == mso_sptLine && !( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) ) + { + basegfx::B2DPolygon aPoly; + aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Left(), aObjData.aBoundRect.Top())); + aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Right(), aObjData.aBoundRect.Bottom())); + xRet.reset(new SdrPathObj( + *pSdrModel, + SdrObjKind::Line, + basegfx::B2DPolyPolygon(aPoly))); + ApplyAttributes( rSt, aSet, aObjData ); + xRet->SetMergedItemSet(aSet); + } + else + { + if ( GetCustomShapeContent( aObjData.eShapeType ) || IsProperty( DFF_Prop_pVertices ) ) + { + + ApplyAttributes( rSt, aSet, aObjData ); + + xRet.reset(new SdrObjCustomShape(*pSdrModel)); + + sal_uInt32 ngtextFStrikethrough = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ); + bool bIsFontwork = ( ngtextFStrikethrough & 0x4000 ) != 0; + + // in case of a FontWork, the text is set by the escher import + if ( bIsFontwork ) + { + OUString aObjectText; + OUString aFontName; + + if ( SeekToContent( DFF_Prop_gtextFont, rSt ) ) + { + SvxFontItem aLatin(EE_CHAR_FONTINFO), aAsian(EE_CHAR_FONTINFO_CJK), aComplex(EE_CHAR_FONTINFO_CTL); + GetDefaultFonts( aLatin, aAsian, aComplex ); + + aFontName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextFont, 0 ), true ); + aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(), + PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO )); + aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(), + PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CJK ) ); + aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(), + PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CTL ) ); + } + + // SJ: applying fontattributes for Fontwork : + if ( IsHardAttribute( DFF_Prop_gtextFItalic ) ) + aSet.Put( SvxPostureItem( ( ngtextFStrikethrough & 0x0010 ) != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) ); + + if ( IsHardAttribute( DFF_Prop_gtextFBold ) ) + aSet.Put( SvxWeightItem( ( ngtextFStrikethrough & 0x0020 ) != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) ); + + // SJ TODO: Vertical Writing is not correct, instead + // this should be replaced through "CharacterRotation" + // by 90 degrees, therefore a new Item has to be + // supported by svx core, api and xml file format + static_cast(xRet.get())->SetVerticalWriting( ( ngtextFStrikethrough & 0x2000 ) != 0 ); + + if ( SeekToContent( DFF_Prop_gtextUNICODE, rSt ) ) + { + aObjectText = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextUNICODE, 0 ), true ); + ReadObjText(aObjectText, xRet.get()); + } + + auto eGeoTextAlign = GetPropertyValue(DFF_Prop_gtextAlign, mso_alignTextCenter); + { + SdrTextHorzAdjust eHorzAdjust; + switch( eGeoTextAlign ) + { + case mso_alignTextLetterJust : + case mso_alignTextWordJust : + case mso_alignTextStretch : eHorzAdjust = SDRTEXTHORZADJUST_BLOCK; break; + default: + case mso_alignTextInvalid : + case mso_alignTextCenter : eHorzAdjust = SDRTEXTHORZADJUST_CENTER; break; + case mso_alignTextLeft : eHorzAdjust = SDRTEXTHORZADJUST_LEFT; break; + case mso_alignTextRight : eHorzAdjust = SDRTEXTHORZADJUST_RIGHT; break; + } + aSet.Put( SdrTextHorzAdjustItem( eHorzAdjust ) ); + + drawing::TextFitToSizeType eFTS = drawing::TextFitToSizeType_NONE; + if ( eGeoTextAlign == mso_alignTextStretch ) + eFTS = drawing::TextFitToSizeType_ALLLINES; + aSet.Put( SdrTextFitToSizeTypeItem( eFTS ) ); + } + if ( IsProperty( DFF_Prop_gtextSpacing ) ) + { + sal_Int32 nTextWidth = GetPropertyValue( DFF_Prop_gtextSpacing, 1 << 16 ) / 655; + if ( nTextWidth != 100 ) + aSet.Put( SvxCharScaleWidthItem( static_cast(nTextWidth), EE_CHAR_FONTWIDTH ) ); + } + if ( ngtextFStrikethrough & 0x1000 ) // SJ: Font Kerning On ? + aSet.Put( SvxKerningItem( 1, EE_CHAR_KERNING ) ); + + // #i119496# the resize autoshape to fit text attr of word art in MS PPT is always false + aSet.Put(makeSdrTextAutoGrowHeightItem(false)); + aSet.Put(makeSdrTextAutoGrowWidthItem(false)); + + bool bWithPadding = !( ngtextFStrikethrough & use_gtextFBestFit + && ngtextFStrikethrough & use_gtextFShrinkFit + && ngtextFStrikethrough & use_gtextFStretch + && ngtextFStrikethrough & gtextFBestFit + && ngtextFStrikethrough & gtextFShrinkFit + && ngtextFStrikethrough & gtextFStretch ); + + if ( bWithPadding ) + { + // trim, remove additional space + VclPtr pDevice = VclPtr::Create(); + vcl::Font aFont = pDevice->GetFont(); + aFont.SetFamilyName( aFontName ); + aFont.SetFontSize( Size( 0, 96 ) ); + pDevice->SetFont( aFont ); + + auto nTextWidth = pDevice->GetTextWidth( aObjectText ); + OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt ); + if ( nTextWidth && aObjData.eShapeType == mso_sptTextPlainText + && aObjName.match( "PowerPlusWaterMarkObject" ) ) + { + double fRatio = static_cast(pDevice->GetTextHeight()) / nTextWidth; + sal_Int32 nNewHeight = fRatio * aObjData.aBoundRect.getWidth(); + sal_Int32 nPaddingY = aObjData.aBoundRect.getHeight() - nNewHeight; + + if ( nPaddingY > 0 ) + aObjData.aBoundRect.setHeight( nNewHeight ); + } + } + } + xRet->SetMergedItemSet( aSet ); + + // sj: taking care of rtl, ltr. In case of fontwork mso. seems not to be able to set + // proper text directions, instead the text default is depending to the string. + // so we have to calculate the a text direction from string: + if ( bIsFontwork ) + { + OutlinerParaObject* pParaObj = static_cast(xRet.get())->GetOutlinerParaObject(); + if ( pParaObj ) + { + SdrOutliner& rOutliner = static_cast(xRet.get())->ImpGetDrawOutliner(); + rOutliner.SetStyleSheetPool(static_cast< SfxStyleSheetPool* >(xRet->getSdrModelFromSdrObject().GetStyleSheetPool())); + bool bOldUpdateMode = rOutliner.SetUpdateLayout( false ); + rOutliner.SetText( *pParaObj ); + ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::DEFAULT); + pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM)); + sal_Int32 i, nParagraphs = rOutliner.GetParagraphCount(); + if ( nParagraphs ) + { + bool bCreateNewParaObject = false; + for ( i = 0; i < nParagraphs; i++ ) + { + OUString aString(rOutliner.GetText(rOutliner.GetParagraph(i))); + bool bIsRTL = pVirDev->GetTextIsRTL(aString, 0, aString.getLength()); + if ( bIsRTL ) + { + SfxItemSet aSet2( rOutliner.GetParaAttribs( i ) ); + aSet2.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) ); + rOutliner.SetParaAttribs( i, aSet2 ); + bCreateNewParaObject = true; + } + } + if ( bCreateNewParaObject ) + { + std::optional pNewText = rOutliner.CreateParaObject(); + rOutliner.Init( OutlinerMode::TextObject ); + static_cast(xRet.get())->NbcSetOutlinerParaObject( std::move(pNewText) ); + } + } + rOutliner.Clear(); + rOutliner.SetUpdateLayout( bOldUpdateMode ); + } + } + + // mso_sptArc special treating + // tdf#124029: A new custom shape is generated from prototype 'msoArc'. Values, which are + // read here, are adapted and merged. The shape type is changed, so this code + // applies only if importing arcs from MS Office. + if ( aObjData.eShapeType == mso_sptArc ) + { + static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" ); + static const OUStringLiteral sViewBox( u"ViewBox" ); + static const OUStringLiteral sPath( u"Path" ); + SdrCustomShapeGeometryItem aGeometryItem( static_cast(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) ); + PropertyValue aPropVal; + + // The default arc goes form -90deg to 0deg. Replace general defaults used + // when read from stream with this specific values. + double fStartAngle(-90.0); + double fEndAngle(0.0); + css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues; + const uno::Any* pAny = aGeometryItem.GetPropertyValueByName(sAdjustmentValues); + if (pAny && (*pAny >>= seqAdjustmentValues) && seqAdjustmentValues.getLength() > 1) + { + auto pseqAdjustmentValues = seqAdjustmentValues.getArray(); + if (seqAdjustmentValues[0].State == css::beans::PropertyState_DEFAULT_VALUE) + { + pseqAdjustmentValues[0].Value <<= -90.0; + pseqAdjustmentValues[0].State = com::sun::star::beans::PropertyState_DIRECT_VALUE; + } + if (seqAdjustmentValues[1].State == css::beans::PropertyState_DEFAULT_VALUE) + { + pseqAdjustmentValues[1].Value <<= 0.0; + pseqAdjustmentValues[1].State = com::sun::star::beans::PropertyState_DIRECT_VALUE; + } + seqAdjustmentValues[0].Value >>= fStartAngle; + seqAdjustmentValues[1].Value >>= fEndAngle; + aPropVal.Name = sAdjustmentValues; + aPropVal.Value <<= seqAdjustmentValues; + aGeometryItem.SetPropertyValue(aPropVal); + } + + // arc first command is always wr -- clockwise arc + // the parameters are : (left,top),(right,bottom),start(x,y),end(x,y) + // The left/top vertex of the frame rectangle of the sector is the origin + // of the shape internal coordinate system in MS Office. The default arc + // has an ellipse frame rectangle with LT(-21600,0) and + // RB(21600,43200) in this coordinate system. + basegfx::B2DRectangle aEllipseRect_MS(-21600.0, 0.0, 21600.0, 43200.0); + css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates; + pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" ); + if (pAny && (*pAny >>= seqCoordinates) && (seqCoordinates.getLength() >= 2)) + { + auto const nL + = *o3tl::doAccess(seqCoordinates[0].First.Value); + auto const nT + = *o3tl::doAccess(seqCoordinates[0].Second.Value); + auto const nR + = *o3tl::doAccess(seqCoordinates[1].First.Value); + auto const nB + = *o3tl::doAccess(seqCoordinates[1].Second.Value); + aEllipseRect_MS = basegfx::B2DRectangle(nL, nT, nR, nB); + } + + // MS Office uses the pie frame rectangle as reference for outer position + // and size of the shape and for text in the shape. We can get this rectangle + // from imported viewBox or from the arc geometry. + basegfx::B2DRectangle aPieRect_MS(0.0 , 0.0, 21600.0, 21600.0); + pAny = aGeometryItem.GetPropertyValueByName(sPath,sViewBox); + css::awt::Rectangle aImportedViewBox; + if (pAny && (*pAny >>= aImportedViewBox)) + { + aPieRect_MS = basegfx::B2DRectangle( aImportedViewBox.X, + aImportedViewBox.Y, + aImportedViewBox.X + aImportedViewBox.Width, + aImportedViewBox.Y + aImportedViewBox.Height); + } + else + { + double fRadStartAngle(basegfx::deg2rad(NormAngle360(fStartAngle))); + double fRadEndAngle(basegfx::deg2rad(NormAngle360(fEndAngle))); + basegfx::B2DPoint aCenter(aEllipseRect_MS.getCenter()); + basegfx::B2DPolygon aTempPie( + basegfx::utils::createPolygonFromEllipseSegment( + aCenter, + aEllipseRect_MS.getWidth() * 0.5, + aEllipseRect_MS.getHeight() * 0.5, + fRadStartAngle, + fRadEndAngle)); + aTempPie.append(aCenter); + aPieRect_MS = aTempPie.getB2DRange(); + } + + // MS Office uses for mso_sptArc a frame rectangle (=resize handles) + // which encloses only the sector, LibreOffice uses for custom shapes as + // default a frame rectangle, which encloses the entire ellipse. That would + // result in wrong positions in Writer and Calc, see tdf#124029. + // We workaround this problem, by setting a suitable viewBox. + bool bIsImportPPT(GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT); + if (bIsImportPPT || aPieRect_MS.getWidth() == 0 || aPieRect_MS.getHeight() == 0) + { // clear item, so that default from EnhancedCustomShapeGeometry is used + aGeometryItem.ClearPropertyValue(sViewBox); + } + else + { + double fX((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) / 2.0); + double fY((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) / 2.0); + css::awt::Rectangle aViewBox_LO; // in LO coordinate system + aViewBox_LO.X = static_cast(fX); + aViewBox_LO.Y = static_cast(fY); + aViewBox_LO.Width = static_cast(aPieRect_MS.getWidth() / 2.0); + aViewBox_LO.Height = static_cast(aPieRect_MS.getHeight() / 2.0); + aPropVal.Name = sViewBox; + aPropVal.Value <<= aViewBox_LO; + aGeometryItem.SetPropertyValue(aPropVal); + } + + // aObjData.aBoundRect contains position and size of the sector in (outer) + // logic coordinates, e.g. for PPT in 1/100 mm, for Word in twips. + // For Impress the default viewBox is used, so adapt aObjData.aBoundRect. + tools::Rectangle aOldBoundRect(aObjData.aBoundRect); // backup, needed later on + if (bIsImportPPT) + { + double fLogicXOfs(0.0); // LogicLeft_LO = LogicLeft_MS + fXLogicOfs + double fLogicYOfs(0.0); + double fLogicPieWidth(aObjData.aBoundRect.getWidth()); + double fLogicPieHeight(aObjData.aBoundRect.getHeight()); + double fLogicEllipseWidth(0.0); // to be LogicWidth_LO + double fLogicEllipseHeight(0.0); + if (aPieRect_MS.getWidth()) + { + // fXScale = ratio 'logic length' : 'shape internal length' + double fXScale = fLogicPieWidth / aPieRect_MS.getWidth(); + if (nSpFlags & ShapeFlag::FlipH) + fLogicXOfs = (aPieRect_MS.getMaxX() - aEllipseRect_MS.getMaxX()) * fXScale; + else + fLogicXOfs = (aEllipseRect_MS.getMinX() - aPieRect_MS.getMinX()) * fXScale; + fLogicEllipseWidth = aEllipseRect_MS.getWidth() * fXScale; + } + if (aPieRect_MS.getHeight()) + { + double fYScale = fLogicPieHeight / aPieRect_MS.getHeight(); + if (nSpFlags & ShapeFlag::FlipV) + fLogicYOfs = (aPieRect_MS.getMaxY() - aEllipseRect_MS.getMaxY()) * fYScale; + else + fLogicYOfs = (aEllipseRect_MS.getMinY() - aPieRect_MS.getMinY()) * fYScale; + fLogicEllipseHeight = aEllipseRect_MS.getHeight() * fYScale; + } + aObjData.aBoundRect = tools::Rectangle( + Point(aOldBoundRect.Left() + static_cast(fLogicXOfs), + aOldBoundRect.Top() + static_cast(fLogicYOfs)), + Size(static_cast(fLogicEllipseWidth), + static_cast(fLogicEllipseHeight))); + } + // else nothing to do. aObjData.aBoundRect corresponds to changed viewBox. + + // creating the text frame -> scaling into (0,0),(21600,21600) destination coordinate system + double fTextFrameScaleX = 0.0; + double fTextFrameScaleY = 0.0; + if (aEllipseRect_MS.getWidth()) + fTextFrameScaleX = 21600.0 / aEllipseRect_MS.getWidth(); + if (aEllipseRect_MS.getHeight()) + fTextFrameScaleY = 21600.0 / aEllipseRect_MS.getHeight(); + + sal_Int32 nLeft = static_cast((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX ); + sal_Int32 nTop = static_cast((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY ); + sal_Int32 nRight = static_cast((aPieRect_MS.getMaxX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX ); + sal_Int32 nBottom= static_cast((aPieRect_MS.getMaxY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY ); + css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrame( 1 ); + auto pTextFrame = aTextFrame.getArray(); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.First, nLeft ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.Second, nTop ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.First, nRight ); + EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.Second,nBottom ); + PropertyValue aProp; + aProp.Name = "TextFrames"; + aProp.Value <<= aTextFrame; + aGeometryItem.SetPropertyValue( sPath, aProp ); + + // sj: taking care of the different rotation points, since the new arc is having a bigger snaprect + if ( mnFix16Angle ) + { + Degree100 nAngle = mnFix16Angle; + if ( nSpFlags & ShapeFlag::FlipH ) + nAngle = 36000_deg100 - nAngle; + if ( nSpFlags & ShapeFlag::FlipV ) + nAngle = -nAngle; + double a = toRadians(nAngle); + double ss = sin( a ); + double cc = cos( a ); + Point aP1( aOldBoundRect.TopLeft() ); + Point aC1( aObjData.aBoundRect.Center() ); + Point aP2( aOldBoundRect.TopLeft() ); + Point aC2( aOldBoundRect.Center() ); + RotatePoint( aP1, aC1, ss, cc ); + RotatePoint( aP2, aC2, ss, cc ); + aObjData.aBoundRect.Move( aP2.X() - aP1.X(), aP2.Y() - aP1.Y() ); + } + + // clearing items, so MergeDefaultAttributes will set the corresponding + // defaults from EnhancedCustomShapeGeometry + aGeometryItem.ClearPropertyValue( "Handles" ); + aGeometryItem.ClearPropertyValue( "Equations" ); + aGeometryItem.ClearPropertyValue( sPath ); + + static_cast(xRet.get())->SetMergedItem( aGeometryItem ); + static_cast(xRet.get())->MergeDefaultAttributes(); + + // now setting a new name, so the above correction is only done once when importing from ms + SdrCustomShapeGeometryItem aGeoName( static_cast(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) ); + aPropVal.Name = "Type"; + aPropVal.Value <<= OUString( "mso-spt100" ); + aGeoName.SetPropertyValue( aPropVal ); + static_cast(xRet.get())->SetMergedItem( aGeoName ); + } + else + static_cast(xRet.get())->MergeDefaultAttributes(); + + xRet->SetSnapRect( aObjData.aBoundRect ); + EnhancedCustomShape2d aCustomShape2d(static_cast(*xRet)); + aTextRect = aCustomShape2d.GetTextRect(); + + if( bIsConnector ) + { + if( nObjectRotation ) + xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation ); + // mirrored horizontally? + if ( nSpFlags & ShapeFlag::FlipH ) + { + tools::Rectangle aBndRect(xRet->GetSnapRect()); + Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() ); + Point aBottom( aTop.X(), aTop.Y() + 1000 ); + xRet->NbcMirror( aTop, aBottom ); + } + // mirrored vertically? + if ( nSpFlags & ShapeFlag::FlipV ) + { + tools::Rectangle aBndRect(xRet->GetSnapRect()); + Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 ); + Point aRight( aLeft.X() + 1000, aLeft.Y() ); + xRet->NbcMirror( aLeft, aRight ); + } + basegfx::B2DPolyPolygon aPoly( static_cast(xRet.get())->GetLineGeometry( true ) ); + + xRet.reset(new SdrEdgeObj(*pSdrModel)); + ApplyAttributes( rSt, aSet, aObjData ); + xRet->SetLogicRect( aObjData.aBoundRect ); + xRet->SetMergedItemSet(aSet); + + // connectors + auto eConnectorStyle = GetPropertyValue(DFF_Prop_cxstyle, mso_cxstyleStraight); + + static_cast(xRet.get())->ConnectToNode(true, nullptr); + static_cast(xRet.get())->ConnectToNode(false, nullptr); + + Point aPoint1( aObjData.aBoundRect.TopLeft() ); + Point aPoint2( aObjData.aBoundRect.BottomRight() ); + + // pay attention to the rotations + if ( nObjectRotation ) + { + double a = toRadians(nObjectRotation); + Point aCenter( aObjData.aBoundRect.Center() ); + double ss = sin(a); + double cc = cos(a); + + RotatePoint(aPoint1, aCenter, ss, cc); + RotatePoint(aPoint2, aCenter, ss, cc); + + // #i120437# reset rotation, it is part of the path and shall not be applied again + nObjectRotation = 0_deg100; + } + + // rotate/mirror line within the area as we need it + if ( nSpFlags & ShapeFlag::FlipH ) + { + sal_Int32 n = aPoint1.X(); + aPoint1.setX( aPoint2.X() ); + aPoint2.setX( n ); + + // #i120437# reset hor flip + nSpFlags &= ~ShapeFlag::FlipH; + } + if ( nSpFlags & ShapeFlag::FlipV ) + { + sal_Int32 n = aPoint1.Y(); + aPoint1.setY( aPoint2.Y() ); + aPoint2.setY( n ); + + // #i120437# reset ver flip + nSpFlags &= ~ShapeFlag::FlipV; + } + + xRet->NbcSetPoint(aPoint1, 0); // start point + xRet->NbcSetPoint(aPoint2, 1); // endpoint + + sal_Int32 n1HorzDist, n1VertDist, n2HorzDist, n2VertDist; + n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 0; + switch( eConnectorStyle ) + { + case mso_cxstyleBent: + { + aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OrthoLines ) ); + n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 630; + } + break; + case mso_cxstyleCurved: + aSet.Put( SdrEdgeKindItem( SdrEdgeKind::Bezier ) ); + break; + default: // mso_cxstyleStraight || mso_cxstyleNone + aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OneLine ) ); + break; + } + aSet.Put( SdrEdgeNode1HorzDistItem( n1HorzDist ) ); + aSet.Put( SdrEdgeNode1VertDistItem( n1VertDist ) ); + aSet.Put( SdrEdgeNode2HorzDistItem( n2HorzDist ) ); + aSet.Put( SdrEdgeNode2VertDistItem( n2VertDist ) ); + + static_cast(xRet.get())->SetEdgeTrackPath( aPoly ); + xRet->SetMergedItemSet(aSet); + } + if ( aObjData.eShapeType == mso_sptLine ) + { + xRet->SetMergedItemSet(aSet); + static_cast(xRet.get())->MergeDefaultAttributes(); + } + } + } + + if (xRet) + { + if( nObjectRotation ) + xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation ); + // mirrored horizontally? + if ( nSpFlags & ShapeFlag::FlipH ) + { + tools::Rectangle aBndRect(xRet->GetSnapRect()); + Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() ); + Point aBottom( aTop.X(), aTop.Y() + 1000 ); + xRet->NbcMirror(aTop, aBottom); + } + // mirrored vertically? + if ( nSpFlags & ShapeFlag::FlipV ) + { + tools::Rectangle aBndRect(xRet->GetSnapRect()); + Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 ); + Point aRight( aLeft.X() + 1000, aLeft.Y() ); + xRet->NbcMirror(aLeft, aRight); + } + } + } + } + + // #i51348# #118052# name of the shape + if (xRet) + { + OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt ); + if( !aObjName.isEmpty() ) + xRet->SetName(aObjName); + } + + xRet.reset(ProcessObj(rSt, aObjData, rClientData, aTextRect, xRet.release())); + + if (xRet) + { + sal_Int32 nGroupProperties( GetPropertyValue( DFF_Prop_fPrint, 0 ) ); + const bool bVisible = ( ( nGroupProperties & 2 ) == 0 ); + xRet->SetVisible( bVisible ); + // In Excel hidden means not printed + if ( !bVisible ) + { + xRet->SetPrintable(false); + } + else + { + // This property isn't used in Excel anymore, leaving it for legacy reasons + xRet->SetPrintable( ( nGroupProperties & 1 ) != 0 ); + } + } + + //Import alt text as description + if (xRet && SeekToContent(DFF_Prop_wzDescription, rSt)) + { + OUString aAltText = MSDFFReadZString(rSt, GetPropertyValue(DFF_Prop_wzDescription, 0), true); + xRet->SetDescription(aAltText); + } + + // If this shape opens a new group, push back its object data because + // finalization will be called when nested objects have been imported; + // otherwise, just finalize here + if (o3tl::make_unsigned(nCalledByGroup) > maPendingGroupData.size()) + { + auto xHdClone = std::make_shared(aObjData.rSpHd); + maPendingGroupData.emplace_back(DffObjData(xHdClone, aObjData), xHdClone ); + } + else + { + xRet.reset(FinalizeObj(aObjData, xRet.release())); + } + return xRet.release(); +} + +tools::Rectangle SvxMSDffManager::GetGlobalChildAnchor( const DffRecordHeader& rHd, SvStream& rSt, tools::Rectangle& aClientRect ) +{ + tools::Rectangle aChildAnchor; + if (!rHd.SeekToContent(rSt)) + return aChildAnchor; + + bool bIsClientRectRead = false; + while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < rHd.GetRecEndFilePos() ) ) + { + DffRecordHeader aShapeHd; + if (!ReadDffRecordHeader(rSt, aShapeHd)) + break; + if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) || + ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) ) + { + DffRecordHeader aShapeHd2( aShapeHd ); + if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) + ReadDffRecordHeader( rSt, aShapeHd2 ); + while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos()) + { + DffRecordHeader aShapeAtom; + if (!ReadDffRecordHeader(rSt, aShapeAtom)) + break; + + if ( aShapeAtom.nRecType == DFF_msofbtClientAnchor ) + { + if ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT ) + { + sal_Int32 l(0), t(0), r(0), b(0); + if ( aShapeAtom.nRecLen == 16 ) + { + rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b ); + } + else + { + sal_Int16 ls(0), ts(0), rs(0), bs(0); + rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange... + l = ls; + t = ts; + r = rs; + b = bs; + } + Scale( l ); + Scale( t ); + Scale( r ); + Scale( b ); + if ( bIsClientRectRead ) + { + tools::Rectangle aChild( l, t, r, b ); + aChildAnchor.Union( aChild ); + } + else + { + aClientRect = tools::Rectangle( l, t, r, b ); + bIsClientRectRead = true; + } + } + break; + } + else if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor ) + { + sal_Int32 l(0), o(0), r(0), u(0); + rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u ); + Scale( l ); + Scale( o ); + Scale( r ); + Scale( u ); + tools::Rectangle aChild( l, o, r, u ); + aChildAnchor.Union( aChild ); + break; + } + if (!aShapeAtom.SeekToEndOfRecord(rSt)) + break; + } + } + if (!aShapeHd.SeekToEndOfRecord(rSt)) + break; + } + return aChildAnchor; +} + +void SvxMSDffManager::GetGroupAnchors( const DffRecordHeader& rHd, SvStream& rSt, + tools::Rectangle& rGroupClientAnchor, tools::Rectangle& rGroupChildAnchor, + const tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect ) +{ + if (!rHd.SeekToContent(rSt)) + return; + + bool bFirst = true; + DffRecordHeader aShapeHd; + while (rSt.good() && rSt.Tell() < rHd.GetRecEndFilePos()) + { + if (!ReadDffRecordHeader(rSt, aShapeHd)) + break; + if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) || + ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) ) + { + DffRecordHeader aShapeHd2( aShapeHd ); + if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) + ReadDffRecordHeader( rSt, aShapeHd2 ); + while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos()) + { + DffRecordHeader aShapeAtom; + if (!ReadDffRecordHeader(rSt, aShapeAtom)) + break; + if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor ) + { + sal_Int32 l(0), o(0), r(0), u(0); + rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u ); + Scale( l ); + Scale( o ); + Scale( r ); + Scale( u ); + tools::Rectangle aChild( l, o, r, u ); + + if ( bFirst ) + { + if ( !rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() ) + { + double fWidth = o3tl::saturating_sub(r, l); + double fHeight= o3tl::saturating_sub(u, o); + double fXScale = static_cast(rClientRect.GetWidth()) / static_cast(rGlobalChildRect.GetWidth()); + double fYScale = static_cast(rClientRect.GetHeight()) / static_cast(rGlobalChildRect.GetHeight()); + double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left(); + double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top(); + fWidth *= fXScale; + fHeight *= fYScale; + rGroupClientAnchor = tools::Rectangle( Point( static_cast(fl), static_cast(fo) ), Size( static_cast( fWidth + 1 ), static_cast( fHeight + 1 ) ) ); + } + bFirst = false; + } + else + rGroupChildAnchor.Union( aChild ); + break; + } + if (!aShapeAtom.SeekToEndOfRecord(rSt)) + break; + } + } + if (!aShapeHd.SeekToEndOfRecord(rSt)) + break; + } +} + +SvxMSDffImportRec* SvxMSDffImportData::find(const SdrObject* pObj) +{ + auto it = m_ObjToRecMap.find(pObj); + if (it != m_ObjToRecMap.end()) + return it->second; + return nullptr; +} + +void SvxMSDffImportData::insert(std::unique_ptr pImpRec) +{ + auto aRet = m_Records.insert(std::move(pImpRec)); + bool bSuccess = aRet.second; + if (bSuccess) + { + SvxMSDffImportRec* pRec = aRet.first->get(); + m_ObjToRecMap[pRec->pObj] = pRec; + } +} + +void SvxMSDffImportData::NotifyFreeObj(SdrObject* pObj) +{ + if (SvxMSDffImportRec* pRecord = find(pObj)) + { + m_ObjToRecMap.erase(pObj); + pRecord->pObj = nullptr; + } +} + +void SvxMSDffManager::NotifyFreeObj(SvxMSDffClientData& rData, SdrObject* pObj) +{ + if (SdrObjGroup* pGroup = dynamic_cast(pObj)) + { + SdrObjList* pSubList = pGroup->GetSubList(); + size_t nObjCount = pSubList->GetObjCount(); + for (size_t i = 0; i < nObjCount; ++i) + NotifyFreeObj(rData, pSubList->GetObj(i)); + } + + rData.NotifyFreeObj(pObj); +} + +void SvxMSDffManager::FreeObj(SvxMSDffClientData& rData, SdrObject* pObj) +{ + NotifyFreeObj(rData, pObj); + SdrObject::Free(pObj); +} + +SdrObject* SvxMSDffManager::ProcessObj(SvStream& rSt, + DffObjData& rObjData, + SvxMSDffClientData& rData, + tools::Rectangle& rTextRect, + SdrObject* pObj + ) +{ + if( !rTextRect.IsEmpty() ) + { + SvxMSDffImportData& rImportData = static_cast(rData); + SvxMSDffImportRec* pImpRec = new SvxMSDffImportRec; + bool bDeleteImpRec = true; + SvxMSDffImportRec* pTextImpRec = pImpRec; + bool bDeleteTextImpRec = false; + + // fill Import Record with data + pImpRec->nShapeId = rObjData.nShapeId; + pImpRec->eShapeType = rObjData.eShapeType; + + auto eWrapMode = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare); + rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt, + DFF_msofbtClientAnchor, + SEEK_FROM_CURRENT_AND_RESTART ); + if( rObjData.bClientAnchor ) + ProcessClientAnchor( rSt, + maShapeRecords.Current()->nRecLen, + pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen ); + + rObjData.bClientData = maShapeRecords.SeekToContent( rSt, + DFF_msofbtClientData, + SEEK_FROM_CURRENT_AND_RESTART ); + if( rObjData.bClientData ) + ProcessClientData( rSt, + maShapeRecords.Current()->nRecLen, + pImpRec->pClientDataBuffer, pImpRec->nClientDataLen ); + + + // process user (== Winword) defined parameters in 0xF122 record + if( maShapeRecords.SeekToContent( rSt, + DFF_msofbtUDefProp, + SEEK_FROM_CURRENT_AND_RESTART ) + && maShapeRecords.Current()->nRecLen ) + { + sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen; + while( 5 < nBytesLeft ) + { + sal_uInt16 nPID(0); + rSt.ReadUInt16(nPID); + if (!rSt.good()) + break; + sal_uInt32 nUDData(0); + rSt.ReadUInt32(nUDData); + switch (nPID) + { + case 0x038F: pImpRec->nXAlign = nUDData; break; + case 0x0390: + pImpRec->nXRelTo = nUDData; + break; + case 0x0391: pImpRec->nYAlign = nUDData; break; + case 0x0392: + pImpRec->nYRelTo = nUDData; + break; + case 0x03BF: pImpRec->nGroupShapeBooleanProperties = nUDData; break; + case 0x0393: + // This seems to correspond to o:hrpct from .docx (even including + // the difference that it's in 0.1% even though the .docx spec + // says it's in 1%). + pImpRec->relativeHorizontalWidth = nUDData; + break; + case 0x0394: + // And this is really just a guess, but a mere presence of this + // flag makes a horizontal rule be as wide as the page (unless + // overridden by something), so it probably matches o:hr from .docx. + pImpRec->isHorizontalRule = true; + break; + } + if (!rSt.good()) + break; + nBytesLeft -= 6; + } + } + + // text frame, also Title or Outline + SdrObject* pOrgObj = pObj; + SdrRectObj* pTextObj = nullptr; + sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 ); + if( nTextId ) + { + SfxItemSet aSet( pSdrModel->GetItemPool() ); + + //Originally anything that as a mso_sptTextBox was created as a + //textbox, this was changed for #88277# to be created as a simple + //rect to keep impress happy. For the rest of us we'd like to turn + //it back into a textbox again. + bool bTextFrame = (pImpRec->eShapeType == mso_sptTextBox); + if (!bTextFrame) + { + //Either + //a) it's a simple text object or + //b) it's a rectangle with text and square wrapping. + bTextFrame = + ( + (pImpRec->eShapeType == mso_sptTextSimple) || + ( + (pImpRec->eShapeType == mso_sptRectangle) + && (eWrapMode == mso_wrapSquare) + && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() ) + ) + ); + } + + if (bTextFrame) + { + SdrObject::Free( pObj ); + pObj = pOrgObj = nullptr; + } + + // Distance of Textbox to its surrounding Customshape + sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440L); + sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440L ); + sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720L ); + sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720L ); + + ScaleEmu( nTextLeft ); + ScaleEmu( nTextRight ); + ScaleEmu( nTextTop ); + ScaleEmu( nTextBottom ); + + Degree100 nTextRotationAngle(0); + bool bVerticalText = false; + if ( IsProperty( DFF_Prop_txflTextFlow ) ) + { + auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF; + switch( eTextFlow ) + { + case mso_txflBtoT: + nTextRotationAngle = 9000_deg100; + break; + case mso_txflVertN: + case mso_txflTtoBN: + nTextRotationAngle = 27000_deg100; + break; + case mso_txflTtoBA: + bVerticalText = true; + break; + case mso_txflHorzA: + bVerticalText = true; + nTextRotationAngle = 9000_deg100; + break; + case mso_txflHorzN: + default : + break; + } + } + + if (nTextRotationAngle) + { + switch (nTextRotationAngle.get()) + { + case 9000: + { + tools::Long nWidth = rTextRect.GetWidth(); + rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() ); + rTextRect.SetBottom( rTextRect.Top() + nWidth ); + + sal_Int32 nOldTextLeft = nTextLeft; + sal_Int32 nOldTextRight = nTextRight; + sal_Int32 nOldTextTop = nTextTop; + sal_Int32 nOldTextBottom = nTextBottom; + + nTextLeft = nOldTextBottom; + nTextRight = nOldTextTop; + nTextTop = nOldTextLeft; + nTextBottom = nOldTextRight; + } + break; + case 27000: + { + tools::Long nWidth = rTextRect.GetWidth(); + rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() ); + rTextRect.SetBottom( rTextRect.Top() + nWidth ); + + sal_Int32 nOldTextLeft = nTextLeft; + sal_Int32 nOldTextRight = nTextRight; + sal_Int32 nOldTextTop = nTextTop; + sal_Int32 nOldTextBottom = nTextBottom; + + nTextLeft = nOldTextTop; + nTextRight = nOldTextBottom; + nTextTop = nOldTextRight; + nTextBottom = nOldTextLeft; + } + break; + } + } + + pTextObj = new SdrRectObj( + *pSdrModel, + SdrObjKind::Text, + rTextRect); + pTextImpRec = new SvxMSDffImportRec(*pImpRec); + bDeleteTextImpRec = true; + + // the vertical paragraph indents are part of the BoundRect, + // here we 'remove' them by calculating + tools::Rectangle aNewRect(rTextRect); + aNewRect.AdjustBottom( -(nTextTop + nTextBottom) ); + aNewRect.AdjustRight( -(nTextLeft + nTextRight) ); + + // Only if it's a simple textbox may Writer replace + // the object with a frame, otherwise + if( bTextFrame ) + { + auto const pTmpRec = std::make_shared(0, pImpRec->nShapeId); + + SvxMSDffShapeInfos_ById::const_iterator const it = + m_xShapeInfosById->find(pTmpRec); + if (it != m_xShapeInfosById->end()) + { + SvxMSDffShapeInfo& rInfo = **it; + pTextImpRec->bReplaceByFly = rInfo.bReplaceByFly; + } + } + + if( !pObj ) + ApplyAttributes( rSt, aSet, rObjData ); + + bool bFitText = false; + if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2) + { + aSet.Put( makeSdrTextAutoGrowHeightItem( true ) ); + aSet.Put( makeSdrTextMinFrameHeightItem( + aNewRect.Bottom() - aNewRect.Top() ) ); + aSet.Put( makeSdrTextMinFrameWidthItem( + aNewRect.Right() - aNewRect.Left() ) ); + bFitText = true; + } + else + { + aSet.Put( makeSdrTextAutoGrowHeightItem( false ) ); + aSet.Put( makeSdrTextAutoGrowWidthItem( false ) ); + } + + switch (GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare)) + { + case mso_wrapNone : + aSet.Put( makeSdrTextAutoGrowWidthItem( true ) ); + if (bFitText) + { + //can't do autowidth in flys #i107184# + pTextImpRec->bReplaceByFly = false; + } + break; + case mso_wrapByPoints : + aSet.Put( makeSdrTextContourFrameItem( true ) ); + break; + default: break; + } + + // set margins at the border of the textbox + aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) ); + aSet.Put( makeSdrTextRightDistItem( nTextRight ) ); + aSet.Put( makeSdrTextUpperDistItem( nTextTop ) ); + aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) ); + pTextImpRec->nDxTextLeft = nTextLeft; + pTextImpRec->nDyTextTop = nTextTop; + pTextImpRec->nDxTextRight = nTextRight; + pTextImpRec->nDyTextBottom = nTextBottom; + + // read text anchor + if ( IsProperty( DFF_Prop_anchorText ) ) + { + auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, 0); + + SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_CENTER; + bool bTVASet(false); + bool bTHASet(false); + + switch( eTextAnchor ) + { + case mso_anchorTop: + { + eTVA = SDRTEXTVERTADJUST_TOP; + bTVASet = true; + } + break; + case mso_anchorTopCentered: + { + eTVA = SDRTEXTVERTADJUST_TOP; + bTVASet = true; + bTHASet = true; + } + break; + + case mso_anchorMiddle: + bTVASet = true; + break; + case mso_anchorMiddleCentered: + { + bTVASet = true; + bTHASet = true; + } + break; + case mso_anchorBottom: + { + eTVA = SDRTEXTVERTADJUST_BOTTOM; + bTVASet = true; + } + break; + case mso_anchorBottomCentered: + { + eTVA = SDRTEXTVERTADJUST_BOTTOM; + bTVASet = true; + bTHASet = true; + } + break; + default : break; + } + // insert + if ( bTVASet ) + aSet.Put( SdrTextVertAdjustItem( eTVA ) ); + if ( bTHASet ) + aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) ); + } + + pTextObj->SetMergedItemSet(aSet); + + if (bVerticalText) + pTextObj->SetVerticalWriting(true); + + if (nTextRotationAngle) + { + tools::Long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ? + rTextRect.GetWidth() : rTextRect.GetHeight(); + nMinWH /= 2; + Point aPivot(rTextRect.TopLeft()); + aPivot.AdjustX(nMinWH ); + aPivot.AdjustY(nMinWH ); + pTextObj->SdrAttrObj::NbcRotate(aPivot, nTextRotationAngle); + } + + // rotate text with shape? + if ( mnFix16Angle ) + { + double a = toRadians(mnFix16Angle); + pTextObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle, + sin( a ), cos( a ) ); + } + + if( !pObj ) + { + pObj = pTextObj; + } + else + { + if( pTextObj != pObj ) + { + SdrObject* pGroup = new SdrObjGroup(*pSdrModel); + pGroup->GetSubList()->NbcInsertObject( pObj ); + pGroup->GetSubList()->NbcInsertObject( pTextObj ); + if (pOrgObj == pObj) + pOrgObj = pGroup; + else + pOrgObj = pObj; + pObj = pGroup; + } + } + } + else if( !pObj ) + { + // simple rectangular objects are ignored by ImportObj() :-( + // this is OK for Draw but not for Calc and Writer + // cause here these objects have a default border + pObj = new SdrRectObj( + *pSdrModel, + rTextRect); + + pOrgObj = pObj; + SfxItemSet aSet( pSdrModel->GetItemPool() ); + ApplyAttributes( rSt, aSet, rObjData ); + + SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR ); + if( SfxItemState::DEFAULT == eState ) + aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) ); + pObj->SetMergedItemSet(aSet); + } + + //Means that fBehindDocument is set + if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20) + pImpRec->bDrawHell = true; + else + pImpRec->bDrawHell = false; + if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02) + pImpRec->bHidden = true; + pTextImpRec->bDrawHell = pImpRec->bDrawHell; + pTextImpRec->bHidden = pImpRec->bHidden; + pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext, 0 ); + pTextImpRec->nNextShapeId=pImpRec->nNextShapeId; + + if ( nTextId ) + { + pTextImpRec->aTextId.nTxBxS = static_cast( nTextId >> 16 ); + pTextImpRec->aTextId.nSequence = static_cast(nTextId); + } + + pTextImpRec->nDxWrapDistLeft = GetPropertyValue( + DFF_Prop_dxWrapDistLeft, 114935L ) / 635L; + pTextImpRec->nDyWrapDistTop = GetPropertyValue( + DFF_Prop_dyWrapDistTop, 0 ) / 635L; + pTextImpRec->nDxWrapDistRight = GetPropertyValue( + DFF_Prop_dxWrapDistRight, 114935L ) / 635L; + pTextImpRec->nDyWrapDistBottom = GetPropertyValue( + DFF_Prop_dyWrapDistBottom, 0 ) / 635L; + // 16.16 fraction times total image width or height, as appropriate. + + if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt)) + { + pTextImpRec->pWrapPolygon.reset(); + sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(8); + rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert ); + // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4 + // low-order bytes are recorded + if (nElemSizeVert == 0xFFF0) + nElemSizeVert = 4; + + // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert; + bool bOk = nElemSizeVert && (rSt.remainingSize() / nElemSizeVert >= nNumElemVert); + if (bOk) + { + pTextImpRec->pWrapPolygon = tools::Polygon(nNumElemVert); + for (sal_uInt16 i = 0; i < nNumElemVert; ++i) + { + sal_Int32 nX(0), nY(0); + if (nElemSizeVert == 8) + rSt.ReadInt32( nX ).ReadInt32( nY ); + else + { + sal_Int16 nSmallX(0), nSmallY(0); + rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY ); + nX = nSmallX; + nY = nSmallY; + } + (*(pTextImpRec->pWrapPolygon))[i].setX( nX ); + (*(pTextImpRec->pWrapPolygon))[i].setY( nY ); + } + } + } + + pImpRec->nCropFromTop = GetPropertyValue( + DFF_Prop_cropFromTop, 0 ); + pImpRec->nCropFromBottom = GetPropertyValue( + DFF_Prop_cropFromBottom, 0 ); + pImpRec->nCropFromLeft = GetPropertyValue( + DFF_Prop_cropFromLeft, 0 ); + pImpRec->nCropFromRight = GetPropertyValue( + DFF_Prop_cropFromRight, 0 ); + + pImpRec->bVFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipV); + pImpRec->bHFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipH); + + sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ); + pImpRec->eLineStyle = (nLineFlags & 8) + ? static_cast(GetPropertyValue( + DFF_Prop_lineStyle, + mso_lineSimple )) + : MSO_LineStyle_NONE; + pTextImpRec->eLineStyle = pImpRec->eLineStyle; + + pImpRec->eLineDashing = static_cast(GetPropertyValue( + DFF_Prop_lineDashing, mso_lineSolid )); + pTextImpRec->eLineDashing = pImpRec->eLineDashing; + + if( pImpRec->nShapeId ) + { + // amend the import record list + if( pOrgObj ) + { + pImpRec->pObj = pOrgObj; + rImportData.insert(std::unique_ptr(pImpRec)); + bDeleteImpRec = false; + if (pImpRec == pTextImpRec) + bDeleteTextImpRec = false; + } + + if( pTextObj && (pOrgObj != pTextObj) ) + { + // Modify ShapeId (must be unique) + pImpRec->nShapeId |= 0x8000000; + pTextImpRec->pObj = pTextObj; + rImportData.insert(std::unique_ptr(pTextImpRec)); + bDeleteTextImpRec = false; + if (pTextImpRec == pImpRec) + bDeleteImpRec = false; + } + + // entry in the z-order-list in order to complement the pointer to this object + /*Only store objects which are not deep inside the tree*/ + if( ( rObjData.nCalledByGroup == 0 ) + || + ( (rObjData.nSpFlags & ShapeFlag::Group) + && (rObjData.nCalledByGroup < 2) ) + ) + StoreShapeOrder( pImpRec->nShapeId, + ( static_cast(pImpRec->aTextId.nTxBxS) << 16 ) + + pImpRec->aTextId.nSequence, pObj ); + } + + if (bDeleteImpRec) + delete pImpRec; + + if (bDeleteTextImpRec) + delete pTextImpRec; + } + + return pObj; +}; + +SdrObject* SvxMSDffManager::FinalizeObj(DffObjData& /* rObjData */, SdrObject* pObj) +{ + return pObj; +} + + +void SvxMSDffManager::StoreShapeOrder(sal_uLong nId, + sal_uLong nTxBx, + SdrObject* pObject, + SwFlyFrameFormat* pFly) const +{ + for (const auto& pOrder : m_aShapeOrders) + { + if (pOrder->nShapeId == nId) + { + pOrder->nTxBxComp = nTxBx; + pOrder->pObj = pObject; + pOrder->pFly = pFly; + } + } +} + + +void SvxMSDffManager::ExchangeInShapeOrder( SdrObject const * pOldObject, + sal_uLong nTxBx, + SdrObject* pObject) const +{ + for (const auto& pOrder : m_aShapeOrders) + { + if (pOrder->pObj == pOldObject) + { + pOrder->pFly = nullptr; + pOrder->pObj = pObject; + pOrder->nTxBxComp = nTxBx; + } + } +} + + +void SvxMSDffManager::RemoveFromShapeOrder( SdrObject const * pObject ) const +{ + for (const auto& pOrder : m_aShapeOrders) + { + if (pOrder->pObj == pObject) + { + pOrder->pObj = nullptr; + pOrder->pFly = nullptr; + pOrder->nTxBxComp = 0; + } + } +} + + +// exported class: Public Methods + +SvxMSDffManager::SvxMSDffManager(SvStream& rStCtrl_, + OUString aBaseURL, + sal_uInt32 nOffsDgg_, + SvStream* pStData_, + SdrModel* pSdrModel_,// see SetModel() below + tools::Long nApplicationScale, + Color mnDefaultColor_, + SvStream* pStData2_, + bool bSkipImages ) + :DffPropertyReader( *this ), + m_pBLIPInfos( new SvxMSDffBLIPInfos ), + m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ), + nOffsDgg( nOffsDgg_ ), + nBLIPCount( USHRT_MAX ), // initialize with error, since we first check if the + nGroupShapeFlags(ShapeFlag::NONE), // ensure initialization here, as some corrupted + // files may yield to this being uninitialized + maBaseURL(std::move( aBaseURL )), + mnIdClusters(0), + rStCtrl( rStCtrl_ ), + pStData( pStData_ ), + pStData2( pStData2_ ), + nSvxMSDffSettings( 0 ), + nSvxMSDffOLEConvFlags( 0 ), + mnDefaultColor( mnDefaultColor_), + mbSkipImages (bSkipImages) +{ + SetModel( pSdrModel_, nApplicationScale ); + + // remember FilePos of the stream(s) + sal_uInt64 nOldPosCtrl = rStCtrl.Tell(); + sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl; + + // if no data stream is given we assume that the BLIPs + // are in the control stream + if( !pStData ) + pStData = &rStCtrl; + + SetDefaultPropSet( rStCtrl, nOffsDgg ); + + // read control stream, if successful set nBLIPCount + GetCtrlData( nOffsDgg ); + + // check Text-Box-Story-Chain-Infos + CheckTxBxStoryChain(); + + // restore old FilePos of the stream(s) + rStCtrl.Seek( nOldPosCtrl ); + if( &rStCtrl != pStData ) + pStData->Seek( nOldPosData ); +} + +SvxMSDffManager::SvxMSDffManager( SvStream& rStCtrl_, OUString aBaseURL ) + :DffPropertyReader( *this ), + m_pBLIPInfos( new SvxMSDffBLIPInfos ), + m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ), + nOffsDgg( 0 ), + nBLIPCount( USHRT_MAX ), // initialize with error, since we first have to check + nGroupShapeFlags(ShapeFlag::NONE), + maBaseURL(std::move( aBaseURL )), + mnIdClusters(0), + rStCtrl( rStCtrl_ ), + pStData( nullptr ), + pStData2( nullptr ), + nSvxMSDffSettings( 0 ), + nSvxMSDffOLEConvFlags( 0 ), + mnDefaultColor( COL_DEFAULT ), + mbSkipImages(false) +{ + SetModel( nullptr, 0 ); +} + +SvxMSDffManager::~SvxMSDffManager() +{ +} + +void SvxMSDffManager::InitSvxMSDffManager( sal_uInt32 nOffsDgg_, SvStream* pStData_, sal_uInt32 nOleConvFlags ) +{ + nOffsDgg = nOffsDgg_; + pStData = pStData_; + nSvxMSDffOLEConvFlags = nOleConvFlags; + + // remember FilePos of the stream(s) + sal_uInt64 nOldPosCtrl = rStCtrl.Tell(); + + SetDefaultPropSet( rStCtrl, nOffsDgg ); + + // insert fidcl cluster table + GetFidclData( nOffsDgg ); + + // read control stream, if successful, set nBLIPCount + GetCtrlData( nOffsDgg ); + + // check Text-Box-Story-Chain-Infos + CheckTxBxStoryChain(); + + // restore old FilePos of the stream(s) + rStCtrl.Seek( nOldPosCtrl ); +} + +void SvxMSDffManager::SetDgContainer( SvStream& rSt ) +{ + sal_uInt64 nFilePos = rSt.Tell(); + DffRecordHeader aDgContHd; + bool bOk = ReadDffRecordHeader(rSt, aDgContHd); + // insert this container only if there is also a DggAtom + if (bOk && SeekToRec(rSt, DFF_msofbtDg, aDgContHd.GetRecEndFilePos())) + { + DffRecordHeader aRecHd; + if (ReadDffRecordHeader(rSt, aRecHd)) + { + sal_uInt32 nDrawingId = aRecHd.nRecInstance; + maDgOffsetTable[nDrawingId] = nFilePos; + } + } + rSt.Seek(nFilePos); +} + +void SvxMSDffManager::GetFidclData( sal_uInt32 nOffsDggL ) +{ + if (!nOffsDggL) + return; + + sal_uInt64 nOldPos = rStCtrl.Tell(); + + if (nOffsDggL == rStCtrl.Seek(nOffsDggL)) + { + DffRecordHeader aRecHd; + bool bOk = ReadDffRecordHeader(rStCtrl, aRecHd); + + DffRecordHeader aDggAtomHd; + if (bOk && SeekToRec(rStCtrl, DFF_msofbtDgg, aRecHd.GetRecEndFilePos(), &aDggAtomHd)) + { + aDggAtomHd.SeekToContent( rStCtrl ); + sal_uInt32 nCurMaxShapeId; + sal_uInt32 nDummy; + rStCtrl.ReadUInt32( nCurMaxShapeId ) + .ReadUInt32( mnIdClusters ) + .ReadUInt32( nDummy ) + .ReadUInt32( nDummy ); // nDrawingsSaved + + if ( mnIdClusters-- > 2 ) + { + const std::size_t nFIDCLsize = sizeof(sal_uInt32) * 2; + if ( aDggAtomHd.nRecLen == ( mnIdClusters * nFIDCLsize + 16 ) ) + { + sal_uInt64 nMaxEntriesPossible = rStCtrl.remainingSize() / nFIDCLsize; + SAL_WARN_IF(nMaxEntriesPossible < mnIdClusters, + "filter.ms", "FIDCL list longer than remaining bytes, ppt or parser is wrong"); + mnIdClusters = std::min(nMaxEntriesPossible, static_cast(mnIdClusters)); + + maFidcls.resize(mnIdClusters); + for (sal_uInt32 i = 0; i < mnIdClusters; ++i) + { + sal_uInt32 cspidCur; ///< number of SPIDs used so far + rStCtrl.ReadUInt32( maFidcls[ i ].dgid ) + .ReadUInt32( cspidCur ); + } + } + } + } + } + rStCtrl.Seek( nOldPos ); +} + +void SvxMSDffManager::CheckTxBxStoryChain() +{ + m_xShapeInfosById.reset(new SvxMSDffShapeInfos_ById); + // mangle old Info array, sorted by nTxBxComp + sal_uInt32 nChain = std::numeric_limits::max(); + bool bSetReplaceFALSE = false; + for (SvxMSDffShapeInfos_ByTxBxComp::iterator iter = + m_xShapeInfosByTxBxComp->begin(), + mark = m_xShapeInfosByTxBxComp->begin(); + iter != m_xShapeInfosByTxBxComp->end(); ++iter) + { + std::shared_ptr const pObj = *iter; + if( pObj->nTxBxComp ) + { + // group change? + // the text id also contains an internal drawing container id + // to distinguish between text id of drawing objects in different + // drawing containers. + if( nChain != pObj->nTxBxComp ) + { + // reset mark and helper flag + mark = iter; + nChain = pObj->nTxBxComp; + bSetReplaceFALSE = !pObj->bReplaceByFly; + } + else if( !pObj->bReplaceByFly ) + { + // object that must NOT be replaced by frame? + bSetReplaceFALSE = true; + // maybe reset flags in start of group + for (SvxMSDffShapeInfos_ByTxBxComp::iterator itemp = mark; + itemp != iter; ++itemp) + { + (*itemp)->bReplaceByFly = false; + } + } + + if( bSetReplaceFALSE ) + { + pObj->bReplaceByFly = false; + } + } + // copy all Shape Info objects to m_xShapeInfosById, sorted by nShapeId + pObj->nTxBxComp = pObj->nTxBxComp & 0xFFFF0000; + m_xShapeInfosById->insert( pObj ); + } + // free original array but don't free its elements + m_xShapeInfosByTxBxComp.reset(); +} + + +/***************************************************************************** + + Reading the Shape-Infos in the Ctor: + --------------------------------- + remembering the Shape-Ids and the associated Blip-Numbers and TextBox-Infos + ========= ============ ============= + and remembering the File-Offsets for each Blip + ============ +******************************************************************************/ +void SvxMSDffManager::GetCtrlData(sal_uInt32 nOffsDggL) +{ + // position control stream + if (!checkSeek(rStCtrl, nOffsDggL)) + return; + + sal_uInt8 nVer; + sal_uInt16 nInst; + sal_uInt16 nFbt; + sal_uInt32 nLength; + if( !ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) ) return; + + sal_uInt64 nPos = nOffsDggL + DFF_COMMON_RECORD_HEADER_SIZE; + + // case A: first Drawing Group Container, then n times Drawing Container + if( DFF_msofbtDggContainer != nFbt ) + return; + + bool bOk; + GetDrawingGroupContainerData( rStCtrl, nLength ); + + sal_uInt64 nMaxStrPos = rStCtrl.TellEnd(); + + nPos += nLength; + sal_uInt16 nDrawingContainerId = 1; + do + { + if (!checkSeek(rStCtrl, nPos)) + break; + + bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) && ( DFF_msofbtDgContainer == nFbt ); + + if( !bOk ) + { + nPos++; // ????????? TODO: trying to get a one-hit wonder, this code should be rewritten... + if (nPos != rStCtrl.Seek(nPos)) + break; + bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) + && ( DFF_msofbtDgContainer == nFbt ); + } + if( bOk ) + { + GetDrawingContainerData( rStCtrl, nLength, nDrawingContainerId ); + } + nPos += DFF_COMMON_RECORD_HEADER_SIZE + nLength; + ++nDrawingContainerId; + } + while( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( nPos < nMaxStrPos ) && bOk ); +} + + +// from here on: Drawing Group Container i.e. document-wide valid data + +void SvxMSDffManager::GetDrawingGroupContainerData( SvStream& rSt, sal_uInt32 nLenDgg ) +{ + sal_uInt8 nVer; + sal_uInt16 nInst; + sal_uInt16 nFbt; + sal_uInt32 nLength; + + sal_uInt32 nLenBStoreCont = 0, nLenFBSE = 0; + sal_uLong nRead = 0; + + // search for a BStore Container + bool bOk = true; + do + { + if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength)) + return; + nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength; + if (DFF_msofbtBstoreContainer == nFbt) + { + nLenBStoreCont = nLength; + break; + } + bOk = checkSeek(rSt, rSt.Tell() + nLength); + } + while (bOk && nRead < nLenDgg); + + if (!bOk || !nLenBStoreCont) + return; + + // Read all atoms of the containers from the BStore container and store all + // relevant data of all contained FBSEs in out pointer array. + // We also count all found FBSEs in member nBLIPCount. + + const sal_uLong nSkipBLIPLen = 20; // skip to get to the nBLIPLen + const sal_uLong nSkipBLIPPos = 4; // thereafter skip up to nBLIPPos + + sal_uInt32 nBLIPLen = 0, nBLIPPos = 0; + + nRead = 0; + do + { + if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return; + nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength; + if( DFF_msofbtBSE == nFbt && /* magic value from spec */ 0x2 == nVer ) + { + nLenFBSE = nLength; + // is FBSE big enough for our data + bOk = ( nSkipBLIPLen + 4 + nSkipBLIPPos + 4 <= nLenFBSE ); + + if (bOk) + { + rSt.SeekRel( nSkipBLIPLen ); + rSt.ReadUInt32( nBLIPLen ); + rSt.SeekRel( nSkipBLIPPos ); + rSt.ReadUInt32( nBLIPPos ); + bOk = rSt.GetError() == ERRCODE_NONE; + + nLength -= nSkipBLIPLen+ 4 + nSkipBLIPPos + 4; + } + + if (bOk) + { + // specialty: + // If nBLIPLen is less than nLenFBSE AND nBLIPPos is NULL, + // then we assume, that the image is in FBSE! + if( (!nBLIPPos) && (nBLIPLen < nLenFBSE) ) + nBLIPPos = rSt.Tell() + 4; + + if( USHRT_MAX == nBLIPCount ) + nBLIPCount = 1; + else + nBLIPCount++; + + // now save the info for later access + m_pBLIPInfos->push_back(SvxMSDffBLIPInfo(nBLIPPos)); + } + if (!checkSeek(rSt, rSt.Tell() + nLength)) + return; // invalid offset + } + else return; // invalid input + } + while( nRead < nLenBStoreCont ); +} + + +// from now on: Drawing Container which means Pages (Sheet, Slide) - wide valid data +// ================= ====== + +void SvxMSDffManager::GetDrawingContainerData( SvStream& rSt, sal_uInt32 nLenDg, + sal_uInt16 nDrawingContainerId ) +{ + sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength; + + sal_uLong nReadDg = 0; + + // We are now in a drawing container (one per each page) and + // we now have to iterate through all contained shape group containers + do + { + if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength)) + return; + nReadDg += DFF_COMMON_RECORD_HEADER_SIZE; + // Patriarch found (the upmost shape group container) ? + if (DFF_msofbtSpgrContainer == nFbt) + { + if (!GetShapeGroupContainerData(rSt, nLength, true, nDrawingContainerId)) + return; + } + // empty Shape Container ? (outside of shape group container) + else if (DFF_msofbtSpContainer == nFbt) + { + if (!GetShapeContainerData( + rSt, nLength, std::numeric_limits::max(), nDrawingContainerId)) + return; + } + else + { + if (!checkSeek(rSt, rSt.Tell() + nLength)) + return; + } + nReadDg += nLength; + } + while( nReadDg < nLenDg ); +} + +bool SvxMSDffManager::GetShapeGroupContainerData( SvStream& rSt, + sal_uInt32 nLenShapeGroupCont, + bool bPatriarch, + sal_uInt16 nDrawingContainerId ) +{ + sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength; + sal_uInt64 nStartShapeGroupCont = rSt.Tell(); + // We are now in a shape group container (conditionally multiple per page) + // and we now have to iterate through all contained shape containers + bool bFirst = !bPatriarch; + sal_uLong nReadSpGrCont = 0; + do + { + if( !ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength ) ) + return false; + nReadSpGrCont += DFF_COMMON_RECORD_HEADER_SIZE; + // Shape Container? + if( DFF_msofbtSpContainer == nFbt ) + { + sal_uInt64 nGroupOffs = bFirst ? nStartShapeGroupCont - DFF_COMMON_RECORD_HEADER_SIZE : std::numeric_limits::max(); + if ( !GetShapeContainerData( rSt, nLength, nGroupOffs, nDrawingContainerId ) ) + return false; + bFirst = false; + } + // nested shape group container ? + else if( DFF_msofbtSpgrContainer == nFbt ) + { + if ( !GetShapeGroupContainerData( rSt, nLength, false, nDrawingContainerId ) ) + return false; + } + else + { + if (!checkSeek(rSt, rSt.Tell() + nLength)) + return false; + } + nReadSpGrCont += nLength; + } + while( nReadSpGrCont < nLenShapeGroupCont ); + // position the stream correctly + rSt.Seek( nStartShapeGroupCont + nLenShapeGroupCont ); + return true; +} + +bool SvxMSDffManager::GetShapeContainerData( SvStream& rSt, + sal_uInt32 nLenShapeCont, + sal_uInt64 nPosGroup, + sal_uInt16 nDrawingContainerId ) +{ + sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength; + sal_uInt64 nStartShapeCont = rSt.Tell(); + + // We are in a shape container (possibly more than one per shape group) and we now + // have to fetch the shape id and file position (to be able to access them again later) + // and the first BStore reference (if present). + sal_uInt32 nLenShapePropTbl = 0; + sal_uLong nReadSpCont = 0; + + // Store file offset of the shape containers or respectively the group(!). + sal_uInt64 nStartOffs = (std::numeric_limits::max() > nPosGroup) ? + nPosGroup : nStartShapeCont - DFF_COMMON_RECORD_HEADER_SIZE; + SvxMSDffShapeInfo aInfo( nStartOffs ); + + // Can the shape be replaced with a frame? + // (provided that it is a TextBox and the text is not rotated) + bool bCanBeReplaced = nPosGroup >= std::numeric_limits::max(); + + // we don't know yet whether it's a TextBox + MSO_SPT eShapeType = mso_sptNil; + + // analyze Shape + + do + { + if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return false; + nReadSpCont += DFF_COMMON_RECORD_HEADER_SIZE; + // FSP ? + if( ( DFF_msofbtSp == nFbt ) && ( 4 <= nLength ) ) + { + // we've found the FSP: note Shape Type and Id! + eShapeType = static_cast(nInst); + rSt.ReadUInt32( aInfo.nShapeId ); + rSt.SeekRel( nLength - 4 ); + nReadSpCont += nLength; + } + else if( DFF_msofbtOPT == nFbt ) // Shape Property Table ? + { + // We've found the Property Table: + // search for the Blip Property! + sal_uLong nPropRead = 0; + nLenShapePropTbl = nLength; + auto nStartShapePropTbl = rSt.Tell(); + do + { + sal_uInt16 nPropId(0); + sal_uInt32 nPropVal(0); + + rSt.ReadUInt16( nPropId ) + .ReadUInt32( nPropVal ); + nPropRead += 6; + + switch( nPropId ) + { + case DFF_Prop_txflTextFlow : + //Writer can now handle vertical textflows in its + //native frames, to only need to do this for the + //other two formats + + //Writer will handle all textflow except BtoT + if (GetSvxMSDffSettings() & + (SVXMSDFF_SETTINGS_IMPORT_PPT | + SVXMSDFF_SETTINGS_IMPORT_EXCEL)) + { + if( 0 != nPropVal ) + bCanBeReplaced = false; + } + else if ( + (nPropVal != mso_txflHorzN) && + (nPropVal != mso_txflTtoBA) + ) + { + bCanBeReplaced = false; + } + break; + case DFF_Prop_cdirFont : + //Writer can now handle right to left and left + //to right in its native frames, so only do + //this for the other two formats. + if (GetSvxMSDffSettings() & + (SVXMSDFF_SETTINGS_IMPORT_PPT | + SVXMSDFF_SETTINGS_IMPORT_EXCEL)) + { + if( 0 != nPropVal ) + bCanBeReplaced = false; + } + break; + case DFF_Prop_Rotation : + if( 0 != nPropVal ) + bCanBeReplaced = false; + break; + + case DFF_Prop_gtextFStrikethrough : + if( ( 0x20002000 & nPropVal ) == 0x20002000 ) + bCanBeReplaced = false; + break; + + case DFF_Prop_fc3DLightFace : + if( ( 0x00080008 & nPropVal ) == 0x00080008 ) + bCanBeReplaced = false; + break; + + case DFF_Prop_WrapText : + //TODO: eWrapMode = (MSO_WrapMode)nPropVal; + break; + + default: + { + // is the Bit set and valid? + if( 0x4000 == ( nPropId & 0xC000 ) ) + { + // Blip Property found: remember BStore Idx! + nPropRead = nLenShapePropTbl; + } + else if( 0x8000 & nPropId ) + { + // complex Prop found: + // Length is always 6. The length of the appended extra data + // after the actual prop table is of different size. + nPropVal = 6; + } + } + break; + } + } + while (rSt.good() && nPropRead < nLenShapePropTbl); + rSt.Seek( nStartShapePropTbl + nLenShapePropTbl ); + nReadSpCont += nLenShapePropTbl; + } + else if( ( DFF_msofbtClientTextbox == nFbt ) && ( 4 == nLength ) ) // Text-Box-Story-Entry found + { + rSt.ReadUInt32( aInfo.nTxBxComp ); + // Add internal drawing container id to text id. + // Note: The text id uses the first two bytes, while the internal + // drawing container id used the second two bytes. + aInfo.nTxBxComp = ( aInfo.nTxBxComp & 0xFFFF0000 ) + + nDrawingContainerId; + DBG_ASSERT( (aInfo.nTxBxComp & 0x0000FFFF) == nDrawingContainerId, + " - internal drawing container Id could not be correctly merged into DFF_msofbtClientTextbox value." ); + } + else + { + if (!checkSeek(rSt, rSt.Tell() + nLength)) + { + SAL_WARN("filter.ms", "remaining record longer than available data, ppt or parser is wrong"); + break; + } + nReadSpCont += nLength; + } + } + while( nReadSpCont < nLenShapeCont ); + + + // Now possibly store the information for subsequent accesses to the shape + + if( aInfo.nShapeId ) + { + // Possibly allow replacement of textboxes with frames + if( bCanBeReplaced + && aInfo.nTxBxComp + && ( + ( eShapeType == mso_sptTextSimple ) + || ( eShapeType == mso_sptTextBox ) + || ( eShapeType == mso_sptRectangle ) + || ( eShapeType == mso_sptRoundRectangle ) + ) ) + { + aInfo.bReplaceByFly = true; + } + m_xShapeInfosByTxBxComp->insert(std::make_shared( + aInfo)); + m_aShapeOrders.push_back(std::make_unique( + aInfo.nShapeId )); + } + + // and position the Stream correctly again + rSt.Seek( nStartShapeCont + nLenShapeCont ); + return true; +} + + +/***************************************************************************** + + Access to a shape at runtime (via the Shape-Id) + ---------------------------- +******************************************************************************/ +bool SvxMSDffManager::GetShape(sal_uLong nId, SdrObject*& rpShape, + SvxMSDffImportData& rData) +{ + auto const pTmpRec = std::make_shared(0, nId); + + SvxMSDffShapeInfos_ById::const_iterator const it = + m_xShapeInfosById->find(pTmpRec); + if (it == m_xShapeInfosById->end()) + return false; + + // Possibly delete old error flag. + if( rStCtrl.GetError() ) + rStCtrl.ResetError(); + // store FilePos of the stream(s) + sal_uInt64 nOldPosCtrl = rStCtrl.Tell(); + sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl; + // jump to the shape in the control stream + sal_uInt64 const nFilePos((*it)->nFilePos); + bool bSeeked = (nFilePos == rStCtrl.Seek(nFilePos)); + + // if it failed, reset error statusF + if (!bSeeked || rStCtrl.GetError()) + rStCtrl.ResetError(); + else + rpShape = ImportObj( rStCtrl, rData, rData.aParentRect, rData.aParentRect, /*nCalledByGroup*/0, /*pShapeId*/nullptr ); + + // restore old FilePos of the stream(s) + rStCtrl.Seek( nOldPosCtrl ); + if( &rStCtrl != pStData && pStData ) + pStData->Seek( nOldPosData ); + return ( nullptr != rpShape ); +} + + +/** Access to a BLIP at runtime (if the Blip-Number is already known) + */ +bool SvxMSDffManager::GetBLIP( sal_uLong nIdx_, Graphic& rGraphic, tools::Rectangle* pVisArea ) +{ + if (!pStData) + return false; + + bool bOk = false; // initialize result variable + + // check if a graphic for this blipId is already imported + if (nIdx_) + { + auto iter = aEscherBlipCache.find(nIdx_); + + if (iter != aEscherBlipCache.end()) + { + /* if this entry is available */ + rGraphic = iter->second; + if (rGraphic.GetType() != GraphicType::NONE) + bOk = true; + else + aEscherBlipCache.erase(iter); + } + } + + if (!bOk) + { + sal_uInt16 nIdx = sal_uInt16( nIdx_ ); + if (!nIdx || (m_pBLIPInfos->size() < nIdx)) + return false; + + // possibly delete old error flag(s) + if( rStCtrl.GetError() ) + rStCtrl.ResetError(); + if( ( &rStCtrl != pStData ) + && pStData->GetError() ) + pStData->ResetError(); + + // remember FilePos of the stream(s) + sal_uInt64 nOldPosCtrl = rStCtrl.Tell(); + sal_uInt64 nOldPosData = pStData->Tell(); + + // fetch matching info struct out of the pointer array + SvxMSDffBLIPInfo& rInfo = (*m_pBLIPInfos)[ nIdx-1 ]; + // jump to the BLIP atom in the data stream + bOk = checkSeek(*pStData, rInfo.nFilePos); + // possibly reset error status + if (!bOk || pStData->GetError()) + pStData->ResetError(); + else + bOk = GetBLIPDirect( *pStData, rGraphic, pVisArea ); + if( pStData2 && !bOk ) + { + // Error, but the is a second chance: There is a second + // data stream in which the graphic could be stored! + if( pStData2->GetError() ) + pStData2->ResetError(); + sal_uInt64 nOldPosData2 = pStData2->Tell(); + // jump to the BLIP atom in the second data stream + bOk = checkSeek(*pStData2, rInfo.nFilePos); + // reset error status if necessary + if (!bOk || pStData2->GetError()) + pStData2->ResetError(); + else + bOk = GetBLIPDirect( *pStData2, rGraphic, pVisArea ); + // restore of FilePos of the second data stream + pStData2->Seek( nOldPosData2 ); + } + // restore old FilePos of the stream(s) + rStCtrl.Seek( nOldPosCtrl ); + if( &rStCtrl != pStData ) + pStData->Seek( nOldPosData ); + + if (bOk) + { + // create new BlipCacheEntry for this graphic + aEscherBlipCache.insert(std::make_pair(nIdx_, rGraphic)); + } + } + + return bOk; +} + +/* access to a BLIP at runtime (with correctly positioned stream) + --------------------------------- +******************************************************************************/ +bool SvxMSDffManager::GetBLIPDirect( SvStream& rBLIPStream, Graphic& rData, tools::Rectangle* pVisArea ) +{ + sal_uInt64 nOldPos = rBLIPStream.Tell(); + + ErrCode nRes = ERRCODE_GRFILTER_OPENERROR; // initialize error variable + + // check whether it's really a BLIP + sal_uInt32 nLength; + sal_uInt16 nInst, nFbt( 0 ); + sal_uInt8 nVer; + if( ReadCommonRecordHeader( rBLIPStream, nVer, nInst, nFbt, nLength) && ( 0xF018 <= nFbt ) && ( 0xF117 >= nFbt ) ) + { + Size aMtfSize100; + bool bMtfBLIP = false; + bool bZCodecCompression = false; + // now position it exactly at the beginning of the embedded graphic + sal_uLong nSkip = (nInst & 0x0001) ? 32 : 16; + const OfficeArtBlipRecInstance aRecInstanse = OfficeArtBlipRecInstance(nInst & 0xFFFE); + switch (aRecInstanse) + { + case OfficeArtBlipRecInstance::EMF: + case OfficeArtBlipRecInstance::WMF: + case OfficeArtBlipRecInstance::PICT: + { + rBLIPStream.SeekRel(nSkip + 20); + + // read in size of metafile in English Metric Units (EMUs) + sal_Int32 width(0), height(0); + rBLIPStream.ReadInt32(width).ReadInt32(height); + aMtfSize100.setWidth(width); + aMtfSize100.setHeight(height); + + // 1 EMU = 1/360,000 of a centimeter + // scale to 1/100mm + aMtfSize100.setWidth(aMtfSize100.Width() / 360); + aMtfSize100.setHeight(aMtfSize100.Height() / 360); + + if (pVisArea) // seem that we currently are skipping the visarea position + *pVisArea = tools::Rectangle(Point(), aMtfSize100); + + // skip rest of header + nSkip = 6; + bMtfBLIP = bZCodecCompression = true; + } + break; + case OfficeArtBlipRecInstance::JPEG_RGB: + case OfficeArtBlipRecInstance::JPEG_CMYK: + case OfficeArtBlipRecInstance::PNG: + case OfficeArtBlipRecInstance::DIB: + case OfficeArtBlipRecInstance::TIFF: + nSkip += 1; // Skip one byte tag + break; + } + rBLIPStream.SeekRel( nSkip ); + + SvStream* pGrStream = &rBLIPStream; + std::unique_ptr xOut; + if( bZCodecCompression ) + { + xOut.reset(new SvMemoryStream( 0x8000, 0x4000 )); + ZCodec aZCodec( 0x8000, 0x8000 ); + aZCodec.BeginCompression(); + aZCodec.Decompress( rBLIPStream, *xOut ); + aZCodec.EndCompression(); + xOut->Seek( STREAM_SEEK_TO_BEGIN ); + xOut->SetResizeOffset( 0 ); // sj: #i102257# setting ResizeOffset of 0 prevents from seeking + // behind the stream end (allocating too much memory) + pGrStream = xOut.get(); + } + +#ifdef DEBUG_FILTER_MSDFFIMP + // extract graphics from ole storage into "dbggfxNNN.*" + static sal_Int32 nGrfCount; + + OUString aFileName = "dbggfx" + OUString::number(nGrfCount++); + switch (aRecInstanse) + { + case OfficeArtBlipRecInstance::WMF: + aFileName += ".wmf"; + break; + case OfficeArtBlipRecInstance::EMF: + aFileName += ".emf"; + break; + case OfficeArtBlipRecInstance::PICT: + aFileName += ".pct"; + break; + case OfficeArtBlipRecInstance::JPEG_RGB: + case OfficeArtBlipRecInstance::JPEG_CMYK: + aFileName += ".jpg"; + break; + case OfficeArtBlipRecInstance::PNG: + aFileName += ".png"; + break; + case OfficeArtBlipRecInstance::DIB: + aFileName += ".bmp"; + break; + case OfficeArtBlipRecInstance::TIFF: + aFileName += ".tif"; + break; + } + + + OUString aURLStr; + if( osl::FileBase::getFileURLFromSystemPath( Application::GetAppFileName(), aURLStr ) == osl::FileBase::E_None ) + { + INetURLObject aURL( aURLStr ); + + aURL.removeSegment(); + aURL.removeFinalSlash(); + aURL.Append( aFileName ); + + aURLStr = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + SAL_INFO("filter.ms", "dumping " << aURLStr); + + std::unique_ptr pDbgOut(::utl::UcbStreamHelper::CreateStream(aURLStr, StreamMode::TRUNC | StreamMode::WRITE)); + + if( pDbgOut ) + { + if ( bZCodecCompression ) + { + pDbgOut->WriteBytes(xOut->GetData(), xOut->TellEnd()); + xOut->Seek(STREAM_SEEK_TO_BEGIN); + } + else + { + sal_Int32 nDbgLen = nLength - nSkip; + if ( nDbgLen ) + { + std::vector aData(nDbgLen); + pGrStream->ReadBytes(aData.data(), nDbgLen); + pDbgOut->WriteBytes(aData.data(), nDbgLen); + pGrStream->SeekRel(-nDbgLen); + } + } + } + } +#endif + if (aRecInstanse == OfficeArtBlipRecInstance::DIB) + { // getting the DIBs immediately + Bitmap aNew; + if( ReadDIB(aNew, *pGrStream, false) ) + { + rData = Graphic(BitmapEx(aNew)); + nRes = ERRCODE_NONE; + } + } + else + { // and unleash our filter + GraphicFilter& rGF = GraphicFilter::GetGraphicFilter(); + // ImportUnloadedGraphic() may simply read the entire rest of the stream, + // which may be very large if the whole document is large. Limit the read + // size to the size of this record. + sal_uInt64 maxSize = pGrStream == &rBLIPStream ? nLength : 0; + Graphic aGraphic; + + // Size available in metafile header. + if (aMtfSize100.getWidth() && aMtfSize100.getHeight()) + aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize, &aMtfSize100); + else + aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize); + + if (!aGraphic.IsNone()) + { + rData = aGraphic; + nRes = ERRCODE_NONE; + } + else + nRes = rGF.ImportGraphic( rData, u"", *pGrStream ); + + // SJ: I40472, sometimes the aspect ratio (aMtfSize100) does not match and we get scaling problems, + // then it is better to use the prefsize that is stored within the metafile. Bug #72846# for what the + // scaling has been implemented does not happen anymore. + // + // For pict graphics we will furthermore scale the metafile, because font scaling leads to error if the + // dxarray is empty (this has been solved in wmf/emf but not for pict) + if (bMtfBLIP && (ERRCODE_NONE == nRes) && (rData.GetType() == GraphicType::GdiMetafile) + && (aRecInstanse == OfficeArtBlipRecInstance::PICT)) + { + if ( ( aMtfSize100.Width() >= 1000 ) && ( aMtfSize100.Height() >= 1000 ) ) + { // #75956#, scaling does not work properly, if the graphic is less than 1cm + GDIMetaFile aMtf( rData.GetGDIMetaFile() ); + const Size aOldSize( aMtf.GetPrefSize() ); + + if( aOldSize.Width() && ( aOldSize.Width() != aMtfSize100.Width() ) && + aOldSize.Height() && ( aOldSize.Height() != aMtfSize100.Height() ) ) + { + aMtf.Scale( static_cast(aMtfSize100.Width()) / aOldSize.Width(), + static_cast(aMtfSize100.Height()) / aOldSize.Height() ); + aMtf.SetPrefSize( aMtfSize100 ); + aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + rData = aMtf; + } + } + } + } + // reset error status if necessary + if ( ERRCODE_IO_PENDING == pGrStream->GetError() ) + pGrStream->ResetError(); + } + rBLIPStream.Seek( nOldPos ); // restore old FilePos of the stream + + return ( ERRCODE_NONE == nRes ); // return result +} + +/* also static */ +bool SvxMSDffManager::ReadCommonRecordHeader(SvStream& rSt, + sal_uInt8& rVer, sal_uInt16& rInst, sal_uInt16& rFbt, sal_uInt32& rLength) +{ + sal_uInt16 nTmp(0); + rSt.ReadUInt16( nTmp ).ReadUInt16( rFbt ).ReadUInt32( rLength ); + rVer = sal::static_int_cast< sal_uInt8 >(nTmp & 15); + rInst = nTmp >> 4; + if (!rSt.good()) + return false; + if (rLength > nMaxLegalDffRecordLength) + return false; + return true; +} + +void SvxMSDffManager::ProcessClientAnchor(SvStream& rStData, sal_uInt32 nDatLen, + std::unique_ptr& rpBuff, sal_uInt32& rBuffLen ) +{ + if( nDatLen ) + { + rBuffLen = std::min(rStData.remainingSize(), static_cast(nDatLen)); + rpBuff.reset( new char[rBuffLen] ); + rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen); + } +} + +void SvxMSDffManager::ProcessClientData(SvStream& rStData, sal_uInt32 nDatLen, + std::unique_ptr& rpBuff, sal_uInt32& rBuffLen ) +{ + if( nDatLen ) + { + rBuffLen = std::min(rStData.remainingSize(), static_cast(nDatLen)); + rpBuff.reset( new char[rBuffLen] ); + rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen); + } +} + + +void SvxMSDffManager::ProcessClientAnchor2( SvStream& /* rSt */, DffRecordHeader& /* rHd */ , DffObjData& /* rObj */ ) +{ + // will be overridden by SJ in Draw +} + +bool SvxMSDffManager::GetOLEStorageName( sal_uInt32, OUString&, tools::SvRef&, uno::Reference < embed::XStorage >& ) const +{ + return false; +} + +bool SvxMSDffManager::ShapeHasText( sal_uLong /* nShapeId */, sal_uLong /* nFilePos */ ) const +{ + return true; +} + +// #i32596# - add new parameter <_nCalledByGroup> +SdrObject* SvxMSDffManager::ImportOLE( sal_uInt32 nOLEId, + const Graphic& rGrf, + const tools::Rectangle& rBoundRect, + const tools::Rectangle& rVisArea, + const int /* _nCalledByGroup */ ) const +{ + SdrObject* pRet = nullptr; + OUString sStorageName; + tools::SvRef xSrcStg; + ErrCode nError = ERRCODE_NONE; + uno::Reference < embed::XStorage > xDstStg; + if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg )) + pRet = CreateSdrOLEFromStorage( + *GetModel(), + sStorageName, + xSrcStg, + xDstStg, + rGrf, + rBoundRect, + rVisArea, + pStData, + nError, + nSvxMSDffOLEConvFlags, + embed::Aspects::MSOLE_CONTENT, + maBaseURL); + return pRet; +} + +bool SvxMSDffManager::MakeContentStream( SotStorage * pStor, const GDIMetaFile & rMtf ) +{ + tools::SvRef xStm = pStor->OpenSotStream(SVEXT_PERSIST_STREAM); + xStm->SetVersion( pStor->GetVersion() ); + xStm->SetBufferSize( 8192 ); + + Impl_OlePres aEle; + // Convert the size in 1/100 mm + // If a not applicable MapUnit (device dependent) is used, + // SV tries to guess a best match for the right value + Size aSize = rMtf.GetPrefSize(); + const MapMode& aMMSrc = rMtf.GetPrefMapMode(); + MapMode aMMDst( MapUnit::Map100thMM ); + aSize = OutputDevice::LogicToLogic( aSize, aMMSrc, aMMDst ); + aEle.SetSize( aSize ); + aEle.SetAspect( ASPECT_CONTENT ); + aEle.SetAdviseFlags( 2 ); + aEle.SetMtf( rMtf ); + aEle.Write( *xStm ); + + xStm->SetBufferSize( 0 ); + return xStm->GetError() == ERRCODE_NONE; +} + +namespace { + +struct ClsIDs { + sal_uInt32 nId; + const char* pSvrName; + const char* pDspName; +}; + +} + +const ClsIDs aClsIDs[] = { + + { 0x000212F0, "MSWordArt", "Microsoft Word Art" }, + { 0x000212F0, "MSWordArt.2", "Microsoft Word Art 2.0" }, + + // MS Apps + { 0x00030000, "ExcelWorksheet", "Microsoft Excel Worksheet" }, + { 0x00030001, "ExcelChart", "Microsoft Excel Chart" }, + { 0x00030002, "ExcelMacrosheet", "Microsoft Excel Macro" }, + { 0x00030003, "WordDocument", "Microsoft Word Document" }, + { 0x00030004, "MSPowerPoint", "Microsoft PowerPoint" }, + { 0x00030005, "MSPowerPointSho", "Microsoft PowerPoint Slide Show"}, + { 0x00030006, "MSGraph", "Microsoft Graph" }, + { 0x00030007, "MSDraw", "Microsoft Draw" }, + { 0x00030008, "Note-It", "Microsoft Note-It" }, + { 0x00030009, "WordArt", "Microsoft Word Art" }, + { 0x0003000a, "PBrush", "Microsoft PaintBrush Picture" }, + { 0x0003000b, "Equation", "Microsoft Equation Editor" }, + { 0x0003000c, "Package", "Package" }, + { 0x0003000d, "SoundRec", "Sound" }, + { 0x0003000e, "MPlayer", "Media Player" }, + // MS Demos + { 0x0003000f, "ServerDemo", "OLE 1.0 Server Demo" }, + { 0x00030010, "Srtest", "OLE 1.0 Test Demo" }, + { 0x00030011, "SrtInv", "OLE 1.0 Inv Demo" }, + { 0x00030012, "OleDemo", "OLE 1.0 Demo" }, + + // Coromandel / Dorai Swamy / 718-793-7963 + { 0x00030013, "CoromandelIntegra", "Coromandel Integra" }, + { 0x00030014, "CoromandelObjServer","Coromandel Object Server" }, + + // 3-d Visions Corp / Peter Hirsch / 310-325-1339 + { 0x00030015, "StanfordGraphics", "Stanford Graphics" }, + + // Deltapoint / Nigel Hearne / 408-648-4000 + { 0x00030016, "DGraphCHART", "DeltaPoint Graph Chart" }, + { 0x00030017, "DGraphDATA", "DeltaPoint Graph Data" }, + + // Corel / Richard V. Woodend / 613-728-8200 x1153 + { 0x00030018, "PhotoPaint", "Corel PhotoPaint" }, + { 0x00030019, "CShow", "Corel Show" }, + { 0x0003001a, "CorelChart", "Corel Chart" }, + { 0x0003001b, "CDraw", "Corel Draw" }, + + // Inset Systems / Mark Skiba / 203-740-2400 + { 0x0003001c, "HJWIN1.0", "Inset Systems" }, + + // Mark V Systems / Mark McGraw / 818-995-7671 + { 0x0003001d, "ObjMakerOLE", "MarkV Systems Object Maker" }, + + // IdentiTech / Mike Gilger / 407-951-9503 + { 0x0003001e, "FYI", "IdentiTech FYI" }, + { 0x0003001f, "FYIView", "IdentiTech FYI Viewer" }, + + // Inventa Corporation / Balaji Varadarajan / 408-987-0220 + { 0x00030020, "Stickynote", "Inventa Sticky Note" }, + + // ShapeWare Corp. / Lori Pearce / 206-467-6723 + { 0x00030021, "ShapewareVISIO10", "Shapeware Visio 1.0" }, + { 0x00030022, "ImportServer", "Spaheware Import Server" }, + + // test app SrTest + { 0x00030023, "SrvrTest", "OLE 1.0 Server Test" }, + + // test app ClTest. Doesn't really work as a server but is in reg db + { 0x00030025, "Cltest", "OLE 1.0 Client Test" }, + + // Microsoft ClipArt Gallery Sherry Larsen-Holmes + { 0x00030026, "MS_ClipArt_Gallery", "Microsoft ClipArt Gallery" }, + // Microsoft Project Cory Reina + { 0x00030027, "MSProject", "Microsoft Project" }, + + // Microsoft Works Chart + { 0x00030028, "MSWorksChart", "Microsoft Works Chart" }, + + // Microsoft Works Spreadsheet + { 0x00030029, "MSWorksSpreadsheet", "Microsoft Works Spreadsheet" }, + + // AFX apps - Dean McCrory + { 0x0003002A, "MinSvr", "AFX Mini Server" }, + { 0x0003002B, "HierarchyList", "AFX Hierarchy List" }, + { 0x0003002C, "BibRef", "AFX BibRef" }, + { 0x0003002D, "MinSvrMI", "AFX Mini Server MI" }, + { 0x0003002E, "TestServ", "AFX Test Server" }, + + // Ami Pro + { 0x0003002F, "AmiProDocument", "Ami Pro Document" }, + + // WordPerfect Presentations For Windows + { 0x00030030, "WPGraphics", "WordPerfect Presentation" }, + { 0x00030031, "WPCharts", "WordPerfect Chart" }, + + // MicroGrafx Charisma + { 0x00030032, "Charisma", "MicroGrafx Charisma" }, + { 0x00030033, "Charisma_30", "MicroGrafx Charisma 3.0" }, + { 0x00030034, "CharPres_30", "MicroGrafx Charisma 3.0 Pres" }, + // MicroGrafx Draw + { 0x00030035, "Draw", "MicroGrafx Draw" }, + // MicroGrafx Designer + { 0x00030036, "Designer_40", "MicroGrafx Designer 4.0" }, + + // STAR DIVISION + { 0x00043AD2, "FontWork", "Star FontWork" }, + + { 0, "", "" } }; + + +bool SvxMSDffManager::ConvertToOle2( SvStream& rStm, sal_uInt32 nReadLen, + const GDIMetaFile * pMtf, const tools::SvRef& rDest ) +{ + bool bMtfRead = false; + tools::SvRef xOle10Stm = rDest->OpenSotStream( "\1Ole10Native", + StreamMode::WRITE| StreamMode::SHARE_DENYALL ); + if( xOle10Stm->GetError() ) + return false; + + OUString aSvrName; + sal_uInt32 nDummy0; + sal_uInt32 nDummy1; + sal_uInt32 nBytesRead = 0; + do + { + sal_uInt32 nType(0); + sal_uInt32 nRecType(0); + sal_uInt32 nStrLen(0); + + rStm.ReadUInt32( nType ); + rStm.ReadUInt32( nRecType ); + rStm.ReadUInt32( nStrLen ); + if( nStrLen ) + { + if( 0x10000L > nStrLen ) + { + std::unique_ptr pBuf(new char[ nStrLen ]); + rStm.ReadBytes(pBuf.get(), nStrLen); + aSvrName = OUString( pBuf.get(), static_cast(nStrLen)-1, osl_getThreadTextEncoding() ); + } + else + break; + } + rStm.ReadUInt32( nDummy0 ); + rStm.ReadUInt32( nDummy1 ); + sal_uInt32 nDataLen(0); + rStm.ReadUInt32( nDataLen ); + + nBytesRead += 6 * sizeof( sal_uInt32 ) + nStrLen + nDataLen; + + if (rStm.good() && nReadLen > nBytesRead && nDataLen) + { + if( xOle10Stm.is() ) + { + std::unique_ptr pData(new sal_uInt8[ nDataLen ]); + rStm.ReadBytes(pData.get(), nDataLen); + + // write to ole10 stream + xOle10Stm->WriteUInt32( nDataLen ); + xOle10Stm->WriteBytes(pData.get(), nDataLen); + xOle10Stm = tools::SvRef(); + + // set the compobj stream + const ClsIDs* pIds; + for( pIds = aClsIDs; pIds->nId; pIds++ ) + { + if( aSvrName == OUString::createFromAscii(pIds->pSvrName) ) + break; + } + + if( pIds->nId ) + { + // found! + SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName ); + rDest->SetClass( SvGlobalName( pIds->nId, 0, 0, 0xc0,0,0,0,0,0,0,0x46 ), nCbFmt, + OUString::createFromAscii( pIds->pDspName ) ); + } + else + { + SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName ); + rDest->SetClass( SvGlobalName(), nCbFmt, aSvrName ); + } + } + else if( nRecType == 5 && !pMtf ) + { + sal_uInt64 nPos = rStm.Tell(); + sal_uInt16 sz[4]; + rStm.ReadBytes( sz, 8 ); + Graphic aGraphic; + if( ERRCODE_NONE == GraphicConverter::Import( rStm, aGraphic ) && aGraphic.GetType() != GraphicType::NONE ) + { + const GDIMetaFile& rMtf = aGraphic.GetGDIMetaFile(); + MakeContentStream( rDest.get(), rMtf ); + bMtfRead = true; + } + // set behind the data + rStm.Seek( nPos + nDataLen ); + } + else + rStm.SeekRel( nDataLen ); + } + } while (rStm.good() && nReadLen >= nBytesRead); + + if( !bMtfRead && pMtf ) + { + MakeContentStream( rDest.get(), *pMtf ); + return true; + } + + return false; +} + +static const char* GetInternalServerName_Impl( const SvGlobalName& aGlobName ) +{ + if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) + || aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) ) + return "swriter"; + else if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 ) + || aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) ) + return "scalc"; + else if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) + || aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) ) + return "simpress"; + else if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) + || aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) ) + return "sdraw"; + else if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 ) + || aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) ) + return "smath"; + else if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 ) + || aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) ) + return "schart"; + return nullptr; +} + +OUString SvxMSDffManager::GetFilterNameFromClassID( const SvGlobalName& aGlobName ) +{ + if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) ) + return "StarOffice XML (Writer)"; + + if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) ) + return "writer8"; + + if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 ) ) + return "StarOffice XML (Calc)"; + + if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) ) + return "calc8"; + + if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) ) + return "StarOffice XML (Impress)"; + + if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) ) + return "impress8"; + + if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) ) + return "StarOffice XML (Draw)"; + + if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) ) + return "draw8"; + + if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 ) ) + return "StarOffice XML (Math)"; + + if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) ) + return "math8"; + + if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 ) ) + return "StarOffice XML (Chart)"; + + if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) ) + return "chart8"; + + return OUString(); +} + +void SvxMSDffManager::ExtractOwnStream(SotStorage& rSrcStg, SvMemoryStream& rMemStream) +{ + tools::SvRef xStr + = rSrcStg.OpenSotStream("package_stream", StreamMode::STD_READ); + xStr->ReadStream(rMemStream); +} + +css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForConvertToSOObj( sal_uInt32 nConvertFlags, + SotStorage& rSrcStg, const uno::Reference < embed::XStorage >& rDestStorage, + const Graphic& rGrf, + const tools::Rectangle& rVisArea, OUString const& rBaseURL) +{ + uno::Reference < embed::XEmbeddedObject > xObj; + SvGlobalName aStgNm = rSrcStg.GetClassName(); + const char* pName = GetInternalServerName_Impl( aStgNm ); + OUString sStarName; + if ( pName ) + sStarName = OUString::createFromAscii( pName ); + else if ( nConvertFlags ) + { + static struct ObjImpType + { + sal_uInt32 nFlag; + const char* pFactoryNm; + // GlobalNameId + sal_uInt32 n1; + sal_uInt16 n2, n3; + sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15; + } const aArr[] = { + { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION3_CLASSID }, + { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION2_CLASSID }, + { OLE_WINWORD_2_STARWRITER, "swriter", MSO_WW8_CLASSID }, + // Excel table + { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL5_CLASSID }, + { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CLASSID }, + // 114465: additional Excel OLE chart classId to above. + { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CHART_CLASSID }, + // PowerPoint presentation + { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_CLASSID }, + // PowerPoint slide + { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_SLIDE_CLASSID }, + { 0, nullptr, + 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + for( const ObjImpType* pArr = aArr; pArr->nFlag; ++pArr ) + { + if( nConvertFlags & pArr->nFlag ) + { + SvGlobalName aTypeName( pArr->n1, pArr->n2, pArr->n3, + pArr->b8, pArr->b9, pArr->b10, pArr->b11, + pArr->b12, pArr->b13, pArr->b14, pArr->b15 ); + + if ( aStgNm == aTypeName ) + { + sStarName = OUString::createFromAscii( pArr->pFactoryNm ); + break; + } + } + } + } + + if ( sStarName.getLength() ) + { + //TODO/MBA: check if (and when) storage and stream will be destroyed! + std::shared_ptr pFilter; + SvMemoryStream aMemStream; + if ( pName ) + { + // TODO/LATER: perhaps we need to retrieve VisArea and Metafile from the storage also + SvxMSDffManager::ExtractOwnStream(rSrcStg, aMemStream); + } + else + { + tools::SvRef xStorage = new SotStorage( false, aMemStream ); + rSrcStg.CopyTo( xStorage.get() ); + xStorage->Commit(); + xStorage.clear(); + OUString aType = SfxFilter::GetTypeFromStorage( rSrcStg ); + if (aType.getLength() && !utl::ConfigManager::IsFuzzing()) + { + SfxFilterMatcher aMatch( sStarName ); + pFilter = aMatch.GetFilter4EA( aType ); + } + } + +#ifdef DEBUG_FILTER_MSFILTER + // extract embedded ole streams into "/tmp/embedded_stream_NNN" + static sal_Int32 nOleCount(0); + OUString aTmpName("/tmp/embedded_stream_"); + aTmpName += OUString::number(nOleCount++); + aTmpName += ".bin"; + SvFileStream aTmpStream(aTmpName,StreamMode::READ|StreamMode::WRITE|StreamMode::TRUNC); + xMemStream->Seek(0); + aTmpStream.WriteStream(*xMemStream); + aTmpStream.Close(); +#endif + if ( pName || pFilter ) + { + //Reuse current ole name + OUString aDstStgName = MSO_OLE_Obj + OUString::number(nMSOleObjCntr); + + OUString aFilterName; + if ( pFilter ) + aFilterName = pFilter->GetName(); + else + aFilterName = SvxMSDffManager::GetFilterNameFromClassID( aStgNm ); + + uno::Sequence aMedium(aFilterName.isEmpty() ? 3 : 4); + auto pMedium = aMedium.getArray(); + pMedium[0].Name = "InputStream"; + uno::Reference < io::XInputStream > xStream = new ::utl::OSeekableInputStreamWrapper( aMemStream ); + pMedium[0].Value <<= xStream; + pMedium[1].Name = "URL"; + pMedium[1].Value <<= OUString( "private:stream" ); + pMedium[2].Name = "DocumentBaseURL"; + pMedium[2].Value <<= rBaseURL; + + if ( !aFilterName.isEmpty() ) + { + pMedium[3].Name = "FilterName"; + pMedium[3].Value <<= aFilterName; + } + + OUString aName( aDstStgName ); + comphelper::EmbeddedObjectContainer aCnt( rDestStorage ); + xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL); + + if ( !xObj.is() ) + { + if( !aFilterName.isEmpty() ) + { + // throw the filter parameter away as workaround + aMedium.realloc( 2 ); + xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL); + } + + if ( !xObj.is() ) + return xObj; + } + + // JP 26.10.2001: Bug 93374 / 91928 the writer + // objects need the correct visarea needs the + // correct visarea, but this is not true for + // PowerPoint (see bugdoc 94908b) + // SJ: 19.11.2001 bug 94908, also chart objects + // needs the correct visarea + + // If pName is set this is an own embedded object, it should have the correct size internally + // TODO/LATER: it might make sense in future to set the size stored in internal object + if( !pName && ( sStarName == "swriter" || sStarName == "scalc" ) ) + { + // TODO/LATER: ViewAspect must be passed from outside! + sal_Int64 nViewAspect = embed::Aspects::MSOLE_CONTENT; + MapMode aMapMode( VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nViewAspect ) ) ); + Size aSz; + if ( rVisArea.IsEmpty() ) + aSz = lcl_GetPrefSize(rGrf, aMapMode ); + else + { + aSz = rVisArea.GetSize(); + aSz = OutputDevice::LogicToLogic( aSz, MapMode( MapUnit::Map100thMM ), aMapMode ); + } + + // don't modify the object + //TODO/LATER: remove those hacks, that needs to be done differently! + //xIPObj->EnableSetModified( sal_False ); + awt::Size aSize; + aSize.Width = aSz.Width(); + aSize.Height = aSz.Height(); + xObj->setVisualAreaSize( nViewAspect, aSize ); + //xIPObj->EnableSetModified( sal_True ); + } + else if ( sStarName == "smath" ) + { // SJ: force the object to recalc its visarea + //TODO/LATER: wait for PrinterChangeNotification + //xIPObj->OnDocumentPrinterChanged( NULL ); + } + } + } + + return xObj; +} + +// TODO/MBA: code review and testing! +SdrOle2Obj* SvxMSDffManager::CreateSdrOLEFromStorage( + SdrModel& rSdrModel, + const OUString& rStorageName, + tools::SvRef const & rSrcStorage, + const uno::Reference < embed::XStorage >& xDestStorage, + const Graphic& rGrf, + const tools::Rectangle& rBoundRect, + const tools::Rectangle& rVisArea, + SvStream* pDataStrm, + ErrCode& rError, + sal_uInt32 nConvertFlags, + sal_Int64 nRecommendedAspect, + OUString const& rBaseURL) +{ + sal_Int64 nAspect = nRecommendedAspect; + SdrOle2Obj* pRet = nullptr; + if( rSrcStorage.is() && xDestStorage.is() && rStorageName.getLength() ) + { + comphelper::EmbeddedObjectContainer aCnt( xDestStorage ); + // does the 01Ole-Stream exist at all? + // (that's not the case for e.g. Fontwork ) + // If that's not the case -> include it as graphic + bool bValidStorage = false; + OUString aDstStgName = MSO_OLE_Obj + OUString::number( ++nMSOleObjCntr ); + + { + tools::SvRef xObjStg = rSrcStorage->OpenSotStorage( rStorageName ); + if( xObjStg.is() ) + { + { + sal_uInt8 aTestA[10]; // exist the \1CompObj-Stream ? + tools::SvRef xSrcTst = xObjStg->OpenSotStream( "\1CompObj" ); + bValidStorage = xSrcTst.is() && sizeof( aTestA ) == + xSrcTst->ReadBytes(aTestA, sizeof(aTestA)); + if( !bValidStorage ) + { + // or the \1Ole-Stream ? + xSrcTst = xObjStg->OpenSotStream( "\1Ole" ); + bValidStorage = xSrcTst.is() && sizeof(aTestA) == + xSrcTst->ReadBytes(aTestA, sizeof(aTestA)); + } + } + + if( bValidStorage ) + { + if ( nAspect != embed::Aspects::MSOLE_ICON ) + { + // check whether the object is iconified one + // usually this information is already known, the only exception + // is a kind of embedded objects in Word documents + // TODO/LATER: should the caller be notified if the aspect changes in future? + + tools::SvRef xObjInfoSrc = xObjStg->OpenSotStream( + "\3ObjInfo", StreamMode::STD_READ ); + if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() ) + { + sal_uInt8 nByte = 0; + xObjInfoSrc->ReadUChar( nByte ); + if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON ) + nAspect = embed::Aspects::MSOLE_ICON; + } + } + + uno::Reference < embed::XEmbeddedObject > xObj( CheckForConvertToSOObj( + nConvertFlags, *xObjStg, xDestStorage, rGrf, + rVisArea, rBaseURL)); + if ( xObj.is() ) + { + // remember file name to use in the title bar + INetURLObject aURL(rBaseURL); + xObj->setContainerName(aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset)); + + svt::EmbeddedObjectRef aObj( xObj, nAspect ); + + // TODO/LATER: need MediaType + aObj.SetGraphic( rGrf, OUString() ); + + // TODO/MBA: check setting of PersistName + pRet = new SdrOle2Obj( + rSdrModel, + aObj, + OUString(), + rBoundRect); + + // we have the Object, don't create another + bValidStorage = false; + } + } + } + } + + if( bValidStorage ) + { + // object is not an own object + tools::SvRef xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName, StreamMode::READWRITE ); + + if ( xObjStor.is() ) + { + tools::SvRef xSrcStor = rSrcStorage->OpenSotStorage( rStorageName, StreamMode::READ ); + xSrcStor->CopyTo( xObjStor.get() ); + + if( !xObjStor->GetError() ) + xObjStor->Commit(); + + if( xObjStor->GetError() ) + { + rError = xObjStor->GetError(); + bValidStorage = false; + } + else if( !xObjStor.is() ) + bValidStorage = false; + } + } + else if( pDataStrm ) + { + sal_uInt32 nLen(0), nDummy(0); + pDataStrm->ReadUInt32( nLen ).ReadUInt32( nDummy ); + if( ERRCODE_NONE != pDataStrm->GetError() || + // Id in BugDoc - exist there other Ids? + // The ConvertToOle2 - does not check for consistent + 0x30008 != nDummy ) + bValidStorage = false; + else + { + // or is it an OLE-1 Stream in the DataStream? + tools::SvRef xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName ); + //TODO/MBA: remove metafile conversion from ConvertToOle2 + //when is this code used?! + GDIMetaFile aMtf; + bValidStorage = ConvertToOle2( *pDataStrm, nLen, &aMtf, xObjStor ); + xObjStor->Commit(); + } + } + + if( bValidStorage ) + { + uno::Reference < embed::XEmbeddedObject > xObj = aCnt.GetEmbeddedObject( aDstStgName ); + if( xObj.is() ) + { + // remember file name to use in the title bar + INetURLObject aURL( rBaseURL ); + xObj->setContainerName( aURL.GetLastName( INetURLObject::DecodeMechanism::WithCharset ) ); + + // the visual area must be retrieved from the metafile (object doesn't know it so far) + + if ( nAspect != embed::Aspects::MSOLE_ICON ) + { + // working with visual area can switch the object to running state + try + { + awt::Size aAwtSz; + // the provided visual area should be used, if there is any + if ( rVisArea.IsEmpty() ) + { + MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) ); + Size aSz(lcl_GetPrefSize(rGrf, MapMode(aMapUnit))); + aAwtSz.Width = aSz.Width(); + aAwtSz.Height = aSz.Height(); + } + else + { + aAwtSz.Width = rVisArea.GetWidth(); + aAwtSz.Height = rVisArea.GetHeight(); + } + //xInplaceObj->EnableSetModified( sal_False ); + xObj->setVisualAreaSize( nAspect, aAwtSz ); + //xInplaceObj->EnableSetModified( sal_True ); + } + catch( const uno::Exception& ) + { + OSL_FAIL( "Could not set visual area of the object!" ); + } + } + + svt::EmbeddedObjectRef aObj( xObj, nAspect ); + + // TODO/LATER: need MediaType + aObj.SetGraphic( rGrf, OUString() ); + + pRet = new SdrOle2Obj( + rSdrModel, + aObj, + aDstStgName, + rBoundRect); + } + } + } + + return pRet; +} + +bool SvxMSDffManager::SetPropValue( const uno::Any& rAny, const uno::Reference< css::beans::XPropertySet > & rXPropSet, + const OUString& rPropName ) +{ + bool bRetValue = false; + try + { + uno::Reference< beans::XPropertySetInfo > + aXPropSetInfo( rXPropSet->getPropertySetInfo() ); + if ( aXPropSetInfo.is() ) + bRetValue = aXPropSetInfo->hasPropertyByName( rPropName ); + } + catch( const uno::Exception& ) + { + bRetValue = false; + } + if ( bRetValue ) + { + try + { + rXPropSet->setPropertyValue( rPropName, rAny ); + bRetValue = true; + } + catch( const uno::Exception& ) + { + bRetValue = false; + } + } + return bRetValue; +} + +SvxMSDffImportRec::SvxMSDffImportRec() + : pObj( nullptr ), + nClientAnchorLen( 0 ), + nClientDataLen( 0 ), + nXAlign( 0 ), // position n cm from left + nYAlign( 0 ), // position n cm below + nGroupShapeBooleanProperties(0), // 16 settings: LayoutInCell/AllowOverlap/BehindDocument... + nFlags( ShapeFlag::NONE ), + nDxTextLeft( 144 ), + nDyTextTop( 72 ), + nDxTextRight( 144 ), + nDyTextBottom( 72 ), + nDxWrapDistLeft( 0 ), + nDyWrapDistTop( 0 ), + nDxWrapDistRight( 0 ), + nDyWrapDistBottom(0 ), + nCropFromTop( 0 ), + nCropFromBottom( 0 ), + nCropFromLeft( 0 ), + nCropFromRight( 0 ), + nNextShapeId( 0 ), + nShapeId( 0 ), + eShapeType( mso_sptNil ), + relativeHorizontalWidth( -1 ), + isHorizontalRule( false ) +{ + eLineStyle = mso_lineSimple; // GPF-Bug #66227# + eLineDashing = mso_lineSolid; + bDrawHell = false; + bHidden = false; + + bReplaceByFly = false; + bVFlip = false; + bHFlip = false; + bAutoWidth = false; +} + +SvxMSDffImportRec::SvxMSDffImportRec(const SvxMSDffImportRec& rCopy) + : pObj( rCopy.pObj ), + nXAlign( rCopy.nXAlign ), + nXRelTo( rCopy.nXRelTo ), + nYAlign( rCopy.nYAlign ), + nYRelTo( rCopy.nYRelTo ), + nGroupShapeBooleanProperties(rCopy.nGroupShapeBooleanProperties), + nFlags( rCopy.nFlags ), + nDxTextLeft( rCopy.nDxTextLeft ), + nDyTextTop( rCopy.nDyTextTop ), + nDxTextRight( rCopy.nDxTextRight ), + nDyTextBottom( rCopy.nDyTextBottom ), + nDxWrapDistLeft( rCopy.nDxWrapDistLeft ), + nDyWrapDistTop( rCopy.nDyWrapDistTop ), + nDxWrapDistRight( rCopy.nDxWrapDistRight ), + nDyWrapDistBottom(rCopy.nDyWrapDistBottom ), + nCropFromTop( rCopy.nCropFromTop ), + nCropFromBottom( rCopy.nCropFromBottom ), + nCropFromLeft( rCopy.nCropFromLeft ), + nCropFromRight( rCopy.nCropFromRight ), + aTextId( rCopy.aTextId ), + nNextShapeId( rCopy.nNextShapeId ), + nShapeId( rCopy.nShapeId ), + eShapeType( rCopy.eShapeType ), + relativeHorizontalWidth( rCopy.relativeHorizontalWidth ), + isHorizontalRule( rCopy.isHorizontalRule ) +{ + eLineStyle = rCopy.eLineStyle; // GPF-Bug #66227# + eLineDashing = rCopy.eLineDashing; + bDrawHell = rCopy.bDrawHell; + bHidden = rCopy.bHidden; + bReplaceByFly = rCopy.bReplaceByFly; + bAutoWidth = rCopy.bAutoWidth; + bVFlip = rCopy.bVFlip; + bHFlip = rCopy.bHFlip; + nClientAnchorLen = rCopy.nClientAnchorLen; + if( rCopy.nClientAnchorLen ) + { + pClientAnchorBuffer.reset( new char[ nClientAnchorLen ] ); + memcpy( pClientAnchorBuffer.get(), + rCopy.pClientAnchorBuffer.get(), + nClientAnchorLen ); + } + else + pClientAnchorBuffer = nullptr; + + nClientDataLen = rCopy.nClientDataLen; + if( rCopy.nClientDataLen ) + { + pClientDataBuffer.reset( new char[ nClientDataLen ] ); + memcpy( pClientDataBuffer.get(), + rCopy.pClientDataBuffer.get(), + nClientDataLen ); + } + else + pClientDataBuffer = nullptr; + + if (rCopy.pWrapPolygon) + pWrapPolygon = rCopy.pWrapPolygon; +} + +SvxMSDffImportRec::~SvxMSDffImportRec() +{ +} + +void SvxMSDffManager::insertShapeId( sal_Int32 nShapeId, SdrObject* pShape ) +{ + maShapeIdContainer[nShapeId] = pShape; +} + +void SvxMSDffManager::removeShapeId( SdrObject const * pShape ) +{ + SvxMSDffShapeIdContainer::iterator aIter = std::find_if(maShapeIdContainer.begin(), maShapeIdContainer.end(), + [&pShape](const SvxMSDffShapeIdContainer::value_type& rEntry) { return rEntry.second == pShape; }); + if (aIter != maShapeIdContainer.end()) + maShapeIdContainer.erase( aIter ); +} + +SdrObject* SvxMSDffManager::getShapeForId( sal_Int32 nShapeId ) +{ + SvxMSDffShapeIdContainer::iterator aIter( maShapeIdContainer.find(nShapeId) ); + return aIter != maShapeIdContainer.end() ? (*aIter).second : nullptr; +} + +SvxMSDffImportData::SvxMSDffImportData(const tools::Rectangle& rParentRect) + : aParentRect(rParentRect) +{ +} + +SvxMSDffImportData::~SvxMSDffImportData() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/msfilter.component b/filter/source/msfilter/msfilter.component new file mode 100644 index 000000000..0e1a35ee4 --- /dev/null +++ b/filter/source/msfilter/msfilter.component @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/filter/source/msfilter/msocximex.cxx b/filter/source/msfilter/msocximex.cxx new file mode 100644 index 000000000..e3ccf6524 --- /dev/null +++ b/filter/source/msfilter/msocximex.cxx @@ -0,0 +1,146 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +constexpr OUStringLiteral sWW8_form( u"WW-Standard" ); + +SvxMSConvertOCXControls::SvxMSConvertOCXControls( uno::Reference< frame::XModel > xModel) : mxModel(std::move(xModel)) +{ +} + +SvxMSConvertOCXControls::~SvxMSConvertOCXControls() +{ +} + +void SvxMSConvertOCXControls::GetDrawPage() +{ + if( !xDrawPage.is() && mxModel.is() ) + { + uno::Reference< drawing::XDrawPageSupplier > xTxtDoc(mxModel, + uno::UNO_QUERY); + OSL_ENSURE(xTxtDoc.is(),"no XDrawPageSupplier from XModel"); + xDrawPage = xTxtDoc->getDrawPage(); + OSL_ENSURE( xDrawPage.is(), "no XDrawPage" ); + } +} + + +const uno::Reference< lang::XMultiServiceFactory >& + SvxMSConvertOCXControls::GetServiceFactory() +{ + if( !xServiceFactory.is() && mxModel.is() ) + { + xServiceFactory = uno::Reference< lang::XMultiServiceFactory > + (mxModel, uno::UNO_QUERY); + OSL_ENSURE( xServiceFactory.is(), + "no XMultiServiceFactory from doc Model" ); + } + + return xServiceFactory; +} + +const uno::Reference< drawing::XShapes >& SvxMSConvertOCXControls::GetShapes() +{ + if( !xShapes.is() ) + { + GetDrawPage(); + if( xDrawPage.is() ) + { + xShapes = xDrawPage; + } + } + return xShapes; +} + +const uno::Reference< container::XIndexContainer >& + SvxMSConvertOCXControls::GetFormComps() +{ + if( !xFormComps.is() ) + { + GetDrawPage(); + if( xDrawPage.is() ) + { + uno::Reference< form::XFormsSupplier > xFormsSupplier( xDrawPage, + uno::UNO_QUERY ); + OSL_ENSURE( xFormsSupplier.is(), + "UNO_QUERY failed for XFormsSupplier from XDrawPage" ); + + uno::Reference< container::XNameContainer > xNameCont = + xFormsSupplier->getForms(); + + // The form gets a new name like "WW-Standard[n]" and will + // created new in any case. + OUString sName( sWW8_form ); + sal_uInt16 n = 0; + + while( xNameCont->hasByName( sName ) ) + { + sName = sWW8_form + OUString::number( ++n ); + } + + const uno::Reference< lang::XMultiServiceFactory > &rServiceFactory + = GetServiceFactory(); + if( !rServiceFactory.is() ) + return xFormComps; + + uno::Reference< uno::XInterface > xCreate = + rServiceFactory->createInstance( + "com.sun.star.form.component.Form" ); + if( xCreate.is() ) + { + uno::Reference< beans::XPropertySet > xFormPropSet( xCreate, + uno::UNO_QUERY ); + + uno::Any aTmp(&sName,cppu::UnoType::get()); + xFormPropSet->setPropertyValue( "Name", aTmp ); + + uno::Reference< form::XForm > xForm( xCreate, uno::UNO_QUERY ); + OSL_ENSURE(xForm.is(), "no Form?"); + + uno::Reference< container::XIndexContainer > xForms( xNameCont, + uno::UNO_QUERY ); + OSL_ENSURE( xForms.is(), "XForms not available" ); + + aTmp <<= xForm; + xForms->insertByIndex( xForms->getCount(), aTmp ); + + xFormComps = uno::Reference< container::XIndexContainer > + (xCreate, uno::UNO_QUERY); + } + } + } + + return xFormComps; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/msoleexp.cxx b/filter/source/msfilter/msoleexp.cxx new file mode 100644 index 000000000..9e68e5cb0 --- /dev/null +++ b/filter/source/msfilter/msoleexp.cxx @@ -0,0 +1,340 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +static SvGlobalName GetEmbeddedVersion( const SvGlobalName& aAppName ) +{ + if ( aAppName == SvGlobalName( SO3_SM_CLASSID_60 ) ) + return SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ); + else if ( aAppName == SvGlobalName( SO3_SW_CLASSID_60 ) ) + return SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ); + else if ( aAppName == SvGlobalName( SO3_SC_CLASSID_60 ) ) + return SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ); + else if ( aAppName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) ) + return SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ); + else if ( aAppName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) ) + return SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ); + else if ( aAppName == SvGlobalName( SO3_SCH_CLASSID_60 ) ) + return SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ); + + return SvGlobalName(); +} + +static OUString GetStorageType( const SvGlobalName& aEmbName ) +{ + if ( aEmbName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) ) + return "LibreOffice.MathDocument.1"; + else if ( aEmbName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) ) + return "LibreOffice.WriterDocument.1"; + else if ( aEmbName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) ) + return "LibreOffice.CalcDocument.1"; + else if ( aEmbName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) ) + return "LibreOffice.DrawDocument.1"; + else if ( aEmbName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) ) + return "LibreOffice.ImpressDocument.1"; + else if ( aEmbName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) ) + return "LibreOffice.ChartDocument.1"; + return OUString(); +} + +static bool UseOldMSExport() +{ + uno::Reference< lang::XMultiServiceFactory > xProvider( + configuration::theDefaultProvider::get( + comphelper::getProcessComponentContext())); + try { + uno::Sequence< uno::Any > aArg{ uno::Any( + OUString( "/org.openoffice.Office.Common/InternalMSExport" )) }; + uno::Reference< container::XNameAccess > xNameAccess( + xProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", + aArg ), + uno::UNO_QUERY ); + if ( xNameAccess.is() ) + { + uno::Any aResult = xNameAccess->getByName( "UseOldExport" ); + + bool bResult; + if ( aResult >>= bResult ) + return bResult; + } + } + catch( const uno::Exception& ) + { + } + + OSL_FAIL( "Could not get access to configuration entry!" ); + return false; +} + +void SvxMSExportOLEObjects::ExportOLEObject( const css::uno::Reference < css::embed::XEmbeddedObject>& rObj, SotStorage& rDestStg ) +{ + svt::EmbeddedObjectRef aObj( rObj, embed::Aspects::MSOLE_CONTENT ); + ExportOLEObject( aObj, rDestStg ); +} + +void SvxMSExportOLEObjects::ExportOLEObject( svt::EmbeddedObjectRef const & rObj, SotStorage& rDestStg ) +{ + SvGlobalName aOwnGlobalName; + SvGlobalName aObjName( rObj->getClassID() ); + std::shared_ptr pExpFilter; + { + static struct ObjExpType { + sal_uInt32 nFlag; + const char* pFilterNm; + // GlobalNameId + struct GlobalNameIds { + sal_uInt32 n1; + sal_uInt16 n2, n3; + sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15; + } + aGlNmIds[4]; + } const aArr[] = { + { OLE_STARMATH_2_MATHTYPE, "MathType 3.x", + {{SO3_SM_CLASSID_60}, {SO3_SM_CLASSID_50}, + {SO3_SM_CLASSID_40}, {SO3_SM_CLASSID_30 }}}, + { OLE_STARWRITER_2_WINWORD, "MS Word 97", + {{SO3_SW_CLASSID_60}, {SO3_SW_CLASSID_50}, + {SO3_SW_CLASSID_40}, {SO3_SW_CLASSID_30 }}}, + { OLE_STARCALC_2_EXCEL, "MS Excel 97", + {{SO3_SC_CLASSID_60}, {SO3_SC_CLASSID_50}, + {SO3_SC_CLASSID_40}, {SO3_SC_CLASSID_30 }}}, + { OLE_STARIMPRESS_2_POWERPOINT, "MS PowerPoint 97", + {{SO3_SIMPRESS_CLASSID_60}, {SO3_SIMPRESS_CLASSID_50}, + {SO3_SIMPRESS_CLASSID_40}, {SO3_SIMPRESS_CLASSID_30 }}}, + { 0, "", + {{SO3_SCH_CLASSID_60}, {SO3_SCH_CLASSID_50}, + {SO3_SCH_CLASSID_40}, {SO3_SCH_CLASSID_30 }}}, + { 0, "", + {{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}, // SJ: !!!! SO3_SDRAW_CLASSID is only available up from + {SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50 }}}, // ver 5.0, it is purpose to have double entries here. + + { 0xffff,nullptr, + {{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}, + {SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}}} + }; + + for( const ObjExpType* pArr = aArr; !pExpFilter && ( pArr->nFlag != 0xffff ); ++pArr ) + { + for (const ObjExpType::GlobalNameIds& rId : pArr->aGlNmIds) + { + SvGlobalName aGlbNm( rId.n1, rId.n2, rId.n3, + rId.b8, rId.b9, rId.b10, rId.b11, + rId.b12, rId.b13, rId.b14, rId.b15 ); + if( aObjName == aGlbNm ) + { + aOwnGlobalName = aGlbNm; + + // flags for checking if conversion is wanted at all (SaveOptions?!) + if( nConvertFlags & pArr->nFlag ) + { + pExpFilter = SfxFilterMatcher().GetFilter4FilterName(OUString::createFromAscii(pArr->pFilterNm)); + break; + } + } + } + } + } + + if( pExpFilter ) // use this filter for the export + { + try + { + if ( rObj->getCurrentState() == embed::EmbedStates::LOADED ) + rObj->changeState( embed::EmbedStates::RUNNING ); + //TODO/LATER: is stream instead of outputstream a better choice?! + //TODO/LATER: a "StoreTo" method at embedded object would be nice + SvStream* pStream = new SvMemoryStream; + ::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *pStream ); + uno::Sequence < beans::PropertyValue > aSeq{ + comphelper::makePropertyValue("OutputStream", xOut), + comphelper::makePropertyValue("FilterName", pExpFilter->GetName()) + }; + uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY ); + try + { + xStor->storeToURL( "private:stream", aSeq ); + } + catch( const uno::Exception& ) {} // #TODO really handle exceptions - interactionalhandler etc. ? + + tools::SvRef xOLEStor = new SotStorage( pStream, true ); + xOLEStor->CopyTo( &rDestStg ); + rDestStg.Commit(); + } + catch( const uno::Exception& ) + { + // TODO/LATER: Error handling + OSL_FAIL( "The object could not be exported!" ); + } + } + else if( aOwnGlobalName != SvGlobalName() ) + { + // own format, maybe SO6 format or lower + SvGlobalName aEmbName = GetEmbeddedVersion( aOwnGlobalName ); + if ( aEmbName != SvGlobalName() && !UseOldMSExport() ) + { + // this is a SO6 embedded object, save in old binary format + rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 ); + rDestStg.SetClass( aEmbName, + SotClipboardFormatId::EMBEDDED_OBJ_OLE, + GetStorageType( aEmbName ) ); + tools::SvRef xExtStm = rDestStg.OpenSotStream( + "properties_stream"); + + bool bExtentSuccess = false; + if( !xExtStm->GetError() ) + { + // write extent + //TODO/MBA: check if writing a size is enough + if( rObj.GetObject().is() ) + { + // MSOLE objects don't need to be in running state for VisualArea access + awt::Size aSize; + try + { + // this is an own object, the content size must be stored in the + // extension stream + aSize = rObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); + } + catch( const embed::NoVisualAreaSizeException& ) + { + OSL_FAIL( "Could not get visual area size!" ); + aSize.Width = 5000; + aSize.Height = 5000; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( + "filter.ms", "Unexpected exception while getting visual area size!"); + aSize.Width = 5000; + aSize.Height = 5000; + } + + sal_Int32 pRect[4]; + pRect[0] = 0; + pRect[1] = aSize.Width; + pRect[2] = 0; + pRect[3] = aSize.Height; + + sal_Int8 aWriteSet[16]; + for ( int ind = 0; ind < 4; ind++ ) + { + sal_Int32 nVal = pRect[ind]; + for ( int nByte = 0; nByte < 4; nByte++ ) + { + aWriteSet[ind*4+nByte] = static_cast(nVal) % 0x100; + nVal /= 0x100; + } + } + + bExtentSuccess = (xExtStm->WriteBytes(aWriteSet, 16) == 16); + } + } + + if ( bExtentSuccess ) + { + tools::SvRef xEmbStm = rDestStg.OpenSotStream( + "package_stream"); + if( !xEmbStm->GetError() ) + { + try + { + if ( rObj->getCurrentState() == embed::EmbedStates::LOADED ) + rObj->changeState( embed::EmbedStates::RUNNING ); + //TODO/LATER: is stream instead of outputstream a better choice?! + //TODO/LATER: a "StoreTo" method at embedded object would be nice + ::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *xEmbStm ); + uno::Sequence < beans::PropertyValue > aSeq{ comphelper::makePropertyValue( + "OutputStream", xOut) }; + uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY ); + xStor->storeToURL( "private:stream", aSeq ); + } + catch( const uno::Exception& ) + { + // TODO/LATER: Error handling + OSL_FAIL( "The object could not be exported!" ); + } + } + } + } + else + { + OSL_FAIL("Own binary format inside own container document!"); + } + } + else + { + // alien objects + //TODO/LATER: a "StoreTo" method at embedded object would be nice + rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 ); + uno::Reference < embed::XStorage > xStor = ::comphelper::OStorageHelper::GetTemporaryStorage(); + uno::Reference < embed::XEmbedPersist > xPers( rObj.GetObject(), uno::UNO_QUERY ); + if ( xPers.is() ) + { + uno::Sequence < beans::PropertyValue > aEmptySeq; + OUString aTempName( "bla" ); + try + { + xPers->storeToEntry( xStor, aTempName, aEmptySeq, aEmptySeq ); + } + catch ( const uno::Exception& ) + {} + + tools::SvRef xOLEStor = SotStorage::OpenOLEStorage( xStor, aTempName, StreamMode::STD_READ ); + xOLEStor->CopyTo( &rDestStg ); + rDestStg.Commit(); + } + } + + //We never need this stream: See #99809# and #i2179# + rDestStg.Remove( SVEXT_PERSIST_STREAM ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/mstoolbar.cxx b/filter/source/msfilter/mstoolbar.cxx new file mode 100644 index 000000000..aa781c471 --- /dev/null +++ b/filter/source/msfilter/mstoolbar.cxx @@ -0,0 +1,824 @@ +/* -*- 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/. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; + +int TBBase::nIndent = 0; + +void CustomToolBarImportHelper::ScaleImage( uno::Reference< graphic::XGraphic >& xGraphic, tools::Long nNewSize ) +{ + Graphic aGraphic( xGraphic ); + Size aSize = aGraphic.GetSizePixel(); + if ( aSize.Height() && ( aSize.Height() == aSize.Width() ) ) + { + Graphic aImage(xGraphic); + if ( aSize.Height() != nNewSize ) + { + BitmapEx aBitmap = aImage.GetBitmapEx(); + BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, nNewSize ); + aImage = Graphic(aBitmapex); + xGraphic = aImage.GetXGraphic(); + } + } +} + +void CustomToolBarImportHelper::applyIcons() +{ + for (auto const& concommand : iconcommands) + { + uno::Sequence commands { concommand.sCommand }; + uno::Sequence< uno::Reference< graphic::XGraphic > > images { concommand.image }; + auto pimages = images.getArray(); + + uno::Reference< ui::XImageManager > xImageManager( getCfgManager()->getImageManager(), uno::UNO_QUERY_THROW ); + sal_uInt16 nColor = ui::ImageType::COLOR_NORMAL; + + vcl::Window* topwin = Application::GetActiveTopWindow(); + if ( topwin != nullptr && topwin->GetBackgroundColor().IsDark() ) + nColor = css::ui::ImageType::COLOR_HIGHCONTRAST; + + ScaleImage( pimages[ 0 ], 16 ); + xImageManager->replaceImages( ui::ImageType::SIZE_DEFAULT | nColor, commands, images ); + ScaleImage( pimages[ 0 ], 26 ); + xImageManager->replaceImages( ui::ImageType::SIZE_LARGE | nColor, commands, images ); + } +} + +void CustomToolBarImportHelper::addIcon( const uno::Reference< graphic::XGraphic >& xImage, const OUString& sString ) +{ + iconcontrolitem item; + item.sCommand = sString; + item.image = xImage; + iconcommands.push_back( item ); +} + +CustomToolBarImportHelper::CustomToolBarImportHelper( SfxObjectShell& rDocShell, const css::uno::Reference< css::ui::XUIConfigurationManager>& rxAppCfgMgr ) : mrDocSh( rDocShell ) +{ + m_xCfgSupp.set( mrDocSh.GetModel(), uno::UNO_QUERY_THROW ); + m_xAppCfgMgr.set( rxAppCfgMgr, uno::UNO_SET_THROW ); +} + +uno::Reference< ui::XUIConfigurationManager > +CustomToolBarImportHelper::getCfgManager() +{ + return m_xCfgSupp->getUIConfigurationManager(); +} + + +uno::Any +CustomToolBarImportHelper::createCommandFromMacro( std::u16string_view sCmd ) +{ + //"vnd.sun.star.script:Standard.Module1.Main?language=Basic&location=document" + // create script url + OUString scriptURL + = OUString::Concat("vnd.sun.star.script:") + sCmd + "?language=Basic&location=document"; + return uno::Any( scriptURL ); +} + +OUString CustomToolBarImportHelper::MSOCommandToOOCommand( sal_Int16 msoCmd ) +{ + OUString result; + if (pMSOCmdConvertor) + result = pMSOCmdConvertor->MSOCommandToOOCommand( msoCmd ); + return result; +} + +OUString CustomToolBarImportHelper::MSOTCIDToOOCommand( sal_Int16 msoTCID ) +{ + OUString result; + if (pMSOCmdConvertor) + result = pMSOCmdConvertor->MSOTCIDToOOCommand( msoTCID ); + return result; +} + +bool +CustomToolBarImportHelper::createMenu( const OUString& rName, const uno::Reference< container::XIndexAccess >& xMenuDesc ) +{ + bool bRes = true; + try + { + uno::Reference< ui::XUIConfigurationManager > xCfgManager( getCfgManager() ); + OUString sMenuBar = "private:resource/menubar/" + rName; + uno::Reference< container::XIndexContainer > xPopup( xCfgManager->createSettings(), uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xProps( xPopup, uno::UNO_QUERY_THROW ); + // set name for menubar + xProps->setPropertyValue("UIName", uno::Any( rName ) ); + if ( xPopup.is() ) + { + uno::Sequence< beans::PropertyValue > aPopupMenu{ + comphelper::makePropertyValue("CommandURL", "vnd.openoffice.org:" + rName), + comphelper::makePropertyValue("Label", rName), + comphelper::makePropertyValue("ItemDescriptorContainer", xMenuDesc), + comphelper::makePropertyValue("Type", sal_Int32( 0 )) + }; + + xPopup->insertByIndex( xPopup->getCount(), uno::Any( aPopupMenu ) ); + xCfgManager->insertSettings( sMenuBar, xPopup ); + uno::Reference< ui::XUIConfigurationPersistence > xPersistence( xCfgManager, uno::UNO_QUERY_THROW ); + xPersistence->store(); + } + } + catch( const uno::Exception& ) + { + bRes = false; + } + return bRes; +} + +#ifdef DEBUG_FILTER_MSTOOLBAR +void TBBase::indent_printf( FILE* fp, const char* format, ... ) +{ + va_list ap; + va_start ( ap, format ); + + // indent nIndent spaces + for ( int i=0; i(); + height = std::make_shared(); + rS.ReadUInt16( *width ).ReadUInt16( *height ); + } + return true; +} + +#ifdef DEBUG_FILTER_MSTOOLBAR +void TBCHeader::Print( FILE* fp ) +{ + Indent a; + indent_printf(fp,"[ 0x%x ] TBCHeader -- dump\n", nOffSet ); + indent_printf(fp," bSignature 0x%x\n", bSignature ); + indent_printf(fp," bVersion 0x%x\n", bVersion ); + indent_printf(fp," bFlagsTCR 0x%x\n", bFlagsTCR ); + indent_printf(fp," tct 0x%x\n", tct ); + indent_printf(fp," tcid 0x%x\n", tcid ); + indent_printf(fp," tbct 0x%x\n", static_cast< unsigned int >( tbct )); + indent_printf(fp," bPriority 0x%x\n", bPriority ); + if ( width.get() ) + indent_printf(fp," width %d(0x%x)\n", *width, *width); + if ( height.get() ) + indent_printf(fp," height %d(0x%x)\n", *height, *height); +} +#endif + +TBCData::TBCData( TBCHeader Header ) : rHeader(std::move( Header )) +{ +} + +bool TBCData::Read(SvStream &rS) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + if ( !controlGeneralInfo.Read(rS) /*|| !controlSpecificInfo.Read(rS)*/ ) + return false; + switch ( rHeader.getTct() ) + { + case 0x01: // (Button control) + case 0x10: // (ExpandingGrid control) + controlSpecificInfo = std::make_shared(); + break; + case 0x0A: // (Popup control) + case 0x0C: // (ButtonPopup control) + case 0x0D: // (SplitButtonPopup control) + case 0x0E: // (SplitButtonMRUPopup control) + controlSpecificInfo = std::make_shared(); + break; + case 0x02: // (Edit control) + case 0x04: // (ComboBox control) + case 0x14: // (GraphicCombo control) + case 0x03: // (DropDown control) + case 0x06: // (SplitDropDown control) + case 0x09: // (GraphicDropDown control) + controlSpecificInfo = std::make_shared( rHeader ); + break; + default: + break; + } + if ( controlSpecificInfo ) + return controlSpecificInfo->Read( rS ); + //#FIXME I need to be able to handle different controlSpecificInfo types. + return true; +} + +TBCMenuSpecific* TBCData::getMenuSpecific() +{ + TBCMenuSpecific* pMenu = dynamic_cast< TBCMenuSpecific* >( controlSpecificInfo.get() ); + return pMenu; +} +void TBCData::ImportToolBarControl( CustomToolBarImportHelper& helper, std::vector< css::beans::PropertyValue >& props, bool& bBeginGroup, bool bIsMenuBar ) +{ + sal_uInt16 nStyle = 0; + bBeginGroup = rHeader.isBeginGroup(); + controlGeneralInfo.ImportToolBarControlData( helper, props ); + beans::PropertyValue aProp; + aProp.Name = "Visible"; + aProp.Value <<= rHeader.isVisible(); // where is the visible attribute stored + props.push_back( aProp ); + if ( rHeader.getTct() == 0x01 + || rHeader.getTct() == 0x10 ) + { + TBCBSpecific* pSpecificInfo = dynamic_cast< TBCBSpecific* >( controlSpecificInfo.get() ); + if ( pSpecificInfo ) + { + // if we have an icon then lets set it for the command + OUString sCommand; + for (auto const& property : props) + { + // TODO JNA : couldn't we break if we find CommandURL to avoid keeping on the loop? + if ( property.Name == "CommandURL" ) + property.Value >>= sCommand; + } + if ( TBCBitMap* pIcon = pSpecificInfo->getIcon() ) + { + // Without a command openoffice won't display the icon + if ( !sCommand.isEmpty() ) + { + BitmapEx aBitEx( pIcon->getBitMap() ); + TBCBitMap* pIconMask = pSpecificInfo->getIconMask(); + if (pIconMask) + { + const Bitmap& rMaskBase(pIconMask->getBitMap().GetBitmap()); + Size aMaskSize = rMaskBase.GetSizePixel(); + if (aMaskSize.Width() && aMaskSize.Height()) + { + // according to the spec: + // "the iconMask is white in all the areas in which the icon is + // displayed as transparent and is black in all other areas." + aBitEx = BitmapEx(aBitEx.GetBitmap(), rMaskBase.CreateMask(COL_WHITE)); + } + } + + Graphic aGraphic( aBitEx ); + helper.addIcon( aGraphic.GetXGraphic(), sCommand ); + } + } + else if ( pSpecificInfo->getBtnFace() ) + { + + OUString sBuiltInCmd = helper.MSOTCIDToOOCommand( *pSpecificInfo->getBtnFace() ); + if ( !sBuiltInCmd.isEmpty() ) + { + uno::Sequence sCmds { sBuiltInCmd }; + uno::Reference< ui::XImageManager > xImageManager( helper.getAppCfgManager()->getImageManager(), uno::UNO_QUERY_THROW ); + // 0 = default image size + uno::Sequence< uno::Reference< graphic::XGraphic > > sImages = xImageManager->getImages( 0, sCmds ); + if ( sImages.hasElements() && sImages[0].is() ) + helper.addIcon( sImages[0], sCommand ); + } + } + } + } + else if ( rHeader.getTct() == 0x0a ) + { + aProp.Name = "CommandURL"; + + TBCMenuSpecific* pMenu = getMenuSpecific(); + if ( pMenu ) + { + OUString sMenuBar = "private:resource/menubar/" + pMenu->Name(); + aProp.Value <<= sMenuBar; // name of popup + } + nStyle |= ui::ItemStyle::DROP_DOWN; + props.push_back( aProp ); + } + + short icontext = ( rHeader.getTbct() & 0x03 ); + aProp.Name = "Style"; + if ( bIsMenuBar ) + { + nStyle |= ui::ItemStyle::TEXT; + if ( !icontext || icontext == 0x3 ) + // Text And image + nStyle |= ui::ItemStyle::ICON; + } + else + { + if ( ( icontext & 0x02 ) == 0x02 ) + nStyle |= ui::ItemStyle::TEXT; + if ( !icontext || ( icontext & 0x03 ) == 0x03 ) + nStyle |= ui::ItemStyle::ICON; + } + aProp.Value <<= nStyle; + props.push_back( aProp ); +} + +#ifdef DEBUG_FILTER_MSTOOLBAR +void TBCData::Print( FILE* fp ) +{ + Indent a; + indent_printf(fp,"[ 0x%x ] TBCData -- dump\n", nOffSet ); + indent_printf(fp," dumping controlGeneralInfo( TBCGeneralInfo )\n"); + controlGeneralInfo.Print( fp ); + //if ( rHeader.getTct() == 1 ) + if ( controlSpecificInfo.get() ) + { + indent_printf(fp," dumping controlSpecificInfo( TBCBSpecificInfo )\n"); + controlSpecificInfo->Print( fp ); + } +} +#endif + +bool +WString::Read( SvStream &rS ) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + sal_uInt8 nChars = 0; + rS.ReadUChar( nChars ); + sString = read_uInt16s_ToOUString(rS, nChars); + return true; +} + +TBCExtraInfo::TBCExtraInfo() + : idHelpContext(0) + , tbcu(0) + , tbmg(0) +{ +} + +bool +TBCExtraInfo::Read( SvStream &rS ) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + if( !wstrHelpFile.Read( rS ) ) + return false; + + rS.ReadInt32( idHelpContext ); + + if ( !wstrTag.Read( rS ) || !wstrOnAction.Read( rS ) || !wstrParam.Read( rS ) ) + return false; + + rS.ReadSChar( tbcu ).ReadSChar( tbmg ); + return true; +} + +#ifdef DEBUG_FILTER_MSTOOLBAR +void +TBCExtraInfo::Print( FILE* fp ) +{ + Indent a; + indent_printf( fp, "[ 0x%x ] TBCExtraInfo -- dump\n", nOffSet ); + indent_printf( fp, " wstrHelpFile %s\n", + OUStringToOString( wstrHelpFile.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + indent_printf( fp, " idHelpContext 0x%x\n", static_cast< unsigned int >( idHelpContext ) ); + indent_printf( fp, " wstrTag %s\n", + OUStringToOString( wstrTag.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + indent_printf( fp, " wstrOnAction %s\n", + OUStringToOString( wstrOnAction.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + indent_printf( fp, " wstrParam %s\n", + OUStringToOString( wstrParam.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + indent_printf( fp, " tbcu 0x%x\n", tbcu ); + indent_printf( fp, " tbmg 0x%x\n", tbmg ); +} +#endif + +OUString const & +TBCExtraInfo::getOnAction() const +{ + return wstrOnAction.getString(); +} + +TBCGeneralInfo::TBCGeneralInfo() : bFlags( 0 ) +{ +} + +bool TBCGeneralInfo::Read( SvStream &rS ) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + rS.ReadUChar( bFlags ); + + if ( ( bFlags & 0x1 ) && !customText.Read( rS ) ) + return false; + if ( ( bFlags & 0x2 ) && ( !descriptionText.Read( rS ) || !tooltip.Read( rS ) ) ) + return false; + if ( ( bFlags & 0x4 ) && !extraInfo.Read( rS ) ) + return false; + return true; +} + +#ifdef DEBUG_FILTER_MSFILTER +void +TBCGeneralInfo::Print( FILE* fp ) +{ + Indent a; + indent_printf( fp, "[ 0x%x ] TBCGeneralInfo -- dump\n", nOffSet ); + indent_printf( fp, " bFlags 0x%x\n", bFlags ); + indent_printf( fp, " customText %s\n", + OUStringToOString( customText.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + indent_printf( fp, " description %s\n", + OUStringToOString( descriptionText.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + indent_printf( fp, " tooltip %s\n", + OUStringToOString( tooltip.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + if ( bFlags & 0x4 ) + extraInfo.Print( fp ); +} +#endif + +void +TBCGeneralInfo::ImportToolBarControlData( CustomToolBarImportHelper& helper, std::vector< beans::PropertyValue >& sControlData ) +{ + if ( !(bFlags & 0x5) ) + return; + + beans::PropertyValue aProp; + // probably access to the header would be a better test than seeing if there is an action, e.g. + // if ( rHeader.getTct() == 0x01 && rHeader.getTcID() == 0x01 ) // not defined, probably this is a command + if ( !extraInfo.getOnAction().isEmpty() ) + { + aProp.Name = "CommandURL"; + ooo::vba::MacroResolvedInfo aMacroInf = ooo::vba::resolveVBAMacro( &helper.GetDocShell(), extraInfo.getOnAction(), true ); + if ( aMacroInf.mbFound ) + aProp.Value = CustomToolBarImportHelper::createCommandFromMacro( aMacroInf.msResolvedMacro ); + else + aProp.Value <<= "UnResolvedMacro[" + extraInfo.getOnAction() + "]"; + sControlData.push_back( aProp ); + } + + aProp.Name = "Label"; + aProp.Value <<= customText.getString().replace('&','~'); + sControlData.push_back( aProp ); + + aProp.Name = "Type"; + aProp.Value <<= ui::ItemType::DEFAULT; + sControlData.push_back( aProp ); + + aProp.Name = "Tooltip"; + aProp.Value <<= tooltip.getString(); + sControlData.push_back( aProp ); +/* +aToolbarItem(0).Name = "CommandURL" wstrOnAction +aToolbarItem(0).Value = Command +aToolbarItem(1).Name = "Label" customText +aToolbarItem(1).Value = Label +aToolbarItem(2).Name = "Type" +aToolbarItem(2).Value = 0 +aToolbarItem(3).Name = "Visible" +aToolbarItem(3).Value = true +*/ +} + +TBCMenuSpecific::TBCMenuSpecific() : tbid( 0 ) +{ +} + +bool +TBCMenuSpecific::Read( SvStream &rS) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + rS.ReadInt32( tbid ); + if ( tbid == 1 ) + { + name = std::make_shared(); + return name->Read( rS ); + } + return true; +} + +#ifdef DEBUG_FILTER_MSFILTER +void +TBCMenuSpecific::Print( FILE* fp ) +{ + Indent a; + indent_printf( fp, "[ 0x%x ] TBCMenuSpecific -- dump\n", nOffSet ); + indent_printf( fp, " tbid 0x%x\n", static_cast< unsigned int >( tbid ) ); + if ( tbid == 1 ) + indent_printf( fp, " name %s\n", OUStringToOString( name->getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); +} +#endif + +OUString TBCMenuSpecific::Name() +{ + OUString aName; + if ( name ) + aName = name->getString(); + return aName; +} +TBCBSpecific::TBCBSpecific() : bFlags( 0 ) +{ +} + +bool TBCBSpecific::Read( SvStream &rS) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + rS.ReadUChar( bFlags ); + + // bFlags determines what we read next + + // bFlags.fCustomBitmap = 1 ( 0x8 ) set + if ( bFlags & 0x8 ) + { + icon = std::make_shared(); + iconMask = std::make_shared(); + if ( !icon->Read( rS ) || !iconMask->Read( rS ) ) + return false; + } + // if bFlags.fCustomBtnFace = 1 ( 0x10 ) + if ( bFlags & 0x10 ) + { + iBtnFace = std::make_shared(); + rS.ReadUInt16( *iBtnFace ); + } + // if bFlags.fAccelerator equals 1 ( 0x04 ) + if ( bFlags & 0x04 ) + { + wstrAcc = std::make_shared(); + return wstrAcc->Read( rS ); + } + return true; +} + + +#ifdef DEBUG_FILTER_MSFILTER +void TBCBSpecific::Print( FILE* fp ) +{ + Indent a; + indent_printf( fp, "[ 0x%x ] TBCBSpecific -- dump\n", nOffSet ); + indent_printf( fp, " bFlags 0x%x\n", bFlags ); + bool bResult = ( icon.get() != NULL ); + indent_printf( fp, " icon present? %s\n", bResult ? "true" : "false" ); + if ( bResult ) + { + Indent b; + indent_printf( fp, " icon: \n"); + icon->Print( fp ); // will dump size + } + bResult = ( iconMask.get() != NULL ); + indent_printf( fp, " icon mask present? %s\n", bResult ? "true" : "false" ); + if ( bResult ) + { + Indent c; + indent_printf( fp, " icon mask: \n"); + iconMask->Print( fp ); // will dump size + } + if ( iBtnFace.get() ) + { + indent_printf( fp, " iBtnFace 0x%x\n", *iBtnFace ); + } + bResult = ( wstrAcc.get() != NULL ); + indent_printf( fp, " option string present? %s ->%s<-\n", bResult ? "true" : "false", bResult ? OUStringToOString( wstrAcc->getString(), RTL_TEXTENCODING_UTF8 ).getStr() : "N/A" ); +} +#endif + +TBCBitMap* +TBCBSpecific::getIcon() +{ + return icon.get(); +} + +TBCBitMap* +TBCBSpecific::getIconMask() +{ + return iconMask.get(); +} + +TBCComboDropdownSpecific::TBCComboDropdownSpecific(const TBCHeader& header ) +{ + if ( header.getTcID() == 0x01 ) + data = std::make_shared(); +} + +bool TBCComboDropdownSpecific::Read( SvStream &rS) +{ + nOffSet = rS.Tell(); + if ( data ) + return data->Read( rS ); + return true; +} + +#ifdef DEBUG_FILTER_MSFILTER +void TBCComboDropdownSpecific::Print( FILE* fp) +{ + Indent a; + indent_printf(fp,"[ 0x%x ] TBCComboDropdownSpecific -- dump\n", nOffSet ); + if ( data.get() ) + data->Print( fp ); + else + indent_printf(fp," no data " ); +} +#endif + +TBCCDData::TBCCDData() + : cwstrItems(0) + , cwstrMRU(0) + , iSel(0) + , cLines(0) + , dxWidth(0) +{ +} + +TBCCDData::~TBCCDData() +{ +} + +bool TBCCDData::Read( SvStream &rS) +{ + nOffSet = rS.Tell(); + rS.ReadInt16( cwstrItems ); + if (cwstrItems > 0) + { + auto nItems = o3tl::make_unsigned(cwstrItems); + //each WString is at least one byte + if (rS.remainingSize() < nItems) + return false; + for (decltype(nItems) index = 0; index < nItems; ++index) + { + WString aString; + if ( !aString.Read( rS ) ) + return false; + wstrList.push_back( aString ); + } + } + rS.ReadInt16( cwstrMRU ).ReadInt16( iSel ).ReadInt16( cLines ).ReadInt16( dxWidth ); + + return wstrEdit.Read( rS ); +} + +#ifdef DEBUG_FILTER_MSFILTER +void TBCCDData::Print( FILE* fp) +{ + Indent a; + indent_printf(fp,"[ 0x%x ] TBCCDData -- dump\n", nOffSet ); + indent_printf(fp," cwstrItems items in wstrList %d\n", cwstrItems); + for ( sal_Int32 index=0; index < cwstrItems; ++index ) + { + Indent b; + indent_printf(fp, " wstrList[%d] %s", static_cast< int >( index ), OUStringToOString( wstrList[index].getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); + } + indent_printf(fp," cwstrMRU num most recently used string %d item\n", cwstrMRU); + indent_printf(fp," iSel index of selected item %d item\n", iSel); + indent_printf(fp," cLines num of suggested lines to display %d", cLines); + indent_printf(fp," dxWidth width in pixels %d", dxWidth); + indent_printf(fp," wstrEdit %s", OUStringToOString( wstrEdit.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); +} +#endif + +TBCBitMap::TBCBitMap() : cbDIB( 0 ) +{ +} + +TBCBitMap::~TBCBitMap() +{ +} + +bool TBCBitMap::Read( SvStream& rS) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + rS.ReadInt32( cbDIB ); + // cbDIB = sizeOf(biHeader) + sizeOf(colors) + sizeOf(bitmapData) + 10 + return ReadDIBBitmapEx(mBitMap, rS, false, true); +} + +#ifdef DEBUG_FILTER_MSTOOLBAR +void TBCBitMap::Print( FILE* fp ) +{ + Indent a; + indent_printf(fp, "[ 0x%x ] TBCBitMap -- dump\n", nOffSet ); + indent_printf(fp, " TBCBitMap size of bitmap data 0x%x\n", static_cast< unsigned int > ( cbDIB ) ); +} +#endif + +TB::TB() : bSignature(0x2), +bVersion(0x1), +cCL(0), +ltbid( 0x1 ), +ltbtr(0), +cRowsDefault( 0 ), +bFlags( 0 ) +{ +} + +bool TB::Read(SvStream &rS) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + rS.ReadUChar( bSignature ).ReadUChar( bVersion ).ReadInt16( cCL ).ReadInt32( ltbid ).ReadUInt32( ltbtr ).ReadUInt16( cRowsDefault ).ReadUInt16( bFlags ); + name.Read( rS ); + return true; + +} + +bool TB::IsEnabled() const +{ + return ( bFlags & 0x01 ) != 0x01; +} + +#ifdef DEBUG_FILTER_MSTOOLBAR +void TB::Print( FILE* fp ) +{ + Indent a; + indent_printf(fp,"[ 0x%x ] TB -- dump\n", nOffSet ); + indent_printf(fp," bSignature 0x%x\n", bSignature ); + indent_printf(fp," bVersion 0x%x\n", bVersion ); + indent_printf(fp," cCL 0x%x\n", cCL ); + indent_printf(fp," ltbid 0x%x\n", ltbid ); + indent_printf(fp," ltbtr 0x%x\n", ltbtr ); + indent_printf(fp," cRowsDefault 0x%x\n", cRowsDefault ); + indent_printf(fp," bFlags 0x%x\n", bFlags ); + indent_printf(fp, " name %s\n", OUStringToOString( name.getString(), RTL_TEXTENCODING_UTF8 ).getStr() ); +} +#endif + +TBVisualData::TBVisualData() : tbds(0), tbv(0), tbdsDock(0), iRow(0) +{ +} + +bool TBVisualData::Read( SvStream& rS ) +{ + SAL_INFO("filter.ms", "stream pos " << rS.Tell()); + nOffSet = rS.Tell(); + rS.ReadSChar( tbds ).ReadSChar( tbv ).ReadSChar( tbdsDock ).ReadSChar( iRow ); + rcDock.Read( rS ); + rcFloat.Read( rS ); + return true; +} + +#ifdef DEBUG_FILTER_MSTOOLBAR +void SRECT::Print( FILE* fp ) +{ + Indent a; + indent_printf( fp, " left 0x%x\n", left); + indent_printf( fp, " top 0x%x\n", top); + indent_printf( fp, " right 0x%x\n", right); + indent_printf( fp, " bottom 0x%x\n", bottom); +} +#endif + +#ifdef DEBUG_FILTER_MSTOOLBAR +void TBVisualData::Print( FILE* fp ) +{ + Indent a; + indent_printf( fp, "[ 0x%x ] TBVisualData -- dump\n", nOffSet ); + indent_printf( fp, " tbds 0x%x\n", tbds); + indent_printf( fp, " tbv 0x%x\n", tbv); + indent_printf( fp, " tbdsDoc 0x%x\n", tbdsDock); + indent_printf( fp, " iRow 0x%x\n", iRow); + rcDock.Print( fp ); + rcFloat.Print( fp ); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/msvbahelper.cxx b/filter/source/msfilter/msvbahelper.cxx new file mode 100644 index 000000000..d55a636fc --- /dev/null +++ b/filter/source/msfilter/msvbahelper.cxx @@ -0,0 +1,768 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace ooo::vba { + +constexpr OUStringLiteral sUrlPart0( u"vnd.sun.star.script:" ); +constexpr OUStringLiteral sUrlPart1( u"?language=Basic&location=document" ); + +OUString makeMacroURL( std::u16string_view sMacroName ) +{ + return sUrlPart0 + sMacroName + sUrlPart1; +} + +OUString extractMacroName( const OUString& rMacroUrl ) +{ + if( rMacroUrl.startsWith( sUrlPart0 ) && rMacroUrl.endsWith( sUrlPart1 ) ) + { + return rMacroUrl.copy( sUrlPart0.getLength(), + rMacroUrl.getLength() - sUrlPart0.getLength() - sUrlPart1.getLength() ); + } + return OUString(); +} + +static std::u16string_view trimMacroName( std::u16string_view rMacroName ) +{ + // the name may contain whitespaces and may be enclosed in apostrophs + std::u16string_view aMacroName = o3tl::trim(rMacroName); + size_t nMacroLen = aMacroName.size(); + if( (nMacroLen >= 2) && (aMacroName[ 0 ] == '\'') && (aMacroName[ nMacroLen - 1 ] == '\'') ) + aMacroName = o3tl::trim(aMacroName.substr( 1, nMacroLen - 2 )); + return aMacroName; +} + +#if HAVE_FEATURE_SCRIPTING + +static SfxObjectShell* findShellForUrl( const OUString& sMacroURLOrPath ) +{ + SfxObjectShell* pFoundShell=nullptr; + SfxObjectShell* pShell = SfxObjectShell::GetFirst(); + INetURLObject aObj; + aObj.SetURL( sMacroURLOrPath ); + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + OUString aURL; + if ( bIsURL ) + aURL = sMacroURLOrPath; + else + { + osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL ); + aObj.SetURL( aURL ); + } + while ( pShell ) + { + + uno::Reference< frame::XModel > xModel = pShell->GetModel(); + // are we searching for a template? if so we have to cater for the + // fact that in openoffice a document opened from a template is always + // a new document :/ + if ( xModel.is() ) + { + SAL_INFO( + "filter.ms", + "shell " << pShell << " has model with url " << xModel->getURL() + << " and we look for " << aURL); + OUString aName = xModel->getURL() ; + if (aName.isEmpty()) + { + uno::Reference< frame::XFrame > xFrame( xModel->getCurrentController()->getFrame(), uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xProps( xFrame, uno::UNO_QUERY_THROW ); + xProps->getPropertyValue("Title") >>= aName; + aName = o3tl::trim(o3tl::getToken(aName, 0, '-')); + if( sMacroURLOrPath.lastIndexOf( aName ) >= 0 ) + { + pFoundShell = pShell; + break; + } + } + + if ( sMacroURLOrPath.endsWithIgnoreAsciiCase( ".dot" ) ) + { + uno::Reference const + xDocPropSupp(xModel, uno::UNO_QUERY); + if (xDocPropSupp.is()) + { + uno::Reference< document::XDocumentProperties > const + xDocProps(xDocPropSupp->getDocumentProperties(), + uno::UNO_SET_THROW); + OUString sCurrName = xDocProps->getTemplateName(); + if( sMacroURLOrPath.lastIndexOf( sCurrName ) >= 0 ) + { + pFoundShell = pShell; + break; + } + } + } + else + { + // sometimes just the name of the document ( without the path + // is used + bool bDocNameNoPathMatch = false; + if ( !aURL.isEmpty() && aURL.indexOf( '/' ) == -1 ) + { + sal_Int32 lastSlashIndex = xModel->getURL().lastIndexOf( '/' ); + if ( lastSlashIndex > -1 ) + { + bDocNameNoPathMatch = xModel->getURL().subView( lastSlashIndex + 1 ) == aURL; + if ( !bDocNameNoPathMatch ) + { + OUString aTmpName = OUString::Concat("'") + xModel->getURL().subView( lastSlashIndex + 1 ) + "'"; + bDocNameNoPathMatch = aTmpName == aURL; + } + } + } + + if ( aURL == xModel->getURL() || bDocNameNoPathMatch ) + { + pFoundShell = pShell; + break; + } + } + } + pShell = SfxObjectShell::GetNext( *pShell ); + } + return pFoundShell; +} + +// sMod can be empty ( but we really need the library to search in ) +// if sMod is empty and a macro is found then sMod is updated +// if sMod is empty, only standard modules will be searched (no class, document, form modules) +static bool hasMacro( SfxObjectShell const * pShell, const OUString& sLibrary, OUString& sMod, const OUString& sMacro ) +{ +#if !HAVE_FEATURE_SCRIPTING + (void) pShell; + (void) sLibrary; + (void) sMod; + (void) sMacro; +#else + if ( !sLibrary.isEmpty() && !sMacro.isEmpty() ) + { + BasicManager* pBasicMgr = pShell-> GetBasicManager(); + if ( pBasicMgr ) + { + StarBASIC* pBasic = pBasicMgr->GetLib( sLibrary ); + if ( !pBasic ) + { + sal_uInt16 nId = pBasicMgr->GetLibId( sLibrary ); + pBasicMgr->LoadLib( nId ); + pBasic = pBasicMgr->GetLib( sLibrary ); + } + if ( pBasic ) + { + if ( !sMod.isEmpty() ) // we wish to find the macro is a specific module + { + SbModule* pModule = pBasic->FindModule( sMod ); + if ( pModule && pModule->FindMethod( sMacro, SbxClassType::Method )) + { + return true; + } + } + else + { + for (auto const& rModuleRef : pBasic->GetModules()) + { + if (rModuleRef && rModuleRef->FindMethod(sMacro, SbxClassType::Method)) + { + sMod = rModuleRef->GetName(); + return true; + } + } + } + } + } + } +#endif + return false; +} + +#endif + +#if HAVE_FEATURE_SCRIPTING + +OUString getDefaultProjectName( SfxObjectShell const * pShell ) +{ + OUString aPrjName; + if( BasicManager* pBasicMgr = pShell ? pShell->GetBasicManager() : nullptr ) + { + aPrjName = pBasicMgr->GetName(); + if( aPrjName.isEmpty() ) + aPrjName = "Standard"; + } + return aPrjName; +} + +static void parseMacro( const OUString& sMacro, OUString& sContainer, OUString& sModule, OUString& sProcedure ) +{ + sal_Int32 nMacroDot = sMacro.lastIndexOf( '.' ); + + if ( nMacroDot != -1 ) + { + sProcedure = sMacro.copy( nMacroDot + 1 ); + + sal_Int32 nContainerDot = sMacro.lastIndexOf( '.', nMacroDot - 1 ); + if ( nContainerDot != -1 ) + { + sModule = sMacro.copy( nContainerDot + 1, nMacroDot - nContainerDot - 1 ); + sContainer = sMacro.copy( 0, nContainerDot ); + } + else + sModule = sMacro.copy( 0, nMacroDot ); + } + else + sProcedure = sMacro; +} + +#endif + +OUString resolveVBAMacro( SfxObjectShell const * pShell, const OUString& rLibName, const OUString& rModuleName, const OUString& rMacroName ) +{ +#if !HAVE_FEATURE_SCRIPTING + (void) pShell; + (void) rLibName; + (void) rModuleName; + (void) rMacroName; +#else + if( pShell ) + { + OUString aLibName = rLibName.isEmpty() ? getDefaultProjectName( pShell ) : rLibName ; + OUString aModuleName = rModuleName; + if( hasMacro( pShell, aLibName, aModuleName, rMacroName ) ) + return aLibName + "." + aModuleName + "." + rMacroName; + } +#endif + return OUString(); +} + +MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const OUString& MacroName, bool bSearchGlobalTemplates ) +{ +#if !HAVE_FEATURE_SCRIPTING + (void) pShell; + (void) MacroName; + (void) bSearchGlobalTemplates; + + return MacroResolvedInfo(); +#else + if( !pShell ) + return MacroResolvedInfo(); + + // the name may be enclosed in apostrophs + std::u16string_view aMacroName = trimMacroName( MacroName ); + + // parse the macro name + size_t nDocSepIndex = aMacroName.find( '!' ); + if( nDocSepIndex > 0 && nDocSepIndex != std::u16string_view::npos ) + { + // macro specified by document name + // find document shell for document name and call ourselves + // recursively + + // assume for now that the document name is *this* document + std::u16string_view sDocUrlOrPath = aMacroName.substr( 0, nDocSepIndex ); + aMacroName = aMacroName.substr( nDocSepIndex + 1 ); + SAL_INFO("filter.ms", "doc search, current shell is " << pShell); + SfxObjectShell* pFoundShell = nullptr; + if( bSearchGlobalTemplates ) + { + SvtPathOptions aPathOpt; + const OUString& aAddinPath = aPathOpt.GetAddinPath(); + if( o3tl::starts_with(sDocUrlOrPath, aAddinPath) ) + pFoundShell = pShell; + } + if( !pFoundShell ) + pFoundShell = findShellForUrl( OUString(sDocUrlOrPath) ); + SAL_INFO( + "filter.ms", + "doc search, after find, found shell is " << pFoundShell); + return resolveVBAMacro( pFoundShell, OUString(aMacroName) ); + } + + // macro is contained in 'this' document ( or code imported from a template + // where that template is a global template or perhaps the template this + // document is created from ) + + MacroResolvedInfo aRes( pShell ); + + // macro format = Container.Module.Procedure + OUString sContainer, sModule, sProcedure; + parseMacro( OUString(aMacroName), sContainer, sModule, sProcedure ); + +#if 0 + // As long as service VBAProjectNameProvider isn't supported in the model, disable the createInstance call + // (the ServiceNotRegisteredException is wrongly caught in ScModelObj::createInstance) + uno::Reference< container::XNameContainer > xPrjNameCache; + uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY); + if ( xSF.is() ) try + { + xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY ); + } + catch( const uno::Exception& ) // createInstance may throw + { + } +#endif + + std::vector< OUString > sSearchList; + + if ( !sContainer.isEmpty() ) + { +// service VBAProjectNameProvider not implemented +#if 0 + // get the Project associated with the Container + if ( xPrjNameCache.is() ) + { + if ( xPrjNameCache->hasByName( sContainer ) ) + { + OUString sProject; + xPrjNameCache->getByName( sContainer ) >>= sProject; + sContainer = sProject; + } + } +#endif + sSearchList.push_back( sContainer ); // First Lib to search + } + else + { + // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates, + // get the name of Project/Library for 'this' document + OUString sThisProject( "Standard" ); + try + { + uno::Reference< beans::XPropertySet > xProps( pShell->GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW ); + sThisProject = xVBAMode->getProjectName(); + } + catch( const uno::Exception& /*e*/) {} + + sSearchList.push_back( sThisProject ); // First Lib to search + +// service VBAProjectNameProvider not implemented +#if 0 + if ( xPrjNameCache.is() ) + { + // is this document created from a template? + uno::Reference< document::XDocumentPropertiesSupplier > const + xDocPropSupp(pShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW ); + + OUString sCreatedFrom = xDocProps->getTemplateURL(); + if ( !sCreatedFrom.isEmpty() ) + { + INetURLObject aObj; + aObj.SetURL( sCreatedFrom ); + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + OUString aURL; + if ( bIsURL ) + aURL = sCreatedFrom; + else + { + osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL ); + aObj.SetURL( aURL ); + } + sCreatedFrom = aObj.GetLastName(); + } + + sal_Int32 nIndex = sCreatedFrom.lastIndexOf( '.' ); + if ( nIndex != -1 ) + sCreatedFrom = sCreatedFrom.copy( 0, nIndex ); + + OUString sPrj; + if ( !sCreatedFrom.isEmpty() && xPrjNameCache->hasByName( sCreatedFrom ) ) + { + xPrjNameCache->getByName( sCreatedFrom ) >>= sPrj; + // Make sure we don't double up with this project + if ( !sPrj.equals( sThisProject ) ) + sSearchList.push_back( sPrj ); + } + + // get list of global template Names + uno::Sequence< OUString > sTemplateNames = xPrjNameCache->getElementNames(); + sal_Int32 nLen = sTemplateNames.getLength(); + for ( sal_Int32 index = 0; ( bSearchGlobalTemplates && index < nLen ); ++index ) + { + + if ( !sCreatedFrom.equals( sTemplateNames[ index ] ) ) + { + if ( xPrjNameCache->hasByName( sTemplateNames[ index ] ) ) + { + xPrjNameCache->getByName( sTemplateNames[ index ] ) >>= sPrj; + // Make sure we don't double up with this project + if ( !sPrj.equals( sThisProject ) ) + sSearchList.push_back( sPrj ); + } + } + + } + } +#endif + } + + for (auto const& search : sSearchList) + { + aRes.mbFound = hasMacro( pShell, search, sModule, sProcedure ); + if ( aRes.mbFound ) + { + sContainer = search; + break; + } + } + //aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 ); + aRes.msResolvedMacro = sContainer + "." + sModule + "." + sProcedure; + + return aRes; +#endif +} + +// Treat the args as possible inputs (conversion at bottom of method) +bool executeMacro( SfxObjectShell* pShell, const OUString& sMacroName, uno::Sequence< uno::Any >& aArgs, uno::Any& aRet, const uno::Any& /*aCaller*/) +{ +#if !HAVE_FEATURE_SCRIPTING + (void) pShell; + (void) sMacroName; + (void) aArgs; + (void) aRet; + + return false; +#else + bool bRes = false; + if ( !pShell ) + return bRes; + OUString sUrl = makeMacroURL( sMacroName ); + + uno::Sequence< sal_Int16 > aOutArgsIndex; + uno::Sequence< uno::Any > aOutArgs; + + try + { + ErrCode nErr = pShell->CallXScript(sUrl, aArgs, aRet, aOutArgsIndex, aOutArgs, false); + sal_Int32 nLen = aOutArgs.getLength(); + // convert any out params to seem like they were inputs + if (nLen) + { + auto pArgs = aArgs.getArray(); + for (sal_Int32 index = 0; index < nLen; ++index) + { + sal_Int32 nOutIndex = aOutArgsIndex[index]; + pArgs[nOutIndex] = aOutArgs[index]; + } + } + bRes = ( nErr == ERRCODE_NONE ); + } + catch ( const uno::Exception& ) + { + bRes = false; + } + return bRes; +#endif +} + + + +VBAMacroResolver::VBAMacroResolver() : + mpObjShell( nullptr ) +{ +} + +VBAMacroResolver::~VBAMacroResolver() +{ +} + +// com.sun.star.lang.XServiceInfo interface ----------------------------------- + +OUString SAL_CALL VBAMacroResolver::getImplementationName() +{ + return "com.sun.star.comp.vba.VBAMacroResolver"; +} + +sal_Bool SAL_CALL VBAMacroResolver::supportsService( const OUString& rService ) +{ + return cppu::supportsService(this, rService); +} + +uno::Sequence< OUString > SAL_CALL VBAMacroResolver::getSupportedServiceNames() +{ + return { "com.sun.star.script.vba.VBAMacroResolver" }; +} + +// com.sun.star.lang.XInitialization interface -------------------------------- + +void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& rArgs ) +{ + OSL_ENSURE( rArgs.getLength() > 1, "VBAMacroResolver::initialize - missing arguments" ); + if( rArgs.getLength() < 2 ) + throw uno::RuntimeException(); + + // first argument: document model + mxModel.set( rArgs[ 0 ], uno::UNO_QUERY_THROW ); + mpObjShell = comphelper::getFromUnoTunnel(mxModel); + if( !mpObjShell ) + throw uno::RuntimeException(); + + // second argument: VBA project name + if( !(rArgs[ 1 ] >>= maProjectName) || (maProjectName.isEmpty()) ) + throw uno::RuntimeException(); +} + +// com.sun.star.script.vba.XVBAMacroResolver interface ------------------------ + +OUString SAL_CALL VBAMacroResolver::resolveVBAMacroToScriptURL( const OUString& rVBAMacroName ) +{ + if( !mpObjShell ) + throw uno::RuntimeException(); + + // the name may be enclosed in apostrophs + OUString aMacroName( trimMacroName( rVBAMacroName ) ); + if( aMacroName.isEmpty() ) + throw lang::IllegalArgumentException(); + + // external references not supported here (syntax is "url!macroname" or "[url]!macroname" or "[url]macroname") + if( (aMacroName[ 0 ] == '[') || (aMacroName.indexOf( '!' ) >= 0) ) + throw lang::IllegalArgumentException(); + + // check if macro name starts with project name, replace with "Standard" + // TODO: adjust this when custom VBA project name is supported + sal_Int32 nDotPos = aMacroName.indexOf( '.' ); + if( (nDotPos == 0) || (nDotPos + 1 == aMacroName.getLength()) ) + throw lang::IllegalArgumentException(); + if( (nDotPos > 0) && aMacroName.matchIgnoreAsciiCase( maProjectName ) ) + aMacroName = aMacroName.copy( nDotPos + 1 ); + + // try to find the macro + MacroResolvedInfo aInfo = resolveVBAMacro( mpObjShell, aMacroName ); + if( !aInfo.mbFound ) + throw lang::IllegalArgumentException(); + + // build and return the script URL + return makeMacroURL( aInfo.msResolvedMacro ); +} + +OUString SAL_CALL VBAMacroResolver::resolveScriptURLtoVBAMacro( const OUString& /*rScriptURL*/ ) +{ + OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" ); + throw uno::RuntimeException(); +} + +static bool getModifier( sal_Unicode c, sal_uInt16& mod ) +{ + if ( c == '+' ) { + mod |= KEY_SHIFT; + return true; + } else if ( c == '^' ) { + mod |= KEY_MOD1; + return true; + } else if ( c == '%' ) { + mod |= KEY_MOD2; + return true; + } + return false; +} + +/// @throws uno::RuntimeException +static sal_uInt16 parseChar( sal_Unicode c ) +{ + sal_uInt16 nVclKey = 0; + // do we care about locale here for letters/digits? probably not + if ( rtl::isAsciiAlpha( c ) ) + { + nVclKey |= ( rtl::toAsciiUpperCase( c ) - 'A' ) + KEY_A; + if ( rtl::isAsciiUpperCase( c ) ) + nVclKey |= KEY_SHIFT; + } + else if ( rtl::isAsciiDigit( c ) ) + nVclKey |= ( c - '0' ) + KEY_0; + else if ( c == '~' ) // special case + nVclKey = KEY_RETURN; + else if ( c == ' ' ) // special case + nVclKey = KEY_SPACE; + else // I guess we have a problem ( but not sure if locale specific keys might come into play here ) + throw uno::RuntimeException(); + return nVclKey; +} + +namespace { + +struct KeyCodeEntry +{ + const char* sName; + sal_uInt16 nCode; +}; + +} + +KeyCodeEntry const aMSKeyCodesData[] = { + { "BACKSPACE", KEY_BACKSPACE }, + { "BS", KEY_BACKSPACE }, + { "DELETE", KEY_DELETE }, + { "DEL", KEY_DELETE }, + { "DOWN", KEY_DOWN }, + { "UP", KEY_UP }, + { "LEFT", KEY_LEFT }, + { "RIGHT", KEY_RIGHT }, + { "END", KEY_END }, + { "ESCAPE", KEY_ESCAPE }, + { "ESC", KEY_ESCAPE }, + { "HELP", KEY_HELP }, + { "HOME", KEY_HOME }, + { "PGDN", KEY_PAGEDOWN }, + { "PGUP", KEY_PAGEUP }, + { "INSERT", KEY_INSERT }, + { "SCROLLLOCK", KEY_SCROLLLOCK }, + { "NUMLOCK", KEY_NUMLOCK }, + { "TAB", KEY_TAB }, + { "F1", KEY_F1 }, + { "F2", KEY_F2 }, + { "F3", KEY_F3 }, + { "F4", KEY_F4 }, + { "F5", KEY_F5 }, + { "F6", KEY_F6 }, + { "F7", KEY_F7 }, + { "F8", KEY_F8 }, + { "F9", KEY_F9 }, + { "F10", KEY_F10 }, + { "F11", KEY_F11 }, + { "F12", KEY_F12 }, + { "F13", KEY_F13 }, + { "F14", KEY_F14 }, + { "F15", KEY_F15 }, +}; + +awt::KeyEvent parseKeyEvent( const OUString& Key ) +{ + static std::map< OUString, sal_uInt16 > s_KeyCodes = []() + { + std::map< OUString, sal_uInt16 > tmp; + for (KeyCodeEntry const & i : aMSKeyCodesData) + { + tmp[ OUString::createFromAscii( i.sName ) ] = i.nCode; + } + return tmp; + }(); + OUString sKeyCode; + sal_uInt16 nVclKey = 0; + + // parse the modifier if any + for ( int i=0; isecond; + } + } + + awt::KeyEvent aKeyEvent = svt::AcceleratorExecute::st_VCLKey2AWTKey( vcl::KeyCode( nVclKey ) ); + return aKeyEvent; +} + +void applyShortCutKeyBinding ( const uno::Reference< frame::XModel >& rxModel, const awt::KeyEvent& rKeyEvent, const OUString& rMacroName ) +{ + OUString MacroName( rMacroName ); + if ( !MacroName.isEmpty() ) + { + OUString aMacroName = MacroName.trim(); + if( aMacroName.startsWith("!") ) + aMacroName = o3tl::trim(aMacroName.subView(1)); + SfxObjectShell* pShell = nullptr; + if ( rxModel.is() ) + { + pShell = comphelper::getFromUnoTunnel(rxModel); + if ( !pShell ) + throw uno::RuntimeException(); + } + MacroResolvedInfo aMacroInfo = resolveVBAMacro( pShell, aMacroName ); + if( !aMacroInfo.mbFound ) + throw uno::RuntimeException( "The procedure doesn't exist" ); + MacroName = aMacroInfo.msResolvedMacro; + } + uno::Reference< ui::XUIConfigurationManagerSupplier > xCfgSupplier(rxModel, uno::UNO_QUERY_THROW); + uno::Reference< ui::XUIConfigurationManager > xCfgMgr = xCfgSupplier->getUIConfigurationManager(); + + uno::Reference< ui::XAcceleratorConfiguration > xAcc( xCfgMgr->getShortCutManager(), uno::UNO_SET_THROW ); + if ( MacroName.isEmpty() ) + // I believe this should really restore the [application] default. Since + // afaik we don't actually setup application default bindings on import + // we don't even know what the 'default' would be for this key + xAcc->removeKeyEvent( rKeyEvent ); + else + xAcc->setKeyEvent( rKeyEvent, ooo::vba::makeMacroURL( MacroName ) ); + +} + + +} // namespace ooo + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_VBAMacroResolver_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new ooo::vba::VBAMacroResolver()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/filter/source/msfilter/rtfutil.cxx b/filter/source/msfilter/rtfutil.cxx new file mode 100644 index 000000000..e20a146c4 --- /dev/null +++ b/filter/source/msfilter/rtfutil.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/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ +/** + * If rOle1 is native OLE1 data of size nOle1Size, wraps it in an OLE2 container. + * + * The OLE2 root's CLSID is set based on rClassName. + */ +void WrapOle1InOle2(SvStream& rOle1, sal_uInt32 nOle1Size, SvStream& rOle2, + const OString& rClassName) +{ + tools::SvRef pStorage = new SotStorage(rOle2); + OString aAnsiUserType; + SvGlobalName aName; + if (rClassName == "PBrush") + { + aAnsiUserType = "Bitmap Image"; + aName = SvGlobalName(0x0003000A, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46); + } + else + { + if (!rClassName.isEmpty() && rClassName != "Package") + { + SAL_WARN("filter.ms", "WrapOle1InOle2: unexpected class name: '" << rClassName << "'"); + } + aAnsiUserType = "OLE Package"; + aName = SvGlobalName(0x0003000C, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46); + } + pStorage->SetClass(aName, SotClipboardFormatId::NONE, ""); + + // [MS-OLEDS] 2.3.7 CompObjHeader + tools::SvRef pCompObj = pStorage->OpenSotStream("\1CompObj"); + // Reserved1 + pCompObj->WriteUInt32(0xfffe0001); + // Version + pCompObj->WriteUInt32(0x00000a03); + // Reserved2 + pCompObj->WriteUInt32(0xffffffff); + pCompObj->WriteUInt32(0x0003000c); + pCompObj->WriteUInt32(0x00000000); + pCompObj->WriteUInt32(0x000000c0); + pCompObj->WriteUInt32(0x46000000); + // Rest of CompObjStream + // AnsiUserType + pCompObj->WriteUInt32(aAnsiUserType.getLength() + 1); + pCompObj->WriteOString(aAnsiUserType); + pCompObj->WriteChar(0); + // AnsiClipboardFormat + pCompObj->WriteUInt32(0x00000000); + // Reserved1 + pCompObj->WriteUInt32(rClassName.getLength() + 1); + pCompObj->WriteOString(rClassName); + pCompObj->WriteChar(0); + // UnicodeMarker + pCompObj->WriteUInt32(0x71B239F4); + // UnicodeUserType + pCompObj->WriteUInt32(0x00000000); + // UnicodeClipboardFormat + pCompObj->WriteUInt32(0x00000000); + // Reserved2 + pCompObj->WriteUInt32(0x00000000); + pCompObj->Commit(); + pCompObj.clear(); + + // [MS-OLEDS] 2.3.6 OLENativeStream + tools::SvRef pOleNative = pStorage->OpenSotStream("\1Ole10Native"); + // NativeDataSize + pOleNative->WriteUInt32(nOle1Size); + pOleNative->WriteStream(rOle1, nOle1Size); + pOleNative->Commit(); + pOleNative.clear(); + + pStorage->Commit(); + pStorage.clear(); + rOle2.Seek(0); +} +} + +namespace msfilter::rtfutil +{ +OString OutHex(sal_uLong nHex, sal_uInt8 nLen) +{ + char aNToABuf[] = "0000000000000000"; + + OSL_ENSURE(nLen < sizeof(aNToABuf), "nLen is too big"); + if (nLen >= sizeof(aNToABuf)) + nLen = (sizeof(aNToABuf) - 1); + + // Set pointer to the buffer end + char* pStr = aNToABuf + (sizeof(aNToABuf) - 1); + for (sal_uInt8 n = 0; n < nLen; ++n) + { + *(--pStr) = static_cast(nHex & 0xf) + 48; + if (*pStr > '9') + *pStr += 39; + nHex >>= 4; + } + return pStr; +} + +// Ideally, this function should work on (sal_uInt32) Unicode scalar values +// instead of (sal_Unicode) UTF-16 code units. However, at least "Rich Text +// Format (RTF) Specification Version 1.9.1" available at +// does not +// look like it allows non-BMP Unicode characters >= 0x10000 in the \uN notation +// (it only talks about "Unicode character", but then explains how values of N +// greater than 32767 will be expressed as negative signed 16-bit numbers, so +// that smells like \uN is limited to BMP). +// However the "Mathematics" section has an example that shows the code point +// U+1D44E being encoded as UTF-16 surrogate pair "\u-10187?\u-9138?", so +// sal_Unicode actually works fine here. +OString OutChar(sal_Unicode c, int* pUCMode, rtl_TextEncoding eDestEnc, bool* pSuccess, + bool bUnicode) +{ + if (pSuccess) + *pSuccess = true; + OStringBuffer aBuf; + const char* pStr = nullptr; + // 0x0b instead of \n, etc because of the replacements in SwWW8AttrIter::GetSnippet() + switch (c) + { + case 0x0b: + // hard line break + pStr = OOO_STRING_SVTOOLS_RTF_LINE; + break; + case '\t': + pStr = OOO_STRING_SVTOOLS_RTF_TAB; + break; + case '\\': + case '}': + case '{': + aBuf.append('\\'); + aBuf.append(static_cast(c)); + break; + case 0xa0: + // non-breaking space + pStr = "\\~"; + break; + case 0x1e: + // non-breaking hyphen + pStr = "\\_"; + break; + case 0x1f: + // optional hyphen + pStr = "\\-"; + break; + default: + if (c >= ' ' && c <= '~') + aBuf.append(static_cast(c)); + else + { + OUString sBuf(&c, 1); + OString sConverted; + if (pSuccess) + *pSuccess &= sBuf.convertToString(&sConverted, eDestEnc, + RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR); + else + sBuf.convertToString(&sConverted, eDestEnc, OUSTRING_TO_OSTRING_CVTFLAGS); + const sal_Int32 nLen = sConverted.getLength(); + + if (pUCMode && bUnicode) + { + if (*pUCMode != nLen) + { + aBuf.append("\\uc"); + aBuf.append(nLen); + // #i47831# add an additional whitespace, so that "document whitespaces" are not ignored. + aBuf.append(' '); + *pUCMode = nLen; + } + aBuf.append("\\u"); + aBuf.append(static_cast(c)); + } + + for (sal_Int32 nI = 0; nI < nLen; ++nI) + { + aBuf.append("\\'"); + aBuf.append(OutHex(sConverted[nI], 2)); + } + } + } + if (pStr) + { + aBuf.append(pStr); + switch (c) + { + case 0xa0: + case 0x1e: + case 0x1f: + break; + default: + aBuf.append(' '); + } + } + return aBuf.makeStringAndClear(); +} + +OString OutString(const OUString& rStr, rtl_TextEncoding eDestEnc, bool bUnicode) +{ + SAL_INFO("filter.ms", __func__ << ", rStr = '" << rStr << "'"); + OStringBuffer aBuf; + int nUCMode = 1; + for (sal_Int32 n = 0; n < rStr.getLength(); ++n) + aBuf.append(OutChar(rStr[n], &nUCMode, eDestEnc, nullptr, bUnicode)); + if (nUCMode != 1) + { + aBuf.append(OOO_STRING_SVTOOLS_RTF_UC); + aBuf.append(sal_Int32(1)); + aBuf.append( + " "); // #i47831# add an additional whitespace, so that "document whitespaces" are not ignored.; + } + return aBuf.makeStringAndClear(); +} + +/// Checks if lossless conversion of the string to eDestEnc is possible or not. +static bool TryOutString(const OUString& rStr, rtl_TextEncoding eDestEnc) +{ + int nUCMode = 1; + for (sal_Int32 n = 0; n < rStr.getLength(); ++n) + { + bool bRet; + OutChar(rStr[n], &nUCMode, eDestEnc, &bRet); + if (!bRet) + return false; + } + return true; +} + +OString OutStringUpr(const char* pToken, const OUString& rStr, rtl_TextEncoding eDestEnc) +{ + if (TryOutString(rStr, eDestEnc)) + return OString::Concat("{") + pToken + " " + OutString(rStr, eDestEnc) + "}"; + + return OString::Concat("{" OOO_STRING_SVTOOLS_RTF_UPR "{") + pToken + " " + + OutString(rStr, eDestEnc, /*bUnicode =*/false) + + "}{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_UD "{" + pToken + " " + + OutString(rStr, eDestEnc) + "}}}"; +} + +int AsHex(char ch) +{ + int ret = 0; + if (rtl::isAsciiDigit(static_cast(ch))) + ret = ch - '0'; + else + { + if (ch >= 'a' && ch <= 'f') + ret = ch - 'a'; + else if (ch >= 'A' && ch <= 'F') + ret = ch - 'A'; + else + return -1; + ret += 10; + } + return ret; +} + +OString WriteHex(const sal_uInt8* pData, sal_uInt32 nSize, SvStream* pStream, sal_uInt32 nLimit) +{ + OStringBuffer aRet; + + sal_uInt32 nBreak = 0; + for (sal_uInt32 i = 0; i < nSize; i++) + { + OString sNo = OString::number(pData[i], 16); + if (sNo.getLength() < 2) + { + if (pStream) + pStream->WriteChar('0'); + else + aRet.append('0'); + } + if (pStream) + pStream->WriteOString(sNo); + else + aRet.append(sNo); + if (++nBreak == nLimit) + { + if (pStream) + pStream->WriteCharPtr(SAL_NEWLINE_STRING); + else + aRet.append(SAL_NEWLINE_STRING); + nBreak = 0; + } + } + + return aRet.makeStringAndClear(); +} + +bool ExtractOLE2FromObjdata(const OString& rObjdata, SvStream& rOle2) +{ + SvMemoryStream aStream; + int b = 0; + int count = 2; + + // Feed the destination text to a stream. + for (int i = 0; i < rObjdata.getLength(); ++i) + { + char ch = rObjdata[i]; + if (ch != 0x0d && ch != 0x0a) + { + b = b << 4; + sal_Int8 parsed = msfilter::rtfutil::AsHex(ch); + if (parsed == -1) + return false; + b += parsed; + count--; + if (!count) + { + aStream.WriteChar(b); + count = 2; + b = 0; + } + } + } + + // Skip ObjectHeader, see [MS-OLEDS] 2.2.4. + if (!aStream.Tell()) + return true; + + aStream.Seek(0); + sal_uInt32 nData; + aStream.ReadUInt32(nData); // OLEVersion + aStream.ReadUInt32(nData); // FormatID + aStream.ReadUInt32(nData); // ClassName + OString aClassName; + if (nData) + { + // -1 because it is null-terminated. + aClassName = read_uInt8s_ToOString(aStream, nData - 1); + // Skip null-termination. + aStream.SeekRel(1); + } + aStream.ReadUInt32(nData); // TopicName + aStream.SeekRel(nData); + aStream.ReadUInt32(nData); // ItemName + aStream.SeekRel(nData); + aStream.ReadUInt32(nData); // NativeDataSize + + if (!nData) + return true; + + sal_uInt64 nPos = aStream.Tell(); + sal_uInt8 aSignature[8]; + aStream.ReadBytes(aSignature, SAL_N_ELEMENTS(aSignature)); + aStream.Seek(nPos); + const sal_uInt8 aOle2Signature[8] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; + // Don't use Storage::IsStorageFile() here, that would seek to the start of the stream, + // where the magic will always mismatch. + if (std::memcmp(aSignature, aOle2Signature, SAL_N_ELEMENTS(aSignature)) == 0) + { + // NativeData + rOle2.WriteStream(aStream, nData); + } + else + { + SvMemoryStream aStorage; + WrapOle1InOle2(aStream, nData, aStorage, aClassName); + rOle2.WriteStream(aStorage); + } + rOle2.Seek(0); + + return true; +} + +bool StripMetafileHeader(const sal_uInt8*& rpGraphicAry, sal_uInt64& rSize) +{ + if (rpGraphicAry && (rSize > 0x22)) + { + if ((rpGraphicAry[0] == 0xd7) && (rpGraphicAry[1] == 0xcd) && (rpGraphicAry[2] == 0xc6) + && (rpGraphicAry[3] == 0x9a)) + { + // we have to get rid of the metafileheader + rpGraphicAry += 22; + rSize -= 22; + return true; + } + } + return false; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/svdfppt.cxx b/filter/source/msfilter/svdfppt.cxx new file mode 100644 index 000000000..74f8da16f --- /dev/null +++ b/filter/source/msfilter/svdfppt.cxx @@ -0,0 +1,7832 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// PPT ColorScheme Slots +#define PPT_COLSCHEME (0x08000000) +#define PPT_COLSCHEME_HINTERGRUND (0x08000000) +#define PPT_COLSCHEME_TEXT_UND_ZEILEN (0x08000001) +#define PPT_COLSCHEME_TITELTEXT (0x08000003) +#define PPT_COLSCHEME_A_UND_HYPERLINK (0x08000006) + +#define ANSI_CHARSET 0 +#define SYMBOL_CHARSET 2 + +/* Font Families */ +#define FF_ROMAN 0x10 +#define FF_SWISS 0x20 +#define FF_MODERN 0x30 +#define FF_SCRIPT 0x40 +#define FF_DECORATIVE 0x50 + +#define DEFAULT_PITCH 0x00 +#define FIXED_PITCH 0x01 +#define VARIABLE_PITCH 0x02 + +using namespace ::com::sun::star ; +using namespace uno ; +using namespace beans ; +using namespace drawing ; +using namespace container ; +using namespace table ; + +PowerPointImportParam::PowerPointImportParam( SvStream& rDocStrm ) : + rDocStream ( rDocStrm ), + nImportFlags ( 0 ) +{ +} + +SvStream& ReadPptCurrentUserAtom( SvStream& rIn, PptCurrentUserAtom& rAtom ) +{ + DffRecordHeader aHd; + ReadDffRecordHeader( rIn, aHd ); + if ( aHd.nRecType == PPT_PST_CurrentUserAtom ) + { + sal_uInt32 nLen; + sal_uInt16 nUserNameLen(0), nPad; + rIn.ReadUInt32( nLen ) + .ReadUInt32( rAtom.nMagic ) + .ReadUInt32( rAtom.nCurrentUserEdit ) + .ReadUInt16( nUserNameLen ) + .ReadUInt16( rAtom.nDocFileVersion ) + .ReadUChar( rAtom.nMajorVersion ) + .ReadUChar( rAtom.nMinorVersion ) + .ReadUInt16( nPad ); + rAtom.aCurrentUser = SvxMSDffManager::MSDFFReadZString( rIn, nUserNameLen, true ); + } + aHd.SeekToEndOfRecord( rIn ); + return rIn; +} + +void PptSlidePersistAtom::Clear() +{ + nReserved = nPsrReference = nFlags = nNumberTexts = nSlideId = 0; +} + +SvStream& ReadPptSlidePersistAtom( SvStream& rIn, PptSlidePersistAtom& rAtom ) +{ + DffRecordHeader aHd; + ReadDffRecordHeader( rIn, aHd ); + rIn + .ReadUInt32( rAtom.nPsrReference ) + .ReadUInt32( rAtom.nFlags ) + .ReadUInt32( rAtom.nNumberTexts ) + .ReadUInt32( rAtom.nSlideId ); + aHd.SeekToEndOfRecord( rIn ); + return rIn; +} + +PptSlidePersistList::PptSlidePersistList() {} + +PptSlidePersistList::~PptSlidePersistList() {} + +sal_uInt16 PptSlidePersistList::FindPage(sal_uInt32 nId) const +{ + for ( size_t i=0; i < mvEntries.size(); i++ ) + { + if (mvEntries[ i ]->GetSlideId() == nId) return i; + } + return PPTSLIDEPERSIST_ENTRY_NOTFOUND; +} + +SvStream& ReadPptInteractiveInfoAtom( SvStream& rIn, PptInteractiveInfoAtom& rAtom ) +{ + rIn.ReadUInt32( rAtom.nSoundRef ) + .ReadUInt32( rAtom.nExHyperlinkId ) + .ReadUChar( rAtom.nAction ) + .ReadUChar( rAtom.nOleVerb ) + .ReadUChar( rAtom.nJump ) + .ReadUChar( rAtom.nFlags ) + .ReadUChar( rAtom.nHyperlinkType ) + .ReadUChar( rAtom.nUnknown1 ) + .ReadUChar( rAtom.nUnknown2 ) + .ReadUChar( rAtom.nUnknown3 ); + return rIn; +} + +SvStream& ReadPptExOleObjAtom( SvStream& rIn, PptExOleObjAtom& rAtom ) +{ + sal_uInt32 nDummy1; + sal_uInt32 nDummy2; + sal_uInt32 nDummy4; + + rIn.ReadUInt32( rAtom.nAspect ) + .ReadUInt32( nDummy1 ) + .ReadUInt32( rAtom.nId ) + .ReadUInt32( nDummy2 ) + .ReadUInt32( rAtom.nPersistPtr ) + .ReadUInt32( nDummy4 ); + return rIn; +} + +SvStream& ReadPptDocumentAtom(SvStream& rIn, PptDocumentAtom& rAtom) +{ +// Actual format: +// 00 aSlidePageSizeXY 8 +// 08 aNotesPageSizeXY 8 +// 16 aZoomRatio (OLE) 8 +// 24 nNotesMasterPersist 4 +// 28 nHandoutMasterPersist 4 +// 32 n1stPageNumber 2 +// 34 ePageFormat 2 +// 36 bEmbeddedTrueType 1 +// 37 bOmitTitlePlace 1 +// 38 bRightToLeft 1 +// 39 bShowComments 1 + + DffRecordHeader aHd; + sal_Int32 nSlideX(0), nSlideY(0), nNoticeX(0), nNoticeY(0), nDummy; + sal_uInt16 nSlidePageFormat(0); + sal_Int8 nEmbeddedTrueType(0), nTitlePlaceHoldersOmitted(0), nRightToLeft(0), nShowComments(0); + + ReadDffRecordHeader( rIn, aHd ); + rIn + .ReadInt32( nSlideX ).ReadInt32( nSlideY ) + .ReadInt32( nNoticeX ).ReadInt32( nNoticeY ) + .ReadInt32( nDummy ).ReadInt32( nDummy ) // skip ZoomRatio + .ReadUInt32( rAtom.nNotesMasterPersist ) + .ReadUInt32( rAtom.nHandoutMasterPersist ) + .ReadUInt16( rAtom.n1stPageNumber ) + .ReadUInt16( nSlidePageFormat ) + .ReadSChar( nEmbeddedTrueType ) + .ReadSChar( nTitlePlaceHoldersOmitted ) + .ReadSChar( nRightToLeft ) + .ReadSChar( nShowComments ); + // clamp dodgy data to avoid overflow in later calculations + const sal_Int32 nPageClamp = SAL_MAX_INT32/5; + rAtom.aSlidesPageSize.setWidth( std::clamp(nSlideX, -nPageClamp, nPageClamp) ); + rAtom.aSlidesPageSize.setHeight( std::clamp(nSlideY, -nPageClamp, nPageClamp) ); + const sal_Int32 nNoteClamp = 65536; + rAtom.aNotesPageSize.setWidth( std::clamp(nNoticeX, -nNoteClamp, nNoteClamp) ); + rAtom.aNotesPageSize.setHeight( std::clamp(nNoticeY, -nNoteClamp, nNoteClamp) ); + rAtom.eSlidesPageFormat = static_cast(nSlidePageFormat); + rAtom.bEmbeddedTrueType = nEmbeddedTrueType; + rAtom.bTitlePlaceholdersOmitted = nTitlePlaceHoldersOmitted; + rAtom.bRightToLeft = nRightToLeft; + rAtom.bShowComments = nShowComments; + aHd.SeekToEndOfRecord( rIn ); + return rIn; +} + +void PptSlideLayoutAtom::Clear() +{ + eLayout = PptSlideLayout::TITLESLIDE; + for (PptPlaceholder & i : aPlaceholderId) + i = PptPlaceholder::NONE; +} + +SvStream& ReadPptSlideLayoutAtom( SvStream& rIn, PptSlideLayoutAtom& rAtom ) +{ + sal_Int32 nTmp; + rIn.ReadInt32(nTmp); + rAtom.eLayout = static_cast(nTmp); + static_assert(sizeof(rAtom.aPlaceholderId) == 8, "wrong size of serialized array"); + rIn.ReadBytes(rAtom.aPlaceholderId, 8); + return rIn; +} + +SvStream& ReadPptSlideAtom( SvStream& rIn, PptSlideAtom& rAtom ) +{ + DffRecordHeader aHd; + ReadDffRecordHeader( rIn, aHd ); + ReadPptSlideLayoutAtom( rIn, rAtom.aLayout ); + rIn.ReadUInt32( rAtom.nMasterId ) + .ReadUInt32( rAtom.nNotesId ) + .ReadUInt16( rAtom.nFlags ); + aHd.SeekToEndOfRecord( rIn ); + return rIn; +} + +void PptSlideAtom::Clear() +{ + nMasterId = nNotesId = 0; + nFlags = 0; +} + +SvStream& ReadPptNotesAtom( SvStream& rIn, PptNotesAtom& rAtom ) +{ + DffRecordHeader aHd; + ReadDffRecordHeader( rIn, aHd ); + rIn + .ReadUInt32( rAtom.nSlideId ) + .ReadUInt16( rAtom.nFlags ); + aHd.SeekToEndOfRecord( rIn ); + return rIn; +} + +void PptNotesAtom::Clear() +{ + nSlideId = 0; + nFlags = 0; +} + +PptColorSchemeAtom::PptColorSchemeAtom() +{ +} + +Color PptColorSchemeAtom::GetColor( sal_uInt16 nNum ) const +{ + Color aRetval; + if ( nNum < 8 ) + { + nNum <<= 2; + aRetval.SetRed( aData[ nNum++ ] ); + aRetval.SetGreen( aData[ nNum++ ] ); + aRetval.SetBlue( aData[ nNum++ ] ); + } + return aRetval; +} + +SvStream& ReadPptColorSchemeAtom( SvStream& rIn, PptColorSchemeAtom& rAtom ) +{ + DffRecordHeader aHd; + ReadDffRecordHeader( rIn, aHd ); + rIn.ReadBytes(rAtom.aData, 32); + aHd.SeekToEndOfRecord( rIn ); + return rIn; +} + +SvStream& ReadPptFontEntityAtom( SvStream& rIn, PptFontEntityAtom& rAtom ) +{ + DffRecordHeader aHd; + ReadDffRecordHeader( rIn, aHd ); + sal_Unicode nTemp, cData[ 32 ]; + rIn.ReadBytes(cData, 64); + + sal_uInt8 lfCharset, lfPitchAndFamily; + + rIn.ReadUChar( lfCharset ) + .ReadUChar( rAtom.lfClipPrecision ) + .ReadUChar( rAtom.lfQuality ) + .ReadUChar( lfPitchAndFamily ); + + switch( lfCharset ) + { + case SYMBOL_CHARSET : + rAtom.eCharSet = RTL_TEXTENCODING_SYMBOL; + break; + case ANSI_CHARSET : + rAtom.eCharSet = RTL_TEXTENCODING_MS_1252; + break; + + default : + rAtom.eCharSet = osl_getThreadTextEncoding(); + } + switch ( lfPitchAndFamily & 0xf0 ) + { + case FF_ROMAN: + rAtom.eFamily = FAMILY_ROMAN; + break; + + case FF_SWISS: + rAtom.eFamily = FAMILY_SWISS; + break; + + case FF_MODERN: + rAtom.eFamily = FAMILY_MODERN; + break; + + case FF_SCRIPT: + rAtom.eFamily = FAMILY_SCRIPT; + break; + + case FF_DECORATIVE: + rAtom.eFamily = FAMILY_DECORATIVE; + break; + + default: + rAtom.eFamily = FAMILY_DONTKNOW; + break; + } + + switch ( lfPitchAndFamily & 0x0f ) + { + case FIXED_PITCH: + rAtom.ePitch = PITCH_FIXED; + break; + + case DEFAULT_PITCH: + case VARIABLE_PITCH: + default: + rAtom.ePitch = PITCH_VARIABLE; + break; + } + sal_uInt16 i; + for ( i = 0; i < 32; i++ ) + { + nTemp = cData[ i ]; + if ( !nTemp ) + break; +#ifdef OSL_BIGENDIAN + cData[ i ] = ( nTemp >> 8 ) | ( nTemp << 8 ); +#endif + } + rAtom.aName = OUString(cData, i); + OutputDevice* pDev = Application::GetDefaultDevice(); + rAtom.bAvailable = pDev->IsFontAvailable( rAtom.aName ); + aHd.SeekToEndOfRecord( rIn ); + return rIn; +} + +SvStream& ReadPptUserEditAtom( SvStream& rIn, PptUserEditAtom& rAtom ) +{ + sal_Int16 lastViewType = 0; + ReadDffRecordHeader( rIn, rAtom.aHd ); + rIn + .ReadInt32( rAtom.nLastSlideID ) + .ReadUInt32( rAtom.nVersion ) + .ReadUInt32( rAtom.nOffsetLastEdit ) + .ReadUInt32( rAtom.nOffsetPersistDirectory ) + .ReadUInt32( rAtom.nDocumentRef ) + .ReadUInt32( rAtom.nMaxPersistWritten ) + .ReadInt16( lastViewType ); + rAtom.eLastViewType = static_cast(lastViewType); + rAtom.aHd.SeekToEndOfRecord(rIn); + return rIn; +} + +void PptOEPlaceholderAtom::Clear() +{ + nPlacementId = 0; + nPlaceholderSize = 0; + nPlaceholderId = PptPlaceholder::NONE; +} + +SvStream& ReadPptOEPlaceholderAtom( SvStream& rIn, PptOEPlaceholderAtom& rAtom ) +{ + rIn.ReadUInt32( rAtom.nPlacementId ); + sal_uInt8 nTmp; + rIn.ReadUChar(nTmp); + rAtom.nPlaceholderId = static_cast(nTmp); + rIn.ReadUChar( rAtom.nPlaceholderSize ); + return rIn; +} + +PptSlidePersistEntry::PptSlidePersistEntry() : + nSlidePersistStartOffset( 0 ), + nSlidePersistEndOffset ( 0 ), + nBackgroundOffset ( 0 ), + nDrawingDgId ( 0xffffffff ), + pBObj ( nullptr ), + ePageKind ( PPT_MASTERPAGE ), + bNotesMaster ( false ), + bHandoutMaster ( false ), + bStarDrawFiller ( false ) +{ + HeaderFooterOfs[ 0 ] = HeaderFooterOfs[ 1 ] = HeaderFooterOfs[ 2 ] = HeaderFooterOfs[ 3 ] = 0; +} + +PptSlidePersistEntry::~PptSlidePersistEntry() +{ +} + +SdrEscherImport::SdrEscherImport( PowerPointImportParam& rParam, const OUString& rBaseURL ) : + SvxMSDffManager ( rParam.rDocStream, rBaseURL ), + nStreamLen ( 0 ), + rImportParam ( rParam ) +{ +} + +SdrEscherImport::~SdrEscherImport() +{ +} + +const PptSlideLayoutAtom* SdrEscherImport::GetSlideLayoutAtom() const +{ + return nullptr; +} + +bool SdrEscherImport::ReadString( OUString& rStr ) const +{ + bool bRet = false; + DffRecordHeader aStrHd; + ReadDffRecordHeader( rStCtrl, aStrHd ); + if (aStrHd.nRecType == PPT_PST_TextBytesAtom + || aStrHd.nRecType == PPT_PST_TextCharsAtom + || aStrHd.nRecType == PPT_PST_CString) + { + bool bUniCode = + (aStrHd.nRecType == PPT_PST_TextCharsAtom + || aStrHd.nRecType == PPT_PST_CString); + sal_uLong nBytes = aStrHd.nRecLen; + rStr = MSDFFReadZString( rStCtrl, nBytes, bUniCode ); + bRet = aStrHd.SeekToEndOfRecord( rStCtrl ); + } + else + aStrHd.SeekToBegOfRecord( rStCtrl ); + return bRet; +} + +bool SdrEscherImport::GetColorFromPalette(sal_uInt16 /*nNum*/, Color& /*rColor*/) const +{ + return false; +} + +bool SdrEscherImport::SeekToShape( SvStream& /*rSt*/, SvxMSDffClientData* /*pClientData*/, sal_uInt32 /*nId*/) const +{ + return false; +} + +const PptFontEntityAtom* SdrEscherImport::GetFontEnityAtom( sal_uInt32 nNum ) const +{ + if (m_xFonts && nNum < m_xFonts->size()) + return &(*m_xFonts)[ nNum ]; + return nullptr; +} + +SdrObject* SdrEscherImport::ReadObjText( PPTTextObj* /*pTextObj*/, SdrObject* pObj, SdPageCapsule /*pPage*/) const +{ + return pObj; +} + +void SdrEscherImport::ProcessClientAnchor2( SvStream& rSt, DffRecordHeader& rHd, DffObjData& rObj ) +{ + sal_Int32 l, t, r, b; + if ( rHd.nRecLen == 16 ) + { + rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b ); + } + else + { + sal_Int16 ls, ts, rs, bs; + rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange... + l = ls; + t = ts; + r = rs; + b = bs; + } + if (!rSt.good()) + { + SAL_WARN("filter.ms", "ProcessClientAnchor2: short read"); + return; + } + Scale( l ); + Scale( t ); + Scale( r ); + Scale( b ); + rObj.aChildAnchor = tools::Rectangle( l, t, r, b ); + rObj.bChildAnchor = true; +}; + +void SdrEscherImport::RecolorGraphic( SvStream& rSt, sal_uInt32 nRecLen, Graphic& rGraphic ) +{ + if ( rGraphic.GetType() != GraphicType::GdiMetafile ) + return; + + sal_uInt16 nX, nGlobalColorsCount, nFillColorsCount; + + rSt.ReadUInt16( nX ) + .ReadUInt16( nGlobalColorsCount ) + .ReadUInt16( nFillColorsCount ) + .ReadUInt16( nX ) + .ReadUInt16( nX ) + .ReadUInt16( nX ); + + if ( ( nGlobalColorsCount > 64 ) || ( nFillColorsCount > 64 ) ) + return; + + if ( static_cast( ( nGlobalColorsCount + nFillColorsCount ) * 44 + 12 ) != nRecLen ) + return; + + sal_uInt32 OriginalGlobalColors[ 64 ]; + sal_uInt32 NewGlobalColors[ 64 ]; + + sal_uInt32 i, j, nGlobalColorsChanged, nFillColorsChanged; + nGlobalColorsChanged = nFillColorsChanged = 0; + + sal_uInt32* pCurrentOriginal = OriginalGlobalColors; + sal_uInt32* pCurrentNew = NewGlobalColors; + sal_uInt32* pCount = &nGlobalColorsChanged; + i = nGlobalColorsCount; + + for ( j = 0; j < 2; j++ ) + { + for ( ; i > 0; i-- ) + { + sal_uInt64 nPos = rSt.Tell(); + sal_uInt16 nChanged; + rSt.ReadUInt16( nChanged ); + if ( nChanged & 1 ) + { + sal_uInt8 nDummy, nRed, nGreen, nBlue; + sal_uInt32 nColor = 0; + sal_uInt32 nIndex; + rSt.ReadUChar( nDummy ) + .ReadUChar( nRed ) + .ReadUChar( nDummy ) + .ReadUChar( nGreen ) + .ReadUChar( nDummy ) + .ReadUChar( nBlue ) + .ReadUInt32( nIndex ); + + if ( nIndex < 8 ) + { + Color aColor = MSO_CLR_ToColor( nIndex << 24 ); + nRed = aColor.GetRed(); + nGreen = aColor.GetGreen(); + nBlue = aColor.GetBlue(); + } + nColor = nRed | ( nGreen << 8 ) | ( nBlue << 16 ); + *pCurrentNew++ = nColor; + rSt.ReadUChar( nDummy ) + .ReadUChar( nRed ) + .ReadUChar( nDummy ) + .ReadUChar( nGreen ) + .ReadUChar( nDummy ) + .ReadUChar( nBlue ); + nColor = nRed | ( nGreen << 8 ) | ( nBlue << 16 ); + *pCurrentOriginal++ = nColor; + (*pCount)++; + } + rSt.Seek( nPos + 44 ); + } + pCount = &nFillColorsChanged; + i = nFillColorsCount; + } + if ( !(nGlobalColorsChanged || nFillColorsChanged) ) + return; + + std::unique_ptr pSearchColors(new Color[ nGlobalColorsChanged ]); + std::unique_ptr pReplaceColors(new Color[ nGlobalColorsChanged ]); + + for ( j = 0; j < nGlobalColorsChanged; j++ ) + { + sal_uInt32 nSearch = OriginalGlobalColors[ j ]; + sal_uInt32 nReplace = NewGlobalColors[ j ]; + + pSearchColors[ j ].SetRed( static_cast(nSearch) ); + pSearchColors[ j ].SetGreen( static_cast( nSearch >> 8 ) ); + pSearchColors[ j ].SetBlue( static_cast( nSearch >> 16 ) ); + + pReplaceColors[ j ].SetRed( static_cast(nReplace) ); + pReplaceColors[ j ].SetGreen( static_cast( nReplace >> 8 ) ); + pReplaceColors[ j ].SetBlue( static_cast( nReplace >> 16 ) ); + } + GDIMetaFile aGdiMetaFile( rGraphic.GetGDIMetaFile() ); + aGdiMetaFile.ReplaceColors( pSearchColors.get(), pReplaceColors.get(), + nGlobalColorsChanged ); + rGraphic = aGdiMetaFile; +} + +sal_uLong DffPropSet::SanitizeEndPos(SvStream &rIn, sal_uLong nEndRecPos) +{ + auto nStreamLen = rIn.Tell() + rIn.remainingSize(); + if (nEndRecPos > nStreamLen) + { + SAL_WARN("filter.ms", "Parsing error: " << nStreamLen << + " max end pos, but " << nEndRecPos << " claimed, truncating"); + nEndRecPos = nStreamLen; + } + return nEndRecPos; +} + +void ProcessData::NotifyFreeObj(SdrObject* pObj) +{ + if (rPersistEntry.xSolverContainer) + { + for (auto & pPtr : rPersistEntry.xSolverContainer->aCList) + { + if (pPtr->pAObj == pObj) + pPtr->pAObj = nullptr; + if (pPtr->pBObj == pObj) + pPtr->pBObj = nullptr; + if (pPtr->pCObj == pObj) + pPtr->pCObj = nullptr; + } + } +} + +/* ProcessObject is called from ImplSdPPTImport::ProcessObj to handle all application specific things, + such as the import of text, animation effects, header footer and placeholder. + + The parameter pOriginalObj is the object as it was imported by our general escher import, it must either + be deleted or it can be returned to be inserted into the sdr page. +*/ +SdrObject* SdrEscherImport::ProcessObj( SvStream& rSt, DffObjData& rObjData, SvxMSDffClientData& rClientData, tools::Rectangle& rTextRect, SdrObject* pOriginalObj ) +{ + if ( dynamic_cast(pOriginalObj) != nullptr ) + pOriginalObj->SetMergedItem( SdrTextFixedCellHeightItem( true ) ); + + // we are initializing our return value with the object that was imported by our escher import + SdrObject* pRet = pOriginalObj; + + ProcessData& rData = static_cast(rClientData); + PptSlidePersistEntry& rPersistEntry = rData.rPersistEntry; + + if ( ! (rObjData.nSpFlags & ShapeFlag::Group) ) // sj: #114758# ... + { + PptOEPlaceholderAtom aPlaceholderAtom; + + if ( maShapeRecords.SeekToContent( rSt, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) ) + { + sal_Int16 nHeaderFooterInstance = -1; + DffRecordHeader aClientDataHd; + auto nEndRecPos = SanitizeEndPos(rSt, maShapeRecords.Current()->GetRecEndFilePos()); + while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) ) + { + ReadDffRecordHeader( rSt, aClientDataHd ); + switch ( aClientDataHd.nRecType ) + { + // importing header/footer object from master page + case PPT_PST_OEPlaceholderAtom : + { + ReadPptOEPlaceholderAtom( rSt, aPlaceholderAtom ); + if ( nHeaderFooterInstance == -1 ) + { + switch ( aPlaceholderAtom.nPlaceholderId ) + { + case PptPlaceholder::MASTERSLIDENUMBER : nHeaderFooterInstance++; + [[fallthrough]]; + case PptPlaceholder::MASTERFOOTER : nHeaderFooterInstance++; + [[fallthrough]]; + case PptPlaceholder::MASTERHEADER : nHeaderFooterInstance++; + [[fallthrough]]; + case PptPlaceholder::MASTERDATE : nHeaderFooterInstance++; break; + default: break; + + } + if ( ! ( nHeaderFooterInstance & 0xfffc ) ) // is this a valid instance ( 0->3 ) + rPersistEntry.HeaderFooterOfs[ nHeaderFooterInstance ] = rObjData.rSpHd.GetRecBegFilePos(); + } + } + break; + + case PPT_PST_RecolorInfoAtom : + { + if ( auto pSdrGrafObj = dynamic_cast(pRet) ) + if ( pSdrGrafObj->HasGDIMetaFile() ) + { + Graphic aGraphic( pSdrGrafObj->GetGraphic() ); + RecolorGraphic( rSt, aClientDataHd.nRecLen, aGraphic ); + pSdrGrafObj->SetGraphic( aGraphic ); + } + } + break; + } + if (!aClientDataHd.SeekToEndOfRecord(rSt)) + break; + } + } + if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESSLIDEIMAGE ) && !rPersistEntry.bNotesMaster ) + { + sal_uInt16 nPageNum = pSdrModel->GetPageCount(); + if ( nPageNum > 0 ) + nPageNum--; + + // replacing the object which we will return with a SdrPageObj + SdrObject::Free( pRet ); + pRet = new SdrPageObj( + *pSdrModel, + rObjData.aBoundRect, + pSdrModel->GetPage(nPageNum - 1)); + } + else + { + // try to load some ppt text + PPTTextObj aTextObj( rSt, static_cast(*this), rPersistEntry, &rObjData ); + if ( aTextObj.Count() || aTextObj.GetOEPlaceHolderAtom() ) + { + bool bVerticalText = false; + // and if the text object is not empty, it must be applied to pRet, the object we + // initially got from our escher import + Degree100 nTextRotationAngle(0); + if ( IsProperty( DFF_Prop_txflTextFlow ) ) + { + auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF; + switch( eTextFlow ) + { + case mso_txflBtoT : // Bottom to Top non-@ + nTextRotationAngle += 9000_deg100; + break; + case mso_txflTtoBA : /* #68110# */ // Top to Bottom @-font + case mso_txflTtoBN : // Top to Bottom non-@ + case mso_txflVertN : // Vertical, non-@, top to bottom + bVerticalText = !bVerticalText; // nTextRotationAngle += 27000; + break; + // case mso_txflHorzN : // Horizontal non-@, normal + // case mso_txflHorzA : // Horizontal @-font, normal + default: break; + } + } + sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 ); + if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) ) + { + bVerticalText = !bVerticalText; + } + const bool bFail = o3tl::checked_multiply(nFontDirection, 9000, nFontDirection); + if (!bFail) + nTextRotationAngle -= Degree100(nFontDirection); + else + SAL_WARN("filter.ms", "Parsing error: bad fontdirection: " << nFontDirection); + aTextObj.SetVertical( bVerticalText ); + if ( pRet ) + { + bool bDeleteSource = aTextObj.GetOEPlaceHolderAtom() != nullptr; + if ( bDeleteSource && dynamic_cast(pRet) == nullptr // we are not allowed to get + && dynamic_cast(pRet) == nullptr // grouped placeholder objects + && dynamic_cast(pRet) == nullptr ) + SdrObject::Free( pRet ); + } + sal_uInt32 nTextFlags = aTextObj.GetTextFlags(); + sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 ); // 0.25 cm (emu) + sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ); // 0.25 cm (emu) + sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 ); // 0.13 cm (emu) + sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 ); + ScaleEmu( nTextLeft ); + ScaleEmu( nTextRight ); + ScaleEmu( nTextTop ); + ScaleEmu( nTextBottom ); + + sal_Int32 nMinFrameWidth = 0; + sal_Int32 nMinFrameHeight = 0; + bool bAutoGrowWidth, bAutoGrowHeight; + + SdrTextVertAdjust eTVA; + SdrTextHorzAdjust eTHA; + + nTextFlags &= PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT + | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK; + + if ( bVerticalText ) + { + eTVA = SDRTEXTVERTADJUST_BLOCK; + eTHA = SDRTEXTHORZADJUST_CENTER; + + // read text anchor + auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop); + + switch( eTextAnchor ) + { + case mso_anchorTop: + case mso_anchorTopCentered: + case mso_anchorTopBaseline: + case mso_anchorTopCenteredBaseline: + eTHA = SDRTEXTHORZADJUST_RIGHT; + break; + + case mso_anchorMiddle : + case mso_anchorMiddleCentered: + eTHA = SDRTEXTHORZADJUST_CENTER; + break; + + case mso_anchorBottom: + case mso_anchorBottomCentered: + case mso_anchorBottomBaseline: + case mso_anchorBottomCenteredBaseline: + eTHA = SDRTEXTHORZADJUST_LEFT; + break; + } + switch ( eTextAnchor ) + { + case mso_anchorTopCentered : + case mso_anchorMiddleCentered : + case mso_anchorBottomCentered : + case mso_anchorTopCenteredBaseline: + case mso_anchorBottomCenteredBaseline: + { + // check if it is sensible to use the centered alignment + const sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK; + switch (nTextFlags & nMask) + { + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT: + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER: + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT: + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK: + eTVA = SDRTEXTVERTADJUST_CENTER; // If the textobject has only one type of alignment, then the text has not to be displayed using the full width; + break; + } + break; + } + default: + break; + } + nMinFrameWidth = rTextRect.GetWidth() - ( nTextLeft + nTextRight ); + } + else + { + eTVA = SDRTEXTVERTADJUST_CENTER; + eTHA = SDRTEXTHORZADJUST_BLOCK; + + // read text anchor + auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop); + + switch( eTextAnchor ) + { + case mso_anchorTop: + case mso_anchorTopCentered: + case mso_anchorTopBaseline: + case mso_anchorTopCenteredBaseline: + eTVA = SDRTEXTVERTADJUST_TOP; + break; + + case mso_anchorMiddle : + case mso_anchorMiddleCentered: + eTVA = SDRTEXTVERTADJUST_CENTER; + break; + + case mso_anchorBottom: + case mso_anchorBottomCentered: + case mso_anchorBottomBaseline: + case mso_anchorBottomCenteredBaseline: + eTVA = SDRTEXTVERTADJUST_BOTTOM; + break; + } + switch ( eTextAnchor ) + { + case mso_anchorTopCentered : + case mso_anchorMiddleCentered : + case mso_anchorBottomCentered : + case mso_anchorTopCenteredBaseline: + case mso_anchorBottomCenteredBaseline: + { + // check if it is sensible to use the centered alignment + const sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK; + switch (nTextFlags & nMask) + { + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT: + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER: + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT: + case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK: + eTHA = SDRTEXTHORZADJUST_CENTER; // If the textobject has only one type of alignment, then the text has not to be displayed using the full width; + break; + } + break; + } + default: + break; + } + nMinFrameHeight = rTextRect.GetHeight() - ( nTextTop + nTextBottom ); + } + + SdrObjKind eTextKind = SdrObjKind::Rectangle; + if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESSLIDEIMAGE ) + || ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::MASTERNOTESSLIDEIMAGE ) ) + { + aTextObj.SetInstance( TSS_Type::Notes ); + eTextKind = SdrObjKind::TitleText; + } + else if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::MASTERNOTESBODYIMAGE ) + || ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESBODY ) ) + { + aTextObj.SetInstance( TSS_Type::Notes ); + eTextKind = SdrObjKind::Text; + } + + TSS_Type nDestinationInstance = aTextObj.GetInstance(); + if ( rPersistEntry.ePageKind == PPT_MASTERPAGE ) + { + if ( !rPersistEntry.pPresentationObjects ) + { + rPersistEntry.pPresentationObjects.reset( new sal_uInt32[ PPT_STYLESHEETENTRIES ] ); + memset( rPersistEntry.pPresentationObjects.get(), 0, PPT_STYLESHEETENTRIES * 4 ); + } + if ( !rPersistEntry.pPresentationObjects[ static_cast(nDestinationInstance) ] ) + rPersistEntry.pPresentationObjects[ static_cast(nDestinationInstance) ] = rObjData.rSpHd.GetRecBegFilePos(); + } + switch ( nDestinationInstance ) + { + case TSS_Type::PageTitle : + case TSS_Type::Title : + { + if ( GetSlideLayoutAtom()->eLayout == PptSlideLayout::TITLEMASTERSLIDE ) + nDestinationInstance = TSS_Type::Title; + else + nDestinationInstance = TSS_Type::PageTitle; + } + break; + case TSS_Type::Body : + case TSS_Type::HalfBody : + case TSS_Type::QuarterBody : + nDestinationInstance = TSS_Type::Body; + break; + default: break; + } + aTextObj.SetDestinationInstance( nDestinationInstance ); + + bool bAutoFit = false; // auto-scale text into shape box + switch ( aTextObj.GetInstance() ) + { + case TSS_Type::PageTitle : + case TSS_Type::Title : eTextKind = SdrObjKind::TitleText; break; + case TSS_Type::Subtitle : eTextKind = SdrObjKind::Text; break; + case TSS_Type::Body : + case TSS_Type::HalfBody : + case TSS_Type::QuarterBody : eTextKind = SdrObjKind::OutlineText; bAutoFit = true; break; + default: break; + } + if ( aTextObj.GetDestinationInstance() != TSS_Type::TextInShape ) + { + if ( !aTextObj.GetOEPlaceHolderAtom() || aTextObj.GetOEPlaceHolderAtom()->nPlaceholderId == PptPlaceholder::NONE ) + { + aTextObj.SetDestinationInstance( TSS_Type::TextInShape ); + eTextKind = SdrObjKind::Rectangle; + } + } + SdrObject* pTObj = nullptr; + bool bWordWrap = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone; + bool bFitShapeToText = ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0; + + if ( dynamic_cast(pRet) != nullptr && ( eTextKind == SdrObjKind::Rectangle ) ) + { + bAutoGrowHeight = bFitShapeToText; + bAutoGrowWidth = !bWordWrap; + pTObj = pRet; + pRet = nullptr; + } + else + { + if ( dynamic_cast(pRet) != nullptr ) + { + SdrObject::Free( pRet ); + pRet = nullptr; + } + pTObj = new SdrRectObj( + *pSdrModel, + eTextKind != SdrObjKind::Rectangle ? eTextKind : SdrObjKind::Text); + SfxItemSet aSet( pSdrModel->GetItemPool() ); + if ( !pRet ) + ApplyAttributes( rSt, aSet, rObjData ); + pTObj->SetMergedItemSet( aSet ); + if ( pRet ) + { + pTObj->SetMergedItem( XLineStyleItem( drawing::LineStyle_NONE ) ); + pTObj->SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) ); + } + if ( bVerticalText ) + { + bAutoGrowWidth = bFitShapeToText; + bAutoGrowHeight = false; + } + else + { + bAutoGrowWidth = false; + + // #119885# re-activating bFitShapeToText here, could not find deeper explanations + // for it (it was from 2005). Keeping the old comment here for reference + // old comment: // bFitShapeToText; can't be used, because we cut the text if it is too height, + bAutoGrowHeight = bFitShapeToText; + } + } + pTObj->SetMergedItem( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) ); + + //Autofit text only if there is no auto grow height and width + //See fdo#41245 + if (bAutoFit && !bAutoGrowHeight && !bAutoGrowWidth) + { + pTObj->SetMergedItem( SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_AUTOFIT) ); + } + + if ( dynamic_cast(pTObj) == nullptr ) + { + pTObj->SetMergedItem( makeSdrTextAutoGrowWidthItem( bAutoGrowWidth ) ); + pTObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( bAutoGrowHeight ) ); + } + else + { + pTObj->SetMergedItem( makeSdrTextWordWrapItem( bWordWrap ) ); + pTObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( bFitShapeToText ) ); + } + + pTObj->SetMergedItem( SdrTextVertAdjustItem( eTVA ) ); + pTObj->SetMergedItem( SdrTextHorzAdjustItem( eTHA ) ); + + if ( nMinFrameHeight < 0 ) + nMinFrameHeight = 0; + if ( dynamic_cast(pTObj) == nullptr ) + pTObj->SetMergedItem( makeSdrTextMinFrameHeightItem( nMinFrameHeight ) ); + + if ( nMinFrameWidth < 0 ) + nMinFrameWidth = 0; + if ( dynamic_cast(pTObj) == nullptr ) + pTObj->SetMergedItem( makeSdrTextMinFrameWidthItem( nMinFrameWidth ) ); + + // set margins at the borders of the textbox + pTObj->SetMergedItem( makeSdrTextLeftDistItem( nTextLeft ) ); + pTObj->SetMergedItem( makeSdrTextRightDistItem( nTextRight ) ); + pTObj->SetMergedItem( makeSdrTextUpperDistItem( nTextTop ) ); + pTObj->SetMergedItem( makeSdrTextLowerDistItem( nTextBottom ) ); + pTObj->SetMergedItem( SdrTextFixedCellHeightItem( true ) ); + + if ( dynamic_cast(pTObj) == nullptr ) + pTObj->SetSnapRect( rTextRect ); + pTObj = ReadObjText( &aTextObj, pTObj, rData.pPage ); + + if ( pTObj ) + { + /* check if our new snaprect makes trouble, + because we do not display the ADJUST_BLOCK + properly if the textsize is bigger than the + snaprect of the object. Then we will use + ADJUST_CENTER instead of ADJUST_BLOCK. + */ + if ( dynamic_cast(pTObj) == nullptr && !bFitShapeToText && !bWordWrap ) + { + SdrTextObj* pText = dynamic_cast( pTObj ); + if ( pText ) + { + if ( bVerticalText ) + { + if ( eTVA == SDRTEXTVERTADJUST_BLOCK ) + { + Size aTextSize( pText->GetTextSize() ); + aTextSize.AdjustWidth(nTextLeft + nTextRight ); + aTextSize.AdjustHeight(nTextTop + nTextBottom ); + if ( rTextRect.GetHeight() < aTextSize.Height() ) + pTObj->SetMergedItem( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) ); + } + } + else + { + if ( eTHA == SDRTEXTHORZADJUST_BLOCK ) + { + Size aTextSize( pText->GetTextSize() ); + aTextSize.AdjustWidth(nTextLeft + nTextRight ); + aTextSize.AdjustHeight(nTextTop + nTextBottom ); + if ( rTextRect.GetWidth() < aTextSize.Width() ) + pTObj->SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) ); + } + } + } + } + // rotate text with shape? + Degree100 nAngle = ( rObjData.nSpFlags & ShapeFlag::FlipV ) ? -mnFix16Angle : mnFix16Angle; // #72116# vertical flip -> rotate by using the other way + nAngle += nTextRotationAngle; + + if ( dynamic_cast< const SdrObjCustomShape* >(pTObj) == nullptr ) + { + if ( rObjData.nSpFlags & ShapeFlag::FlipV ) + { + pTObj->Rotate( rTextRect.Center(), 18000_deg100, 0.0, -1.0 ); + } + if ( rObjData.nSpFlags & ShapeFlag::FlipH ) + nAngle = 36000_deg100 - nAngle; + if ( nAngle ) + pTObj->NbcRotate( rObjData.aBoundRect.Center(), nAngle ); + } + if ( pRet ) + { + SdrObject* pGroup = new SdrObjGroup(*pSdrModel); + pGroup->GetSubList()->NbcInsertObject( pRet ); + pGroup->GetSubList()->NbcInsertObject( pTObj ); + pRet = pGroup; + } + else + pRet = pTObj; + } + } + } + } + else + { + if ( maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) ) + { + maShapeRecords.Current()->SeekToBegOfRecord( rSt ); + DffPropertyReader aSecPropSet( *this ); + aSecPropSet.ReadPropSet( rSt, &rClientData ); + sal_Int32 nTableProperties = aSecPropSet.GetPropertyValue( DFF_Prop_tableProperties, 0 ); + if ( nTableProperties & 3 ) + { + if ( aSecPropSet.SeekToContent( DFF_Prop_tableRowProperties, rSt ) ) + { + sal_Int16 i, nReadRowCount = 0; + rSt.ReadInt16( nReadRowCount ).ReadInt16( i ).ReadInt16( i ); + if (nReadRowCount > 0) + { + const size_t nMinRecordSize = 4; + const size_t nMaxRecords = rSt.remainingSize() / nMinRecordSize; + + auto nRowCount = o3tl::make_unsigned(nReadRowCount); + if (nRowCount > nMaxRecords) + { + SAL_WARN("filter.ms", "Parsing error: " << nMaxRecords << + " max possible entries, but " << nRowCount << " claimed, truncating"); + nRowCount = nMaxRecords; + } + if (nRowCount > 0) + { + std::unique_ptr pTableArry(new sal_uInt32[ nRowCount + 2 ]); + pTableArry[ 0 ] = nTableProperties; + pTableArry[ 1 ] = nRowCount; + for (decltype(nRowCount) nRow = 0; nRow < nRowCount; ++nRow) + rSt.ReadUInt32(pTableArry[nRow + 2]); + rData.pTableRowProperties = std::move(pTableArry); + } + } + } + } + } + } + if ( pRet ) // sj: #i38501#, and taking care of connections to group objects + { + if ( rObjData.nSpFlags & ShapeFlag::Background ) + { + pRet->NbcSetSnapRect( tools::Rectangle( Point(), rData.pPage.page->GetSize() ) ); // set size + } + if (rPersistEntry.xSolverContainer) + { + for (auto & pPtr : rPersistEntry.xSolverContainer->aCList) + { + if ( rObjData.nShapeId == pPtr->nShapeC ) + pPtr->pCObj = pRet; + else + { + SdrObject* pConnectObj = pRet; + if ( pOriginalObj && dynamic_cast< const SdrObjGroup* >(pRet) != nullptr ) + { /* check if the original object from the escherimport is part of the group object, + if this is the case, we will use the original object to connect to */ + SdrObjListIter aIter( *pRet, SdrIterMode::DeepWithGroups ); + while( aIter.IsMore() ) + { + SdrObject* pPartObj = aIter.Next(); + if ( pPartObj == pOriginalObj ) + { + pConnectObj = pPartObj; + break; + } + } + } + if ( rObjData.nShapeId == pPtr->nShapeA ) + { + pPtr->pAObj = pConnectObj; + pPtr->nSpFlagsA = rObjData.nSpFlags; + } + if ( rObjData.nShapeId == pPtr->nShapeB ) + { + pPtr->pBObj = pConnectObj; + pPtr->nSpFlagsB = rObjData.nSpFlags; + } + } + } + } + if ( rPersistEntry.ePageKind == PPT_MASTERPAGE ) + { // maybe the escher clusterlist is not correct, but we have to got the right page by using the + // spMaster property, so we are patching the table + if ( rPersistEntry.nDrawingDgId != 0xffffffff ) + { + sal_uInt32 nSec = ( rObjData.nShapeId >> 10 ) - 1; + if ( !maFidcls.empty() && ( nSec < mnIdClusters ) ) + maFidcls[ nSec ].dgid = rPersistEntry.nDrawingDgId; // insert the correct drawing id; + } + } + if ( GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ) & 0x10 ) + { + if (GetPropertyValue(DFF_Prop_fillType, mso_fillSolid) == mso_fillBackground) + { + rData.aBackgroundColoredObjects.push_back( pRet ); + } + } + } + return pRet; +} + +SdrPowerPointImport::SdrPowerPointImport( PowerPointImportParam& rParam, const OUString& rBaseURL ) : + SdrEscherImport ( rParam, rBaseURL ), + m_bOk ( rStCtrl.GetErrorCode() == ERRCODE_NONE ), + m_nPersistPtrCnt ( 0 ), + m_pDefaultSheet ( nullptr ), + m_nCurrentPageNum ( 0 ), + m_nDocStreamPos ( 0 ), + m_nPageColorsNum ( 0xFFFF ), + m_ePageColorsKind ( PPT_MASTERPAGE ), + m_eCurrentPageKind ( PPT_MASTERPAGE ) +{ + if ( m_bOk ) + { + nStreamLen = rStCtrl.TellEnd(); + + // try to allocate the UserEditAtom via CurrentUserAtom + sal_uInt32 nCurrentUserEdit = rParam.aCurrentUserAtom.nCurrentUserEdit; + if (nCurrentUserEdit && checkSeek(rStCtrl, nCurrentUserEdit)) + { + ReadPptUserEditAtom( rStCtrl, m_aUserEditAtom ); + } + if ( !m_aUserEditAtom.nOffsetPersistDirectory ) + { // if there is no UserEditAtom try to search the last one + + rStCtrl.Seek( 0 ); + DffRecordManager aPptRecManager; // contains all first level container and atoms + aPptRecManager.Consume( rStCtrl, nStreamLen ); + DffRecordHeader* pHd; + for ( pHd = aPptRecManager.Last(); pHd; pHd = aPptRecManager.Prev() ) + { + if ( pHd->nRecType == PPT_PST_UserEditAtom ) + { + pHd->SeekToBegOfRecord( rStCtrl ); + ReadPptUserEditAtom( rStCtrl, m_aUserEditAtom ); + break; + } + } + if ( !pHd ) + m_bOk = false; + } + } + if ( rStCtrl.GetError() != ERRCODE_NONE ) + m_bOk = false; + + if ( m_bOk ) + { + m_nPersistPtrCnt = m_aUserEditAtom.nMaxPersistWritten + 1; + if ( ( m_nPersistPtrCnt >> 2 ) > nStreamLen ) // sj: at least m_nPersistPtrCnt is not allowed to be greater than filesize + m_bOk = false; // (it should not be greater than the PPT_PST_PersistPtrIncrementalBlock, but + // we are reading this block later, so we do not have access yet) + + if ( m_bOk && ( m_nPersistPtrCnt < ( SAL_MAX_UINT32 / sizeof( sal_uInt32 ) ) -1 ) ) + m_pPersistPtr.reset( new (std::nothrow) sal_uInt32[ m_nPersistPtrCnt + 1 ] ); + if ( !m_pPersistPtr ) + m_bOk = false; + if ( m_bOk ) + { + memset( m_pPersistPtr.get(), 0x00, (m_nPersistPtrCnt+1) * sizeof(sal_uInt32) ); + + // SJ: new search mechanism from bottom to top (Issue 21122) + PptUserEditAtom aCurrentEditAtom( m_aUserEditAtom ); + sal_uInt32 nCurrentEditAtomStrmPos = aCurrentEditAtom.aHd.GetRecEndFilePos(); + while( nCurrentEditAtomStrmPos ) + { + sal_uInt32 nPersistIncPos = aCurrentEditAtom.nOffsetPersistDirectory; + if (nPersistIncPos && checkSeek(rStCtrl, nPersistIncPos)) + { + DffRecordHeader aPersistHd; + ReadDffRecordHeader( rStCtrl, aPersistHd ); + if ( aPersistHd.nRecType == PPT_PST_PersistPtrIncrementalBlock ) + { + sal_uLong nPibLen = aPersistHd.GetRecEndFilePos(); + while (m_bOk && rStCtrl.good() && (rStCtrl.Tell() < nPibLen)) + { + sal_uInt32 nOfs(0); + rStCtrl.ReadUInt32( nOfs ); + sal_uInt32 nCnt = nOfs; + nOfs &= 0x000FFFFF; + nCnt >>= 20; + while (m_bOk && rStCtrl.good() && (nCnt > 0) && (nOfs <= m_nPersistPtrCnt)) + { + sal_uInt32 nPt(0); + rStCtrl.ReadUInt32( nPt ); + if ( !m_pPersistPtr[ nOfs ] ) + { + m_pPersistPtr[ nOfs ] = nPt; + if ( m_pPersistPtr[ nOfs ] > nStreamLen ) + { + m_bOk = false; + OSL_FAIL("SdrPowerPointImport::Ctor(): Invalid Entry in Persist-Directory!"); + } + } + nCnt--; + nOfs++; + } + if ( m_bOk && nCnt > 0 ) + { + OSL_FAIL("SdrPowerPointImport::Ctor(): Not all entries of Persist-Directory read!"); + m_bOk = false; + } + } + } + } + nCurrentEditAtomStrmPos = aCurrentEditAtom.nOffsetLastEdit < nCurrentEditAtomStrmPos ? aCurrentEditAtom.nOffsetLastEdit : 0; + if (nCurrentEditAtomStrmPos && checkSeek(rStCtrl, nCurrentEditAtomStrmPos)) + { + ReadPptUserEditAtom( rStCtrl, aCurrentEditAtom ); + } + } + } + } + if ( rStCtrl.GetError() != ERRCODE_NONE ) + m_bOk = false; + if ( m_bOk ) + { // check Document PersistEntry + m_nDocStreamPos = m_aUserEditAtom.nDocumentRef; + if ( m_nDocStreamPos > m_nPersistPtrCnt ) + { + OSL_FAIL("SdrPowerPointImport::Ctor(): m_aUserEditAtom.nDocumentRef invalid!"); + m_bOk = false; + } + } + if ( m_bOk ) + { // check Document FilePos + m_nDocStreamPos = m_pPersistPtr[ m_nDocStreamPos ]; + if ( m_nDocStreamPos >= nStreamLen ) + { + OSL_FAIL("SdrPowerPointImport::Ctor(): m_nDocStreamPos >= nStreamLen!"); + m_bOk = false; + } + } + if ( m_bOk ) + { + rStCtrl.Seek( m_nDocStreamPos ); + aDocRecManager.Consume( rStCtrl ); + + DffRecordHeader aDocHd; + ReadDffRecordHeader( rStCtrl, aDocHd ); + // read DocumentAtom + DffRecordHeader aDocAtomHd; + ReadDffRecordHeader( rStCtrl, aDocAtomHd ); + if ( aDocHd.nRecType == PPT_PST_Document && aDocAtomHd.nRecType == PPT_PST_DocumentAtom ) + { + aDocAtomHd.SeekToBegOfRecord( rStCtrl ); + ReadPptDocumentAtom( rStCtrl, aDocAtom ); + } + else + m_bOk = false; + + if ( m_bOk ) + { + if (!m_xFonts) + ReadFontCollection(); + + // reading TxPF, TxSI + PPTTextParagraphStyleAtomInterpreter aTxPFStyle; + PPTTextSpecInfoAtomInterpreter aTxSIStyle; // styles (default language setting ... ) + + DffRecordHeader* pEnvHd = aDocRecManager.GetRecordHeader( PPT_PST_Environment ); + if ( pEnvHd ) + { + pEnvHd->SeekToContent( rStCtrl ); + DffRecordHeader aTxPFStyleRecHd; + if ( SeekToRec( rStCtrl, PPT_PST_TxPFStyleAtom, pEnvHd->GetRecEndFilePos(), &aTxPFStyleRecHd ) ) + aTxPFStyle.Read( rStCtrl, aTxPFStyleRecHd ); + + pEnvHd->SeekToContent( rStCtrl ); + DffRecordHeader aTxSIStyleRecHd; + if ( SeekToRec( rStCtrl, PPT_PST_TxSIStyleAtom, pEnvHd->GetRecEndFilePos(), &aTxSIStyleRecHd ) ) + { + aTxSIStyle.Read( rStCtrl, aTxSIStyleRecHd, PPT_PST_TxSIStyleAtom ); +#ifdef DBG_UTIL + if ( !aTxSIStyle.bValid ) + { + if (!(rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT )) + { + OSL_FAIL( "SdrTextSpecInfoAtomInterpreter::Ctor(): parsing error, this document needs to be analysed (SJ)" ); + } + } +#endif + } + } + + // TODO:: PPT_PST_TxPFStyleAtom + + // read SlidePersists + m_pMasterPages.reset( new PptSlidePersistList ); + m_pSlidePages.reset( new PptSlidePersistList ); + m_pNotePages.reset( new PptSlidePersistList ); + + // now always creating the handout page, it will be the first in our masterpage list + std::unique_ptr pE(new PptSlidePersistEntry); + pE->aPersistAtom.nPsrReference = aDocAtom.nHandoutMasterPersist; + pE->bHandoutMaster = true; + if ( !aDocAtom.nHandoutMasterPersist ) + pE->bStarDrawFiller = true; // this is a dummy master page + m_pMasterPages->insert(m_pMasterPages->begin(), std::move(pE)); + + DffRecordHeader* pSlideListWithTextHd = aDocRecManager.GetRecordHeader( PPT_PST_SlideListWithText ); + PptSlidePersistEntry* pPreviousPersist = nullptr; + DffRecordHeader* pSlideListHd = aDocRecManager.GetRecordHeader(PPT_PST_List); + sal_uLong nPSTList = 0; + if (pSlideListHd) nPSTList = pSlideListHd->GetRecBegFilePos(); + sal_uInt16 nRealPageNum = 0; + // Normal PPT document has order of Master slides - Presentation slides - Note slides + // for document with the order of Master slides - Note slides - Presentation slides + // we need to swap the later two sections + bool notePresentationSwap = false; + for (sal_uInt16 nPageListNum = 0; + pSlideListWithTextHd && nPageListNum < 3; ++nPageListNum) + { + pSlideListWithTextHd->SeekToContent( rStCtrl ); + PptSlidePersistList* pPageList = nullptr; + sal_uInt32 nSlideListWithTextHdEndOffset = pSlideListWithTextHd->GetRecEndFilePos(); + nRealPageNum = nPageListNum; + while ( SeekToRec( rStCtrl, PPT_PST_SlidePersistAtom, nSlideListWithTextHdEndOffset ) ) + { + if ( pPreviousPersist ) + pPreviousPersist->nSlidePersistEndOffset = rStCtrl.Tell(); + std::unique_ptr pE2(new PptSlidePersistEntry); + ReadPptSlidePersistAtom( rStCtrl, pE2->aPersistAtom ); + pE2->nSlidePersistStartOffset = rStCtrl.Tell(); + // Note/Presentation section swap + if (nPageListNum == 1 && pE2->nSlidePersistStartOffset < nPSTList) + { + notePresentationSwap = true; + } + if (notePresentationSwap) + { + if (nPageListNum == 1) nRealPageNum = 2; + else if (nPageListNum == 2) nRealPageNum = 1; + } + + pE2->ePageKind = PptPageKind(nRealPageNum); + pPreviousPersist = pE2.get(); + if (!pPageList) + { + pPageList = GetPageList(PptPageKind(nRealPageNum)); + } + pPageList->push_back(std::move(pE2)); + } + if ( pPreviousPersist ) + pPreviousPersist->nSlidePersistEndOffset = nSlideListWithTextHdEndOffset; + pSlideListWithTextHd = aDocRecManager.GetRecordHeader( PPT_PST_SlideListWithText, SEEK_FROM_CURRENT ); + } + + // we will ensure that there is at least one master page + if (m_pMasterPages->size() == 1) // -> there is only a handout page available + { + std::unique_ptr pE2(new PptSlidePersistEntry); + pE2->bStarDrawFiller = true; // this is a dummy master page + m_pMasterPages->insert(m_pMasterPages->begin() + 1, std::move(pE2)); + } + + // now we will insert at least one notes master for each master page + sal_uInt16 nMasterPage; + sal_uInt16 nMasterPages = m_pMasterPages->size() - 1; + for ( nMasterPage = 0; nMasterPage < nMasterPages; nMasterPage++ ) + { + std::unique_ptr pE2(new PptSlidePersistEntry); + pE2->bNotesMaster = true; + pE2->bStarDrawFiller = true; // this is a dummy master page + if ( !nMasterPage && aDocAtom.nNotesMasterPersist ) + { // special treatment for the first notes master + pE2->aPersistAtom.nPsrReference = aDocAtom.nNotesMasterPersist; + pE2->bStarDrawFiller = false; // this is a dummy master page + } + m_pMasterPages->insert(m_pMasterPages->begin() + ((nMasterPage + 1) << 1), std::move(pE2)); + } + + // read for each page the SlideAtom respectively the NotesAtom if it exists + for (sal_uInt16 nPageListNum = 0; nPageListNum < 3; ++nPageListNum) + { + PptSlidePersistList* pPageList = GetPageList( PptPageKind( nPageListNum ) ); + for ( size_t nPageNum = 0; nPageNum < pPageList->size(); nPageNum++ ) + { + PptSlidePersistEntry& rE2 = (*pPageList)[ nPageNum ]; + sal_uLong nPersist = rE2.aPersistAtom.nPsrReference; + if ( ( nPersist > 0 ) && ( nPersist < m_nPersistPtrCnt ) ) + { + sal_uLong nFPos = m_pPersistPtr[ nPersist ]; + if ( nFPos < nStreamLen ) + { + rStCtrl.Seek( nFPos ); + DffRecordHeader aSlideHd; + ReadDffRecordHeader( rStCtrl, aSlideHd ); + if ( SeekToRec( rStCtrl, PPT_PST_SlideAtom, aSlideHd.GetRecEndFilePos() ) ) + ReadPptSlideAtom( rStCtrl, rE2.aSlideAtom ); + else if ( SeekToRec( rStCtrl, PPT_PST_NotesAtom, aSlideHd.GetRecEndFilePos() ) ) + ReadPptNotesAtom( rStCtrl, rE2.aNotesAtom ); + aSlideHd.SeekToContent( rStCtrl ); + + DffRecordHeader aPPTDrawingHd; + if ( SeekToRec( rStCtrl, PPT_PST_PPDrawing, aSlideHd.GetRecEndFilePos(), &aPPTDrawingHd ) ) + { + DffRecordHeader aPPTDgContainer; + if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, aPPTDrawingHd.GetRecEndFilePos(), &aPPTDgContainer ) ) + { + if ( SeekToRec( rStCtrl, DFF_msofbtDg, aPPTDrawingHd.GetRecEndFilePos() ) ) + { + DffRecordHeader aDgRecordHeader; + ReadDffRecordHeader( rStCtrl, aDgRecordHeader ); + rE2.nDrawingDgId = aDgRecordHeader.nRecInstance; + aDgRecordHeader.SeekToEndOfRecord( rStCtrl ); + } + if ( SeekToRec( rStCtrl, DFF_msofbtSolverContainer, aPPTDgContainer.GetRecEndFilePos() ) ) + { + rE2.xSolverContainer.reset(new SvxMSDffSolverContainer); + ReadSvxMSDffSolverContainer(rStCtrl, *rE2.xSolverContainer); + } + aPPTDgContainer.SeekToBegOfRecord( rStCtrl ); + SetDgContainer( rStCtrl ); // set this, so that the escherimport is knowing of our drawings + } + } + // office xp is supporting more than one stylesheet + if ( ( rE2.ePageKind == PPT_MASTERPAGE ) && ( rE2.aSlideAtom.nMasterId == 0 ) && !rE2.bNotesMaster ) + { + PPTTextSpecInfo aTxSI( 0 ); + if ( aTxSIStyle.bValid && !aTxSIStyle.aList.empty() ) + aTxSI = aTxSIStyle.aList[ 0 ]; + + rE2.xStyleSheet = std::make_unique(aSlideHd, rStCtrl, *this, aTxPFStyle, aTxSI); + m_pDefaultSheet = rE2.xStyleSheet.get(); + } + if ( SeekToRec( rStCtrl, PPT_PST_ColorSchemeAtom, aSlideHd.GetRecEndFilePos() ) ) + ReadPptColorSchemeAtom( rStCtrl, rE2.aColorScheme ); + else + { + OSL_FAIL( "SdrPowerPointImport::Ctor(): could not get SlideColorScheme! (SJ)" ); + } + } + else + { + OSL_FAIL("SdrPowerPointImport::Ctor(): Persist entry is flawed! (SJ)"); + } + } + } + } + DffRecordHeader* pHeadersFootersHd = aDocRecManager.GetRecordHeader( PPT_PST_HeadersFooters ); + if ( pHeadersFootersHd ) + { + HeaderFooterEntry aNormalMaster, aNotesMaster; + for ( ; pHeadersFootersHd; pHeadersFootersHd = aDocRecManager.GetRecordHeader( PPT_PST_HeadersFooters, SEEK_FROM_CURRENT ) ) + { + if ( pHeadersFootersHd->nRecInstance == 3 ) // normal master + ImportHeaderFooterContainer( *pHeadersFootersHd, aNormalMaster ); + else if ( pHeadersFootersHd->nRecInstance == 4 ) // notes master + ImportHeaderFooterContainer( *pHeadersFootersHd, aNotesMaster ); + } + for (size_t i = 0; i < m_pMasterPages->size(); i++) + { + if ((*m_pMasterPages)[ i ].bNotesMaster) + (*m_pMasterPages)[ i ].xHeaderFooterEntry.reset(new HeaderFooterEntry(aNotesMaster)); + else + (*m_pMasterPages)[ i ].xHeaderFooterEntry.reset(new HeaderFooterEntry(aNormalMaster)); + } + } + } + } + if ( ( rStCtrl.GetError() != ERRCODE_NONE ) || ( m_pDefaultSheet == nullptr ) ) + m_bOk = false; + m_pPPTStyleSheet = m_pDefaultSheet; + rStCtrl.Seek( 0 ); +} + +SdrPowerPointImport::~SdrPowerPointImport() +{ + m_pMasterPages.reset(); + m_pSlidePages.reset(); + m_pNotePages.reset(); +} + +bool PPTConvertOCXControls::ReadOCXStream( tools::SvRef& rSrc, + css::uno::Reference< css::drawing::XShape > *pShapeRef ) +{ + bool bRes = false; + uno::Reference< form::XFormComponent > xFComp; + if ( mpPPTImporter && mpPPTImporter->ReadFormControl( rSrc, xFComp ) ) + { + if ( xFComp.is() ) + { + css::awt::Size aSz; // not used in import + bRes = InsertControl( xFComp, aSz,pShapeRef, false/*bFloatingCtrl*/); + } + } + return bRes; +} + +bool PPTConvertOCXControls::InsertControl( + const css::uno::Reference< css::form::XFormComponent > &rFComp, + const css::awt::Size& rSize, + css::uno::Reference< css::drawing::XShape > *pShape, + bool /*bFloatingCtrl*/) +{ + bool bRetValue = false; + try + { + css::uno::Reference< css::drawing::XShape > xShape; + + const css::uno::Reference< css::container::XIndexContainer > & rFormComps = + GetFormComps(); + + css::uno::Any aTmp( &rFComp, cppu::UnoType::get() ); + + rFormComps->insertByIndex( rFormComps->getCount(), aTmp ); + + const css::uno::Reference< css::lang::XMultiServiceFactory > & rServiceFactory = + GetServiceFactory(); + if( rServiceFactory.is() ) + { + css::uno::Reference< css::uno::XInterface > xCreate = rServiceFactory + ->createInstance( "com.sun.star.drawing.ControlShape" ); + if( xCreate.is() ) + { + xShape.set(xCreate, css::uno::UNO_QUERY); + if ( xShape.is() ) + { + xShape->setSize(rSize); + // set the Control-Model at the Control-Shape + css::uno::Reference< css::drawing::XControlShape > xControlShape( xShape, + css::uno::UNO_QUERY ); + css::uno::Reference< css::awt::XControlModel > xControlModel( rFComp, + css::uno::UNO_QUERY ); + if ( xControlShape.is() && xControlModel.is() ) + { + xControlShape->setControl( xControlModel ); + if (pShape) + *pShape = xShape; + bRetValue = true; + } + } + } + } + } + catch( ... ) + { + bRetValue = false; + } + return bRetValue; +}; +void PPTConvertOCXControls::GetDrawPage() +{ + if( xDrawPage.is() || !mxModel.is() ) + return; + + css::uno::Reference< css::drawing::XDrawPages > xDrawPages; + switch( ePageKind ) + { + case PPT_SLIDEPAGE : + case PPT_NOTEPAGE : + { + css::uno::Reference< css::drawing::XDrawPagesSupplier > + xDrawPagesSupplier( mxModel, css::uno::UNO_QUERY); + if ( xDrawPagesSupplier.is() ) + xDrawPages = xDrawPagesSupplier->getDrawPages(); + } + break; + + case PPT_MASTERPAGE : + { + css::uno::Reference< css::drawing::XMasterPagesSupplier > + xMasterPagesSupplier( mxModel, css::uno::UNO_QUERY); + if ( xMasterPagesSupplier.is() ) + xDrawPages = xMasterPagesSupplier->getMasterPages(); + } + break; + } + if ( xDrawPages.is() && xDrawPages->getCount() ) + { + xDrawPages->getCount(); + css::uno::Any aAny( xDrawPages->getByIndex( xDrawPages->getCount() - 1 ) ); + aAny >>= xDrawPage; + } +} + +static bool SdrPowerPointOLEDecompress( SvStream& rOutput, SvStream& rInput, sal_uInt32 nInputSize ) +{ + sal_uInt32 nOldPos = rInput.Tell(); + std::unique_ptr pBuf(new char[ nInputSize ]); + rInput.ReadBytes(pBuf.get(), nInputSize); + ZCodec aZCodec( 0x8000, 0x8000 ); + aZCodec.BeginCompression(); + SvMemoryStream aSource( pBuf.get(), nInputSize, StreamMode::READ ); + aZCodec.Decompress( aSource, rOutput ); + const bool bSuccess(0 != aZCodec.EndCompression()); + rInput.Seek( nOldPos ); + return bSuccess; +} + +// #i32596# - add new parameter <_nCalledByGroup> +SdrObject* SdrPowerPointImport::ImportOLE( sal_uInt32 nOLEId, + const Graphic& rGraf, + const tools::Rectangle& rBoundRect, + const tools::Rectangle& rVisArea, + const int /*_nCalledByGroup*/ ) const +{ + SdrObject* pRet = nullptr; + + sal_uInt32 nOldPos = rStCtrl.Tell(); + + Graphic aGraphic( rGraf ); + + if ( const_cast(this)->maShapeRecords.SeekToContent( rStCtrl, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) ) + { + DffRecordHeader aPlaceHd; + + auto nEndRecPos = SanitizeEndPos(rStCtrl, const_cast(this)->maShapeRecords.Current()->GetRecEndFilePos()); + while ( ( rStCtrl.GetError() == ERRCODE_NONE ) + && ( rStCtrl.Tell() < nEndRecPos ) ) + { + ReadDffRecordHeader( rStCtrl, aPlaceHd ); + if ( aPlaceHd.nRecType == PPT_PST_RecolorInfoAtom ) + { + const_cast(this)->RecolorGraphic( rStCtrl, aPlaceHd.nRecLen, aGraphic ); + break; + } + else + { + if (!aPlaceHd.SeekToEndOfRecord(rStCtrl)) + break; + } + } + } + + for (PPTOleEntry& rOe : const_cast(this)->aOleObjectList) + { + if ( rOe.nId != nOLEId ) + continue; + + rStCtrl.Seek( rOe.nRecHdOfs ); + + DffRecordHeader aHd; + ReadDffRecordHeader( rStCtrl, aHd ); + + sal_uInt32 nLen = aHd.nRecLen - 4; + if ( static_cast(nLen) > 0 ) + { + bool bSuccess = false; + + rStCtrl.SeekRel( 4 ); + + ::utl::TempFile aTmpFile; + aTmpFile.EnableKillingFile(); + + if ( aTmpFile.IsValid() ) + { + SvStream* pDest = aTmpFile.GetStream(StreamMode::TRUNC | StreamMode::WRITE); + if (pDest) + { + bSuccess = SdrPowerPointOLEDecompress( *pDest, rStCtrl, nLen ); + } + aTmpFile.CloseStream(); + } + if ( bSuccess ) + { + SvStream* pDest = aTmpFile.GetStream(StreamMode::READ); + Storage* pObjStor = pDest ? new Storage( *pDest, true ) : nullptr; + if (pObjStor) + { + tools::SvRef xObjStor( new SotStorage( pObjStor ) ); + if ( xObjStor.is() && !xObjStor->GetError() ) + { + if ( xObjStor->GetClassName() == SvGlobalName() ) + { + xObjStor->SetClass( SvGlobalName( pObjStor->GetClassId() ), pObjStor->GetFormat(), pObjStor->GetUserName() ); + } + tools::SvRef xSrcTst = xObjStor->OpenSotStream( "\1Ole" ); + if ( xSrcTst.is() ) + { + sal_uInt8 aTestA[ 10 ]; + bool bGetItAsOle = (sizeof(aTestA) == xSrcTst->ReadBytes(aTestA, sizeof(aTestA))); + if ( !bGetItAsOle ) + { // maybe there is a contents stream in here + xSrcTst = xObjStor->OpenSotStream( "Contents", StreamMode::READWRITE | StreamMode::NOCREATE ); + bGetItAsOle = (xSrcTst.is() && + sizeof(aTestA) == xSrcTst->ReadBytes(aTestA, sizeof(aTestA))); + } + if ( bGetItAsOle ) + { + OUString aNm; + // if ( nSvxMSDffOLEConvFlags ) + { + uno::Reference < embed::XStorage > xDestStorage( rOe.pShell->GetStorage() ); + uno::Reference < embed::XEmbeddedObject > xObj = + CheckForConvertToSOObj(nSvxMSDffOLEConvFlags, *xObjStor, xDestStorage, rGraf, rVisArea, maBaseURL); + if( xObj.is() ) + { + rOe.pShell->getEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aNm ); + + svt::EmbeddedObjectRef aObj( xObj, rOe.nAspect ); + + // TODO/LATER: need MediaType for Graphic + aObj.SetGraphic( rGraf, OUString() ); + pRet = new SdrOle2Obj( + *pSdrModel, + aObj, + aNm, + rBoundRect); + } + } + if ( !pRet && ( rOe.nType == PPT_PST_ExControl ) ) + { + uno::Reference< frame::XModel > xModel( rOe.pShell->GetModel() ); + PPTConvertOCXControls aPPTConvertOCXControls( this, xModel, m_eCurrentPageKind ); + css::uno::Reference< css::drawing::XShape > xShape; + if ( aPPTConvertOCXControls.ReadOCXStream( xObjStor, &xShape ) ) + pRet = SdrObject::getSdrObjectFromXShape(xShape); + + } + if ( !pRet ) + { + aNm = rOe.pShell->getEmbeddedObjectContainer().CreateUniqueObjectName(); + + // object is not an own object + const css::uno::Reference < css::embed::XStorage >& rStorage = rOe.pShell->GetStorage(); + if (rStorage.is()) + { + tools::SvRef xTarget = SotStorage::OpenOLEStorage(rStorage, aNm, StreamMode::READWRITE); + if (xObjStor.is() && xTarget.is()) + { + xObjStor->CopyTo(xTarget.get()); + if (!xTarget->GetError()) + xTarget->Commit(); + } + xTarget.clear(); + } + + uno::Reference < embed::XEmbeddedObject > xObj = + rOe.pShell->getEmbeddedObjectContainer().GetEmbeddedObject( aNm ); + if ( xObj.is() ) + { + if ( rOe.nAspect != embed::Aspects::MSOLE_ICON ) + { + //TODO/LATER: keep on hacking?! + // we don't want to be modified + //xInplaceObj->EnableSetModified( sal_False ); + if ( rVisArea.IsEmpty() ) + { + MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( rOe.nAspect ) ); + Size aSize( OutputDevice::LogicToLogic( aGraphic.GetPrefSize(), + aGraphic.GetPrefMapMode(), MapMode( aMapUnit ) ) ); + + awt::Size aSz; + aSz.Width = aSize.Width(); + aSz.Height = aSize.Height(); + xObj->setVisualAreaSize( rOe.nAspect, aSz ); + } + else + { + awt::Size aSize( rVisArea.GetSize().Width(), rVisArea.GetSize().Height() ); + xObj->setVisualAreaSize( rOe.nAspect, aSize ); + } + //xInplaceObj->EnableSetModified( sal_True ); + } + + svt::EmbeddedObjectRef aObj( xObj, rOe.nAspect ); + + // TODO/LATER: need MediaType for Graphic + aObj.SetGraphic( aGraphic, OUString() ); + + pRet = new SdrOle2Obj( + *pSdrModel, + aObj, + aNm, + rBoundRect); + } + } + } + } + } + } + aTmpFile.CloseStream(); + } + } + } + rStCtrl.Seek( nOldPos ); + + return pRet; +} + +std::unique_ptr SdrPowerPointImport::ImportExOleObjStg( sal_uInt32 nPersistPtr, sal_uInt32& nOleId ) const +{ + std::unique_ptr pRet; + if ( nPersistPtr && ( nPersistPtr < m_nPersistPtrCnt ) ) + { + sal_uInt32 nOldPos, nOfs = m_pPersistPtr[ nPersistPtr ]; + nOldPos = rStCtrl.Tell(); + rStCtrl.Seek( nOfs ); + DffRecordHeader aHd; + ReadDffRecordHeader( rStCtrl, aHd ); + if ( aHd.nRecType == DFF_PST_ExOleObjStg ) + { + sal_uInt32 nLen = aHd.nRecLen - 4; + if ( static_cast(nLen) > 0 ) + { + rStCtrl.ReadUInt32( nOleId ); + pRet.reset(new SvMemoryStream); + ZCodec aZCodec( 0x8000, 0x8000 ); + aZCodec.BeginCompression(); + aZCodec.Decompress( rStCtrl, *pRet ); + if ( !aZCodec.EndCompression() ) + { + pRet.reset(); + } + } + } + rStCtrl.Seek( nOldPos ); + } + return pRet; +} + +void SdrPowerPointImport::SeekOle( SfxObjectShell* pShell, sal_uInt32 nFilterOptions ) +{ + if ( !pShell ) + return; + + DffRecordHeader* pHd; + + sal_uInt32 nOldPos = rStCtrl.Tell(); + if ( nFilterOptions & 1 ) + { + pHd = aDocRecManager.GetRecordHeader( PPT_PST_List ); + if ( pHd ) + { + // we try to locate the basic atom + pHd->SeekToContent( rStCtrl ); + if ( SeekToRec( rStCtrl, PPT_PST_VBAInfo, pHd->GetRecEndFilePos(), pHd ) ) + { + if ( SeekToRec( rStCtrl, PPT_PST_VBAInfoAtom, pHd->GetRecEndFilePos(), pHd ) ) + { + sal_uInt32 nPersistPtr, nIDoNotKnow1, nIDoNotKnow2; + rStCtrl.ReadUInt32( nPersistPtr ) + .ReadUInt32( nIDoNotKnow1 ) + .ReadUInt32( nIDoNotKnow2 ); + + sal_uInt32 nOleId; + std::unique_ptr pBas = ImportExOleObjStg( nPersistPtr, nOleId ); + if ( pBas ) + { + tools::SvRef xSource( new SotStorage( pBas.release(), true ) ); + tools::SvRef xDest( new SotStorage( new SvMemoryStream(), true ) ); + if ( xSource.is() && xDest.is() ) + { + // is this a visual basic storage ? + tools::SvRef xSubStorage = xSource->OpenSotStorage( "VBA", + StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL ); + if( xSubStorage.is() && ( ERRCODE_NONE == xSubStorage->GetError() ) ) + { + tools::SvRef xMacros = xDest->OpenSotStorage( "MACROS" ); + if ( xMacros.is() ) + { + SvStorageInfoList aList; + xSource->FillInfoList( &aList ); + SvStorageInfoList::size_type i; + + bool bCopied = true; + for ( i = 0; i < aList.size(); i++ ) // copy all entries + { + const SvStorageInfo& rInfo = aList[ i ]; + if ( !xSource->CopyTo( rInfo.GetName(), xMacros.get(), rInfo.GetName() ) ) + bCopied = false; + } + if ( i && bCopied ) + { + uno::Reference < embed::XStorage > xDoc( pShell->GetStorage() ); + if ( xDoc.is() ) + { + tools::SvRef xVBA = SotStorage::OpenOLEStorage( xDoc, SvxImportMSVBasic::GetMSBasicStorageName() ); + if ( xVBA.is() && ( xVBA->GetError() == ERRCODE_NONE ) ) + { + tools::SvRef xSubVBA = xVBA->OpenSotStorage( "_MS_VBA_Overhead" ); + if ( xSubVBA.is() && ( xSubVBA->GetError() == ERRCODE_NONE ) ) + { + tools::SvRef xOriginal = xSubVBA->OpenSotStream( "_MS_VBA_Overhead2" ); + if ( xOriginal.is() && ( xOriginal->GetError() == ERRCODE_NONE ) ) + { + if ( nPersistPtr && ( nPersistPtr < m_nPersistPtrCnt ) ) + { + rStCtrl.Seek( m_pPersistPtr[ nPersistPtr ] ); + ReadDffRecordHeader( rStCtrl, *pHd ); + + xOriginal->WriteUInt32( nIDoNotKnow1 ) + .WriteUInt32( nIDoNotKnow2 ); + + sal_uInt32 nToCopy, nBufSize; + nToCopy = pHd->nRecLen; + std::unique_ptr pBuf(new sal_uInt8[ 0x40000 ]); // 256KB Buffer + while ( nToCopy ) + { + nBufSize = ( nToCopy >= 0x40000 ) ? 0x40000 : nToCopy; + rStCtrl.ReadBytes(pBuf.get(), nBufSize); + xOriginal->WriteBytes(pBuf.get(), nBufSize); + nToCopy -= nBufSize; + } + } + } + } + } + xVBA->Commit(); + } + } + } + } + } + } + } + } + } + } + pHd = aDocRecManager.GetRecordHeader( PPT_PST_ExObjList ); + if ( pHd ) + { + DffRecordHeader* pExEmbed = nullptr; + + pHd->SeekToBegOfRecord( rStCtrl ); + DffRecordManager aExObjListManager( rStCtrl ); + sal_uInt16 i, nRecType(PPT_PST_ExEmbed); + + for ( i = 0; i < 2; i++ ) + { + switch ( i ) + { + case 0 : nRecType = PPT_PST_ExEmbed; break; + case 1 : nRecType = PPT_PST_ExControl; break; + } + for ( pExEmbed = aExObjListManager.GetRecordHeader( nRecType ); + pExEmbed; pExEmbed = aExObjListManager.GetRecordHeader( nRecType, SEEK_FROM_CURRENT ) ) + { + pExEmbed->SeekToContent( rStCtrl ); + + DffRecordHeader aExOleAtHd; + if ( SeekToRec( rStCtrl, PPT_PST_ExOleObjAtom, pExEmbed->GetRecEndFilePos(), &aExOleAtHd ) ) + { + PptExOleObjAtom aAt; + ReadPptExOleObjAtom( rStCtrl, aAt ); + + if ( aAt.nPersistPtr && ( aAt.nPersistPtr < m_nPersistPtrCnt ) ) + { + rStCtrl.Seek( m_pPersistPtr[ aAt.nPersistPtr ] ); + DffRecordHeader aHd; + ReadDffRecordHeader( rStCtrl, aHd ); + if ( aHd.nRecType == DFF_PST_ExOleObjStg ) + { + sal_uInt32 nId; + rStCtrl.ReadUInt32( nId ); + aOleObjectList.emplace_back( + aAt.nId, aHd.nFilePos, pShell, nRecType, aAt.nAspect ); + } + } + } + } + } + } + rStCtrl.Seek( nOldPos ); +} + +bool SdrPowerPointImport::ReadFontCollection() +{ + bool bRet = false; + DffRecordHeader* pEnvHd = aDocRecManager.GetRecordHeader( PPT_PST_Environment ); + if ( pEnvHd ) + { + sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it later + pEnvHd->SeekToContent( rStCtrl ); + DffRecordHeader aListHd; + if ( SeekToRec( rStCtrl, PPT_PST_FontCollection, pEnvHd->GetRecEndFilePos(), &aListHd ) ) + { + sal_uInt16 nCount2 = 0; + while ( SeekToRec( rStCtrl, PPT_PST_FontEntityAtom, aListHd.GetRecEndFilePos() ) ) + { + bRet = true; + if (!m_xFonts) + m_xFonts.emplace(); + PptFontEntityAtom aFontAtom; + ReadPptFontEntityAtom( rStCtrl, aFontAtom ); + + vcl::Font aFont; + aFont.SetCharSet( aFontAtom.eCharSet ); + aFont.SetFamilyName( aFontAtom.aName ); + aFont.SetFamily( aFontAtom.eFamily ); + aFont.SetPitch( aFontAtom.ePitch ); + aFont.SetFontHeight( 100 ); + + // following block is necessary, because our old PowerPoint export did not set the + // correct charset + if ( aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings 2" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings 3" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "Monotype Sorts" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "Monotype Sorts 2" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "Webdings" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "StarBats" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "StarMath" ) || + aFontAtom.aName.equalsIgnoreAsciiCase( "ZapfDingbats" ) ) + { + aFontAtom.eCharSet = RTL_TEXTENCODING_SYMBOL; + }; + m_xFonts->insert(m_xFonts->begin() + nCount2++, std::move(aFontAtom)); + } + } + rStCtrl.Seek( nOldFPos ); // restore FilePos + } + return bRet; +} + +PptSlidePersistList* SdrPowerPointImport::GetPageList(PptPageKind ePageKind) const +{ + switch (ePageKind) + { + case PPT_MASTERPAGE: + return m_pMasterPages.get(); + case PPT_SLIDEPAGE: + return m_pSlidePages.get(); + case PPT_NOTEPAGE: + return m_pNotePages.get(); + } + return nullptr; +} + +SdrOutliner* SdrPowerPointImport::GetDrawOutliner( SdrTextObj const * pSdrText ) +{ + if ( !pSdrText ) + return nullptr; + else + return &pSdrText->ImpGetDrawOutliner(); +} + + +SdrObject* SdrPowerPointImport::ReadObjText( PPTTextObj* pTextObj, SdrObject* pSdrObj, SdPageCapsule pPage ) const +{ + SdrTextObj* pText = dynamic_cast( pSdrObj ); + if ( pText ) + { + if ( !ApplyTextObj( pTextObj, pText, pPage, nullptr, nullptr ) ) + pSdrObj = nullptr; + } + return pSdrObj; +} + +SdrObject* SdrPowerPointImport::ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj* pSdrText, SdPageCapsule /*pPage*/, + SfxStyleSheet* pSheet, SfxStyleSheet** ppStyleSheetAry ) const +{ + SdrTextObj* pText = pSdrText; + if ( pTextObj->Count() ) + { + TSS_Type nDestinationInstance = pTextObj->GetDestinationInstance() ; + SdrOutliner& rOutliner = pText->ImpGetDrawOutliner(); + bool bUndoEnabled = rOutliner.IsUndoEnabled(); + rOutliner.EnableUndo(false); + + if ( ( pText->GetObjInventor() == SdrInventor::Default ) && ( pText->GetObjIdentifier() == SdrObjKind::TitleText ) ) // Outliner-Style for Title-Text object?!? (->of DL) + rOutliner.Init( OutlinerMode::TitleObject ); // Outliner reset + + bool bOldUpdateMode = rOutliner.SetUpdateLayout( false ); + if ( pSheet ) + { + if ( rOutliner.GetStyleSheet( 0 ) != pSheet ) + rOutliner.SetStyleSheet( 0, pSheet ); + } + rOutliner.SetVertical( pTextObj->GetVertical() ); + for ( PPTParagraphObj* pPara = pTextObj->First(); pPara; pPara = pTextObj->Next() ) + { + sal_uInt32 nTextSize = pPara->GetTextSize(); + if ( ! ( nTextSize & 0xffff0000 ) ) + { + PPTPortionObj* pPortion; + std::unique_ptr pParaText(new sal_Unicode[ nTextSize ]); + sal_Int32 nCurrentIndex = 0; + for ( pPortion = pPara->First(); pPortion; pPortion = pPara->Next() ) + { + if ( pPortion->mpFieldItem ) + pParaText[ nCurrentIndex++ ] = ' '; + else + { + sal_Int32 nCharacters = pPortion->Count(); + const sal_Unicode* pSource = pPortion->maString.getStr(); + sal_Unicode* pDest = pParaText.get() + nCurrentIndex; + + sal_uInt32 nFont; + pPortion->GetAttrib( PPT_CharAttr_Font, nFont, pTextObj->GetInstance() ); + const PptFontEntityAtom* pFontEnityAtom = GetFontEnityAtom( nFont ); + if ( pFontEnityAtom && ( pFontEnityAtom->eCharSet == RTL_TEXTENCODING_SYMBOL ) ) + { + sal_Unicode nUnicode; + for (sal_Int32 i = 0; i < nCharacters; i++ ) + { + nUnicode = pSource[ i ]; + if ( ! ( nUnicode & 0xff00 ) ) + nUnicode |= 0xf000; + pDest[ i ] = nUnicode; + } + } + else + memcpy( pDest, pSource, nCharacters << 1 ); + nCurrentIndex += nCharacters; + } + } + sal_Int32 nParaIndex = pTextObj->GetCurrentIndex(); + SfxStyleSheet* pS = ppStyleSheetAry ? ppStyleSheetAry[ pPara->mxParaSet->mnDepth ] : pSheet; + + ESelection aSelection( nParaIndex, 0, nParaIndex, 0 ); + rOutliner.Insert( OUString(), nParaIndex, pPara->mxParaSet->mnDepth ); + rOutliner.QuickInsertText( OUString(pParaText.get(), nCurrentIndex), aSelection ); + rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() ); + if ( pS ) + rOutliner.SetStyleSheet( nParaIndex, pS ); + + for ( pPortion = pPara->First(); pPortion; pPortion = pPara->Next() ) + { + SfxItemSet aPortionAttribs( rOutliner.GetEmptyItemSet() ); + std::unique_ptr pFieldItem(pPortion->GetTextField()); + if ( pFieldItem ) + { + rOutliner.QuickInsertField( *pFieldItem, ESelection( nParaIndex, aSelection.nEndPos, nParaIndex, aSelection.nEndPos + 1 ) ); + aSelection.nEndPos++; + } + else + { + const sal_Unicode *pF, *pPtr = pPortion->maString.getStr(); + const sal_Unicode *pMax = pPtr + pPortion->maString.getLength(); + sal_Int32 nLen; + for ( pF = pPtr; pPtr < pMax; pPtr++ ) + { + if ( *pPtr == 0xb ) + { + nLen = pPtr - pF; + if ( nLen ) + aSelection.nEndPos = + sal::static_int_cast< sal_uInt16 >( + aSelection.nEndPos + nLen ); + pF = pPtr + 1; + rOutliner.QuickInsertLineBreak( ESelection( nParaIndex, aSelection.nEndPos, nParaIndex, aSelection.nEndPos + 1 ) ); + aSelection.nEndPos++; + } + } + nLen = pPtr - pF; + if ( nLen ) + aSelection.nEndPos = sal::static_int_cast< sal_uInt16 >( + aSelection.nEndPos + nLen ); + } + pPortion->ApplyTo( aPortionAttribs, const_cast(*this), nDestinationInstance, pTextObj ); + rOutliner.QuickSetAttribs( aPortionAttribs, aSelection ); + aSelection.nStartPos = aSelection.nEndPos; + } + std::optional< sal_Int16 > oStartNumbering; + SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() ); + pPara->ApplyTo( aParagraphAttribs, oStartNumbering, *this, nDestinationInstance ); + + sal_uInt32 nIsBullet2 = 0; //, nInstance = nDestinationInstance != 0xffffffff ? nDestinationInstance : pTextObj->GetInstance(); + pPara->GetAttrib( PPT_ParaAttr_BulletOn, nIsBullet2, nDestinationInstance ); + if ( !nIsBullet2 ) + aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) ); + + if ( !aSelection.nStartPos ) // in PPT empty paragraphs never gets a bullet + { + aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) ); + } + aSelection.nStartPos = 0; + rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection ); + } + } + std::optional pNewText = rOutliner.CreateParaObject(); + rOutliner.Clear(); + rOutliner.SetUpdateLayout( bOldUpdateMode ); + rOutliner.EnableUndo(bUndoEnabled); + pText->SetOutlinerParaObject( std::move(pNewText) ); + } + return pText; +} + +bool SdrPowerPointImport::SeekToDocument( DffRecordHeader* pRecHd ) const +{ + bool bRet; + sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it, if the situation should happen + rStCtrl.Seek( m_nDocStreamPos ); + DffRecordHeader aDocHd; + ReadDffRecordHeader( rStCtrl, aDocHd ); + bRet = aDocHd.nRecType == PPT_PST_Document; + if ( bRet ) + { + if ( pRecHd ) + *pRecHd = aDocHd; + else + aDocHd.SeekToBegOfRecord( rStCtrl ); + } + if ( !bRet ) + rStCtrl.Seek( nOldFPos ); // restore FilePos + return bRet; +} + +bool SdrPowerPointImport::SeekToContentOfProgTag( sal_Int32 nVersion, SvStream& rSt, + const DffRecordHeader& rSourceHd, DffRecordHeader& rContentHd ) +{ + bool bRetValue = false; + sal_uInt32 nOldPos = rSt.Tell(); + + DffRecordHeader aProgTagsHd, aProgTagBinaryDataHd; + rSourceHd.SeekToContent( rSt ); + bool bFound = rSourceHd.nRecType == PPT_PST_ProgTags; + if ( !bFound ) + bFound = SeekToRec( rSt, PPT_PST_ProgTags, rSourceHd.GetRecEndFilePos(), &aProgTagsHd ); + if ( bFound ) + { + while( SeekToRec( rSt, PPT_PST_ProgBinaryTag, aProgTagsHd.GetRecEndFilePos(), &aProgTagBinaryDataHd ) ) + { + ReadDffRecordHeader( rSt, rContentHd ); + if ( rContentHd.nRecType == PPT_PST_CString ) + { + sal_uInt16 n = 6; + sal_uInt32 i = rContentHd.nRecLen >> 1; + if ( i > n ) + { + OUString aPre = read_uInt16s_ToOUString(rSt, n); + n = static_cast( i - 6 ); + OUString aSuf = read_uInt16s_ToOUString(rSt, n); + sal_Int32 nV = aSuf.toInt32(); + if ( ( nV == nVersion ) && ( aPre == "___PPT" ) ) + { + if (!rContentHd.SeekToEndOfRecord(rSt)) + { + break; + } + ReadDffRecordHeader( rSt, rContentHd ); + if ( rContentHd.nRecType == PPT_PST_BinaryTagData ) + { + bRetValue = true; + break; + } + } + } + } + if (!aProgTagBinaryDataHd.SeekToEndOfRecord(rSt)) + break; + } + } + if ( !bRetValue ) + rSt.Seek( nOldPos ); + return bRetValue; +} + +sal_uInt32 SdrPowerPointImport::GetCurrentPageId() +{ + PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind ); + if ( pList && m_nCurrentPageNum < pList->size() ) + return (*pList)[ m_nCurrentPageNum ].aPersistAtom.nSlideId; + return 0; +} + +bool SdrPowerPointImport::SeekToCurrentPage( DffRecordHeader* pRecHd ) const +{ + bool bRet = false; + PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind ); + if ( pList && ( m_nCurrentPageNum < pList->size() ) ) + { + sal_uLong nPersist = (*pList)[ m_nCurrentPageNum ].aPersistAtom.nPsrReference; + if ( nPersist > 0 && nPersist < m_nPersistPtrCnt ) + { + sal_uLong nFPos = m_pPersistPtr[ nPersist ]; + if ( nFPos < nStreamLen ) + { + rStCtrl.Seek( nFPos ); + if ( pRecHd ) + ReadDffRecordHeader( rStCtrl, *pRecHd ); + bRet = true; + } + } + } + return bRet; +} + +sal_uInt16 SdrPowerPointImport::GetPageCount( PptPageKind ePageKind ) const +{ + PptSlidePersistList* pList = GetPageList( ePageKind ); + if ( pList ) + return pList->size(); + return 0; +} + +void SdrPowerPointImport::SetPageNum( sal_uInt16 nPageNum, PptPageKind eKind ) +{ + m_eCurrentPageKind = eKind; + m_nCurrentPageNum = nPageNum; + + m_pPPTStyleSheet = nullptr; + + bool bHasMasterPage = true; + sal_uInt16 nMasterIndex = 0; + + if ( eKind == PPT_MASTERPAGE ) + nMasterIndex = nPageNum; + else + { + if ( HasMasterPage( nPageNum, eKind ) ) + nMasterIndex = GetMasterPageIndex( nPageNum, eKind ); + else + bHasMasterPage = false; + } + if ( bHasMasterPage ) + { + PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE ); + if ( pPageList && nMasterIndex < pPageList->size() ) + { + PptSlidePersistEntry* pMasterPersist = &(*pPageList)[ nMasterIndex ]; + if (!pMasterPersist->xStyleSheet && pMasterPersist->aSlideAtom.nMasterId) + { + nMasterIndex = m_pMasterPages->FindPage( pMasterPersist->aSlideAtom.nMasterId ); + if ( nMasterIndex != PPTSLIDEPERSIST_ENTRY_NOTFOUND ) + pMasterPersist = &(*pPageList)[ nMasterIndex ]; + } + m_pPPTStyleSheet = pMasterPersist->xStyleSheet.get(); + } + } + if ( !m_pPPTStyleSheet ) + m_pPPTStyleSheet = m_pDefaultSheet; +} + +Size SdrPowerPointImport::GetPageSize() const +{ + Size aRet( IsNoteOrHandout( m_nCurrentPageNum ) ? aDocAtom.GetNotesPageSize() : aDocAtom.GetSlidesPageSize() ); + Scale( aRet ); + // PPT works with units of 576 dpi in any case. To avoid inaccuracies + // I do round the last decimal digit away. + if ( nMapMul > 2 * nMapDiv ) + { + MapUnit eMap = pSdrModel->GetScaleUnit(); + bool bInch = IsInch( eMap ); + tools::Long nInchMul = 1, nInchDiv = 1; + if ( bInch ) + { // temporarily convert size (for rounding it) from inch to metric units + Fraction aFact(GetMapFactor(eMap,MapUnit::Map100thMM).X()); + nInchMul = aFact.GetNumerator(); + nInchDiv = aFact.GetDenominator(); + aRet.setWidth( BigMulDiv( aRet.Width(), nInchMul, nInchDiv ) ); + aRet.setHeight( BigMulDiv( aRet.Height(), nInchMul, nInchDiv ) ); + } + aRet.AdjustWidth(5 ); aRet.setWidth( aRet.Width() / 10 ); aRet.setWidth( aRet.Width() * 10 ); + aRet.AdjustHeight(5 ); aRet.setHeight( aRet.Height() / 10 ); aRet.setHeight( aRet.Height() * 10 ); + if ( bInch ) + { + aRet.setWidth( BigMulDiv( aRet.Width(), nInchDiv, nInchMul ) ); + aRet.setHeight( BigMulDiv( aRet.Height(), nInchDiv, nInchMul ) ); + } + } + return aRet; +} + +bool SdrPowerPointImport::GetColorFromPalette( sal_uInt16 nNum, Color& rColor ) const +{ + if ( m_nPageColorsNum != m_nCurrentPageNum || m_ePageColorsKind != m_eCurrentPageKind ) + { + sal_uInt16 nSlideFlags = 0; + PptSlidePersistList* pPageList = GetPageList( m_eCurrentPageKind ); + if ( pPageList && ( m_nCurrentPageNum < pPageList->size() ) ) + { + assert( !pPageList->is_null( m_nCurrentPageNum ) ); + const PptSlidePersistEntry& rE = (*pPageList)[ m_nCurrentPageNum ]; + nSlideFlags = rE.aSlideAtom.nFlags; + if ( ! ( nSlideFlags & 2 ) ) + const_cast(this)->m_aPageColors = rE.aColorScheme; + } + if ( nSlideFlags & 2 ) // follow master colorscheme? + { + PptSlidePersistList* pPageList2 = GetPageList( PPT_MASTERPAGE ); + if ( pPageList2 ) + { + PptSlidePersistEntry* pMasterPersist = nullptr; + if ( m_eCurrentPageKind == PPT_MASTERPAGE ) + pMasterPersist = &(*pPageList2)[ m_nCurrentPageNum ]; + else + { + if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) ) + { + sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind ); + if ( nMasterNum < pPageList2->size() ) + pMasterPersist = &(*pPageList2)[ nMasterNum ]; + } + } + if ( pMasterPersist ) + { + while( (pMasterPersist->aSlideAtom.nFlags & 2) // it is possible that a masterpage + && pMasterPersist->aSlideAtom.nMasterId ) // itself is following a master colorscheme + { + auto nOrigMasterId = pMasterPersist->aSlideAtom.nMasterId; + sal_uInt16 nNextMaster = m_pMasterPages->FindPage(nOrigMasterId); + if (nNextMaster == PPTSLIDEPERSIST_ENTRY_NOTFOUND) + break; + pMasterPersist = &(*pPageList2)[ nNextMaster ]; + if (pMasterPersist->aSlideAtom.nMasterId == nOrigMasterId) + { + SAL_WARN("filter.ms", "loop in atom chain"); + break; + } + } + const_cast(this)->m_aPageColors = pMasterPersist->aColorScheme; + } + } + } + // register current color scheme + const_cast(this)->m_nPageColorsNum = m_nCurrentPageNum; + const_cast(this)->m_ePageColorsKind = m_eCurrentPageKind; + } + rColor = m_aPageColors.GetColor( nNum ); + return true; +} + +bool SdrPowerPointImport::SeekToShape( SvStream& rSt, SvxMSDffClientData* pClientData, sal_uInt32 nId ) const +{ + bool bRet = SvxMSDffManager::SeekToShape( rSt, pClientData, nId ); + if (!bRet && pClientData) + { + ProcessData& rData = *static_cast(pClientData); + PptSlidePersistEntry& rPersistEntry = rData.rPersistEntry; + if ( rPersistEntry.ePageKind == PPT_SLIDEPAGE ) + { + if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) ) + { + sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind ); + PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE ); + if ( pPageList && ( nMasterNum < pPageList->size() ) ) + { + assert( !pPageList->is_null( nMasterNum ) ); + const PptSlidePersistEntry& rPersist = (*pPageList)[ nMasterNum ]; // get the masterpage's persistentry + if ( rPersist.pPresentationObjects ) + { + sal_uInt32 nCurrent(0); + DffRecordList* pCList = maShapeRecords.pCList; // we got a backup of the current position + if ( pCList ) + nCurrent = pCList->nCurrent; + if ( const_cast(this)->maShapeRecords.SeekToContent( rSt, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) ) + { + sal_uInt32 nStreamPos = rSt.Tell(); + PPTTextObj aTextObj( rSt, const_cast(*this), rPersistEntry, nullptr ); + if ( aTextObj.Count() || aTextObj.GetOEPlaceHolderAtom() ) + { + sal_uInt32 nShapePos = 0; + switch ( aTextObj.GetInstance() ) + { + case TSS_Type::Title : + nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::PageTitle) ]; + break; + case TSS_Type::PageTitle : + nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::PageTitle) ]; + break; + case TSS_Type::Subtitle : + case TSS_Type::HalfBody : + case TSS_Type::QuarterBody : + case TSS_Type::Body : + nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::Body) ]; + break; + default: break; + } + if ( nShapePos ) + { + rSt.Seek( nShapePos ); + bRet = true; + } + } + if ( !bRet ) + rSt.Seek( nStreamPos ); + } + if ( pCList ) // restoring + pCList->nCurrent = nCurrent; + const_cast(this)->maShapeRecords.pCList = pCList; + } + } + } + } + } + return bRet; +} + +rtl::Reference SdrPowerPointImport::MakeBlankPage( bool bMaster ) const +{ + rtl::Reference pRet = pSdrModel->AllocPage( bMaster ); + pRet->SetSize( GetPageSize() ); + + return pRet; +} + +static void ImportComment10( SvxMSDffManager const & rMan, SvStream& rStCtrl, SdrPage* pPage, DffRecordHeader const & rComment10Hd ) +{ + OUString sAuthor; + OUString sText; + OUString sInitials; + + sal_Int32 nIndex = 0; + util::DateTime aDateTime; + sal_Int32 nPosX = 0; + sal_Int32 nPosY = 0; + + + auto nEndRecPos = DffPropSet::SanitizeEndPos(rStCtrl, rComment10Hd.GetRecEndFilePos()); + while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) ) + { + DffRecordHeader aCommentHd; + ReadDffRecordHeader( rStCtrl, aCommentHd ); + switch( aCommentHd.nRecType ) + { + case PPT_PST_CString : + { + OUString aString = SvxMSDffManager::MSDFFReadZString( rStCtrl, + aCommentHd.nRecLen, true ); + switch ( aCommentHd.nRecInstance ) + { + case 0 : sAuthor = aString; break; + case 1 : sText = aString; break; + case 2 : sInitials = aString; break; + } + } + break; + + case PPT_PST_CommentAtom10 : + { + sal_uInt16 millisec = 0; + rStCtrl.ReadInt32( nIndex ) + .ReadInt16( aDateTime.Year ) + .ReadUInt16( aDateTime.Month ) + .ReadUInt16( aDateTime.Day ) // DayOfWeek + .ReadUInt16( aDateTime.Day ) + .ReadUInt16( aDateTime.Hours ) + .ReadUInt16( aDateTime.Minutes ) + .ReadUInt16( aDateTime.Seconds ) + .ReadUInt16( millisec ) + .ReadInt32( nPosX ) + .ReadInt32( nPosY ); + + aDateTime.NanoSeconds = millisec * ::tools::Time::nanoPerMilli; + } + break; + } + if (!aCommentHd.SeekToEndOfRecord(rStCtrl)) + break; + } + Point aPosition( nPosX, nPosY ); + rMan.Scale( aPosition ); + + try + { + uno::Reference< office::XAnnotationAccess > xAnnotationAccess( pPage->getUnoPage(), UNO_QUERY_THROW ); + uno::Reference< office::XAnnotation > xAnnotation( xAnnotationAccess->createAndInsertAnnotation() ); + xAnnotation->setPosition( geometry::RealPoint2D( aPosition.X() / 100.0, aPosition.Y() / 100.0 ) ); + xAnnotation->setAuthor( sAuthor ); + xAnnotation->setDateTime( aDateTime ); + xAnnotation->setInitials( sInitials ); + uno::Reference< text::XText > xText( xAnnotation->getTextRange() ); + xText->setString( sText ); + } + catch( const uno::Exception& ) + { + + } +} + + +// be sure not to import masterpages with this method +void SdrPowerPointImport::ImportPage( SdrPage* pRet, const PptSlidePersistEntry* pMasterPersist ) +{ + sal_uInt32 nOldPos = rStCtrl.Tell(); + PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind ); + if ( ( !pList ) || ( pList->size() <= m_nCurrentPageNum ) ) + return; + PptSlidePersistEntry& rSlidePersist = (*pList)[ m_nCurrentPageNum ]; + if ( rSlidePersist.bStarDrawFiller ) + return; + + DffRecordHeader aPageHd; + if ( SeekToCurrentPage( &aPageHd ) ) + { + rSlidePersist.xHeaderFooterEntry.reset(new HeaderFooterEntry(pMasterPersist)); + ProcessData aProcessData( rSlidePersist, SdPageCapsule(pRet) ); + auto nEndRecPos = SanitizeEndPos(rStCtrl, aPageHd.GetRecEndFilePos()); + while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) ) + { + DffRecordHeader aHd; + ReadDffRecordHeader( rStCtrl, aHd ); + switch ( aHd.nRecType ) + { + case PPT_PST_HeadersFooters : + { + ImportHeaderFooterContainer(aHd, *rSlidePersist.xHeaderFooterEntry); + } + break; + + case PPT_PST_ProgTags : + { + DffRecordHeader aContentDataHd; + if ( SeekToContentOfProgTag( 10, rStCtrl, aHd, aContentDataHd ) ) + { + DffRecordHeader aComment10Hd; + while( ( rStCtrl.GetError() == ERRCODE_NONE ) && SeekToRec( rStCtrl, PPT_PST_Comment10, aContentDataHd.GetRecEndFilePos(), &aComment10Hd ) ) + { + ImportComment10( *this, rStCtrl, pRet, aComment10Hd ); + if (!aComment10Hd.SeekToEndOfRecord(rStCtrl)) + break; + } + } + } + break; + + case PPT_PST_PPDrawing : + { + DffRecordHeader aPPDrawHd; + if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, aHd.GetRecEndFilePos(), &aPPDrawHd ) ) + { + sal_uInt32 nPPDrawOfs = rStCtrl.Tell(); + + // importing the background object before importing the page + auto nPPEndRecPos = SanitizeEndPos(rStCtrl, aPPDrawHd.GetRecEndFilePos()); + while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nPPEndRecPos ) ) + { + DffRecordHeader aEscherObjListHd; + ReadDffRecordHeader( rStCtrl, aEscherObjListHd ); + switch ( aEscherObjListHd.nRecType ) + { + case DFF_msofbtSpContainer : + { + tools::Rectangle aPageSize( Point(), pRet->GetSize() ); + if ( rSlidePersist.aSlideAtom.nFlags & 4 ) // follow master background? + { + if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) ) + { + sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind ); + PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE ); + PptSlidePersistEntry* pE = &(*pPageList)[ nMasterNum ]; + while( ( pE->aSlideAtom.nFlags & 4 ) && pE->aSlideAtom.nMasterId ) + { + auto nOrigMasterId = pE->aSlideAtom.nMasterId; + sal_uInt16 nNextMaster = m_pMasterPages->FindPage(nOrigMasterId); + if ( nNextMaster == PPTSLIDEPERSIST_ENTRY_NOTFOUND ) + break; + else + pE = &(*pPageList)[ nNextMaster ]; + if (pE->aSlideAtom.nMasterId == nOrigMasterId) + { + SAL_WARN("filter.ms", "loop in atom chain"); + break; + } + } + if ( pE->nBackgroundOffset ) + { + // do not follow master colorscheme? + sal_uInt32 nPos = rStCtrl.Tell(); + rStCtrl.Seek( pE->nBackgroundOffset ); + rSlidePersist.pBObj = ImportObj( rStCtrl, aProcessData, aPageSize, aPageSize, /*nCalledByGroup*/0, /*pShapeId*/nullptr ); + rStCtrl.Seek( nPos ); + } + } + } + else + { + DffRecordHeader aShapeHd; + ReadDffRecordHeader( rStCtrl, aShapeHd ); + if ( aShapeHd.nRecType == DFF_msofbtSp ) + { + sal_uInt32 nSpFlags; + rStCtrl.ReadUInt32( nSpFlags ).ReadUInt32( nSpFlags ); + if (rStCtrl.good() && ShapeFlag(nSpFlags) & ShapeFlag::Background) + { + aEscherObjListHd.SeekToBegOfRecord( rStCtrl ); + rSlidePersist.pBObj = ImportObj( rStCtrl, aProcessData, aPageSize, aPageSize, /*nCalledByGroup*/0, /*pShapeId*/nullptr ); + } + } + } + } + break; + } + if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer ) + break; + if (!aEscherObjListHd.SeekToEndOfRecord(rStCtrl)) + break; + } + + // now importing page + rStCtrl.Seek( nPPDrawOfs ); + auto nHdEndRecPos = SanitizeEndPos(rStCtrl, aPPDrawHd.GetRecEndFilePos()); + while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nHdEndRecPos ) ) + { + DffRecordHeader aEscherObjListHd; + ReadDffRecordHeader( rStCtrl, aEscherObjListHd ); + switch ( aEscherObjListHd.nRecType ) + { + case DFF_msofbtSpgrContainer : + { + DffRecordHeader aShapeHd; + if ( SeekToRec( rStCtrl, DFF_msofbtSpContainer, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) ) + { + if (!aShapeHd.SeekToEndOfRecord(rStCtrl)) + { + break; + } + auto nListEndRecPos = SanitizeEndPos(rStCtrl, aEscherObjListHd.GetRecEndFilePos()); + while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nListEndRecPos ) ) + { + ReadDffRecordHeader( rStCtrl, aShapeHd ); + if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) || ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) ) + { + tools::Rectangle aEmpty; + aShapeHd.SeekToBegOfRecord( rStCtrl ); + sal_Int32 nShapeId; + aProcessData.pTableRowProperties.reset(); + SdrObject* pObj = ImportObj( rStCtrl, aProcessData, aEmpty, aEmpty, 0, &nShapeId ); + if ( pObj ) + { + if ( aProcessData.pTableRowProperties ) + pObj = CreateTable(pObj, aProcessData.pTableRowProperties.get(), aProcessData.rPersistEntry.xSolverContainer.get(), aProcessData.aBackgroundColoredObjects); + + pRet->NbcInsertObject( pObj ); + + if( nShapeId ) + insertShapeId( nShapeId, pObj ); + } + } + bool bSuccess = aShapeHd.SeekToEndOfRecord(rStCtrl); + if (!bSuccess) + break; + } + } + } + break; + } + if ( aEscherObjListHd.nRecType == DFF_msofbtSpgrContainer ) + break; + if (!aEscherObjListHd.SeekToEndOfRecord(rStCtrl)) + break; + } + + // Handle shapes where the fill matches the background + // fill (mso_fillBackground). + if (rSlidePersist.ePageKind == PPT_SLIDEPAGE) + { + if (!aProcessData.aBackgroundColoredObjects.empty()) + { + if (!rSlidePersist.pBObj) + { + for (auto pObject : aProcessData.aBackgroundColoredObjects) + { + // The shape wants a background, but the slide doesn't have + // one: default to white. + SfxItemSet aNewSet(*pObject->GetMergedItemSet().GetPool()); + aNewSet.Put(XFillStyleItem(css::drawing::FillStyle_SOLID)); + aNewSet.Put(XFillColorItem(OUString(), COL_WHITE)); + pObject->SetMergedItemSet(aNewSet); + } + } + } + } + + if ( rSlidePersist.pBObj ) + { + // #i99386# transfer the attributes from the temporary BackgroundObject + // to the Page and delete it. + pRet->getSdrPageProperties().ClearItem(); + pRet->getSdrPageProperties().PutItemSet(rSlidePersist.pBObj->GetMergedItemSet()); + if (rSlidePersist.xSolverContainer) + { + for (auto & pPtr : rSlidePersist.xSolverContainer->aCList) + { + // check connections to the group object + if (pPtr->pAObj == rSlidePersist.pBObj) + pPtr->pAObj = nullptr; + if (pPtr->pBObj == rSlidePersist.pBObj) + pPtr->pBObj = nullptr; + if (pPtr->pCObj == rSlidePersist.pBObj) + pPtr->pCObj = nullptr; + } + } + SdrObject::Free(rSlidePersist.pBObj); + } + } + } + break; + } + if (!aHd.SeekToEndOfRecord(rStCtrl)) + break; + } + if (rSlidePersist.xSolverContainer) + SolveSolver(*rSlidePersist.xSolverContainer); + } + rStCtrl.Seek( nOldPos ); +} + +const PptSlideLayoutAtom* SdrPowerPointImport::GetSlideLayoutAtom() const +{ + PptSlidePersistList* pPageList = GetPageList( m_eCurrentPageKind ); + if ( pPageList && m_nCurrentPageNum < pPageList->size() ) + { + assert( !pPageList->is_null( m_nCurrentPageNum ) ); + return &(*pPageList)[ m_nCurrentPageNum ].aSlideAtom.aLayout; + } + return nullptr; +} + +bool SdrPowerPointImport::IsNoteOrHandout( sal_uInt16 nPageNum ) const +{ + bool bNote = m_eCurrentPageKind == PPT_NOTEPAGE; + if ( m_eCurrentPageKind == PPT_MASTERPAGE ) + bNote = ( nPageNum & 1 ) == 0; + return bNote; +} + +sal_uInt32 SdrPowerPointImport::GetMasterPageId( sal_uInt16 nPageNum, PptPageKind ePageKind ) const +{ + PptSlidePersistList* pPageList = GetPageList( ePageKind ); + if ( pPageList && nPageNum < pPageList->size() ) + return (*pPageList)[ nPageNum ].aSlideAtom.nMasterId; + return 0; +} + +sal_uInt32 SdrPowerPointImport::GetNotesPageId( sal_uInt16 nPageNum ) const +{ + PptSlidePersistList* pPageList=GetPageList( PPT_SLIDEPAGE ); + if ( pPageList && nPageNum < pPageList->size() ) + return (*pPageList)[ nPageNum ].aSlideAtom.nNotesId; + return 0; +} + +bool SdrPowerPointImport::HasMasterPage( sal_uInt16 nPageNum, PptPageKind ePageKind ) const +{ + if ( ePageKind == PPT_NOTEPAGE ) + return aDocAtom.nNotesMasterPersist != 0; + if ( ePageKind == PPT_MASTERPAGE ) + return false; + return GetMasterPageId( nPageNum, ePageKind ) != 0; +} + +sal_uInt16 SdrPowerPointImport::GetMasterPageIndex( sal_uInt16 nPageNum, PptPageKind ePageKind ) const +{ + sal_uInt16 nIdx = 0; + if ( ePageKind == PPT_NOTEPAGE ) + return 2; + sal_uInt32 nId = GetMasterPageId( nPageNum, ePageKind ); + if (nId && m_pMasterPages) + { + nIdx = m_pMasterPages->FindPage( nId ); + if ( nIdx == PPTSLIDEPERSIST_ENTRY_NOTFOUND ) + nIdx = 0; + } + return nIdx; +} + +SdrObject* SdrPowerPointImport::ImportPageBackgroundObject( const SdrPage& rPage, sal_uInt32& nBgFileOffset ) +{ + SdrObject* pRet = nullptr; + std::optional pSet; + sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it later + DffRecordHeader aPageHd; + if ( SeekToCurrentPage( &aPageHd ) ) + { // and now search for the background attributes of the Page + sal_uLong nPageRecEnd = aPageHd.GetRecEndFilePos(); + DffRecordHeader aPPDrawHd; + if ( SeekToRec( rStCtrl, PPT_PST_PPDrawing, nPageRecEnd, &aPPDrawHd ) ) + { + sal_uLong nPPDrawEnd = aPPDrawHd.GetRecEndFilePos(); + DffRecordHeader aEscherF002Hd; + if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, nPPDrawEnd, &aEscherF002Hd ) ) + { + sal_uLong nEscherF002End = aEscherF002Hd.GetRecEndFilePos(); + DffRecordHeader aEscherObjectHd; + if ( SeekToRec( rStCtrl, DFF_msofbtSpContainer, nEscherF002End, &aEscherObjectHd ) ) + { + nBgFileOffset = aEscherObjectHd.GetRecBegFilePos(); + //sal_uLong nEscherObjectEnd = aEscherObjectHd.GetRecEndFilePos(); + //DffRecordHeader aEscherPropertiesHd; + if ( SeekToRec( rStCtrl, DFF_msofbtOPT,nEscherF002End ) ) + { + ReadDffPropSet( rStCtrl, static_cast(*this) ); + mnFix16Angle = Fix16ToAngle( GetPropertyValue( DFF_Prop_Rotation, 0 ) ); + sal_uInt32 nColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); + pSet.emplace( pSdrModel->GetItemPool() ); + DffObjData aObjData( aEscherObjectHd, tools::Rectangle( 0, 0, 28000, 21000 ), 0 ); + ApplyAttributes( rStCtrl, *pSet, aObjData ); + Color aColor( MSO_CLR_ToColor( nColor ) ); + pSet->Put( XFillColorItem( OUString(), aColor ) ); + } + } + } + } + } + rStCtrl.Seek( nOldFPos ); // restore FilePos + if ( !pSet ) + { + pSet.emplace( pSdrModel->GetItemPool() ); + pSet->Put( XFillStyleItem( drawing::FillStyle_NONE ) ); + } + pSet->Put( XLineStyleItem( drawing::LineStyle_NONE ) ); + tools::Rectangle aRect( + rPage.GetLeftBorder(), + rPage.GetUpperBorder(), + rPage.GetWidth() - rPage.GetRightBorder(), + rPage.GetHeight() - rPage.GetLowerBorder()); + + pRet = new SdrRectObj( + *pSdrModel, + aRect); + + pRet->SetMergedItemSet(*pSet); + pRet->SetMarkProtect( true ); + pRet->SetMoveProtect( true ); + pRet->SetResizeProtect( true ); + return pRet; +} + +HeaderFooterEntry::HeaderFooterEntry( const PptSlidePersistEntry* pMPE ) : + pMasterPersist ( pMPE ), + nAtom ( 0 ) +{ + if ( pMPE ) + { + HeaderFooterEntry* pMHFE = pMPE->xHeaderFooterEntry.get(); + if ( pMHFE ) + { + nAtom = pMPE->xHeaderFooterEntry->nAtom; + pPlaceholder[ 0 ] = pMHFE->pPlaceholder[ 0 ]; + pPlaceholder[ 1 ] = pMHFE->pPlaceholder[ 1 ]; + pPlaceholder[ 2 ] = pMHFE->pPlaceholder[ 2 ]; + pPlaceholder[ 3 ] = pMHFE->pPlaceholder[ 3 ]; + } + } +} + +sal_uInt32 HeaderFooterEntry::IsToDisplay( sal_uInt32 nInstance ) +{ + sal_uInt32 nMask = 0; + switch ( nInstance ) + { + case 0 : nMask = 0x010000; break; + case 1 : nMask = 0x100000; break; + case 2 : nMask = 0x200000; break; + case 3 : nMask = 0x080000; break; + } + return ( nAtom & nMask ); +} + +// The following method checks if the slide is using a different colorscheme than +// its master, if this is the fact, then the HeaderFooter must probably be +// imported as real sdrobject. In this case, the return value is the offset to the +// master header footer object, so it can be re-loaded with a different color set +sal_uInt32 HeaderFooterEntry::NeedToImportInstance( const sal_uInt32 nInstance, const PptSlidePersistEntry& rSlidePersist ) +{ + sal_uInt32 nRet = 0; + if ( pMasterPersist ) + { + if ( !( rSlidePersist.aSlideAtom.nFlags & 2 ) ) + { // not following the master persist, so we have to check if the colors are changed + if ( memcmp( &rSlidePersist.aColorScheme, &pMasterPersist->aColorScheme, 32 ) ) + { + nRet = pMasterPersist->HeaderFooterOfs[ nInstance ]; + } + } + } + return nRet; +} + +void SdrEscherImport::ImportHeaderFooterContainer( DffRecordHeader const & rHd, HeaderFooterEntry& rE ) +{ + rHd.SeekToContent( rStCtrl ); + auto nEndRecPos = SanitizeEndPos(rStCtrl, rHd.GetRecEndFilePos()); + while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) ) + { + DffRecordHeader aHd; + ReadDffRecordHeader( rStCtrl, aHd ); + switch ( aHd.nRecType ) + { + case PPT_PST_HeadersFootersAtom : + rStCtrl.ReadUInt32( rE.nAtom ); + break; + + case PPT_PST_CString : + { + if ( aHd.nRecInstance < 4 ) + { + rE.pPlaceholder[ aHd.nRecInstance ] = MSDFFReadZString( rStCtrl, + aHd.nRecLen, true ); + } + } + break; + } + if (!aHd.SeekToEndOfRecord(rStCtrl)) + break; + } +} + +PPTBuGraEntry::PPTBuGraEntry( Graphic aGraphic, sal_uInt32 nInst ) : + nInstance ( nInst ), + aBuGra (std::move( aGraphic )) {} + +PPTExtParaLevel::PPTExtParaLevel() +: mnExtParagraphMask( 0 ) +, mnBuBlip( 0xffff ) +, mnHasAnm( 0 ) +, mnAnmScheme( 0 ) +, mpfPP10Ext( 0 ) +, mnExtCharacterMask( 0 ) +, mcfPP10Ext( 0 ) +, mbSet( false ) +{} + +SvStream& ReadPPTExtParaLevel( SvStream& rIn, PPTExtParaLevel& rLevel ) +{ + rLevel.mbSet = true; + rIn.ReadUInt32( rLevel.mnExtParagraphMask ); + if ( rLevel.mnExtParagraphMask & 0x00800000 ) + rIn.ReadUInt16( rLevel.mnBuBlip ); + if ( rLevel.mnExtParagraphMask & 0x02000000 ) + rIn.ReadUInt16( rLevel.mnHasAnm ); + if ( rLevel.mnExtParagraphMask & 0x01000000 ) + rIn.ReadUInt32( rLevel.mnAnmScheme ); + if ( rLevel.mnExtParagraphMask & 0x04000000 ) + rIn.ReadUInt32( rLevel.mpfPP10Ext ); + rIn.ReadUInt32( rLevel.mnExtCharacterMask ); + if ( rLevel.mnExtCharacterMask & 0x100000 ) + rIn.ReadUInt32( rLevel.mcfPP10Ext ); + return rIn; +} + +bool PPTExtParaProv::GetGraphic( sal_uInt32 nInstance, Graphic& rGraph ) const +{ + bool bRetValue = false; + PPTBuGraEntry* pPtr = nullptr; + if ( nInstance < aBuGraList.size() ) + { + pPtr = aBuGraList[ nInstance ].get(); + if ( pPtr->nInstance == nInstance ) + bRetValue = true; + } + if ( !bRetValue ) + { + for (std::unique_ptr const & i : aBuGraList) + { + pPtr = i.get(); + if ( pPtr->nInstance == nInstance ) + { + bRetValue = true; + break; + } + } + } + if ( bRetValue ) + rGraph = pPtr->aBuGra; + return bRetValue; +} + +PPTExtParaProv::PPTExtParaProv( SdrPowerPointImport& rMan, SvStream& rSt, const DffRecordHeader* pHd ) : + bStyles ( false ) +{ + sal_uInt32 nOldPos = rSt.Tell(); + + // here we have to get the graphical bullets... + + DffRecordHeader aHd; + DffRecordHeader aContentDataHd; + + const DffRecordHeader* pListHd = rMan.aDocRecManager.GetRecordHeader( PPT_PST_List ); + if( pListHd ) + pListHd->SeekToContent( rSt ); + if ( pListHd && SdrPowerPointImport::SeekToContentOfProgTag( 9, rSt, *pListHd, aContentDataHd ) ) + { + auto nEndRecPos = DffPropSet::SanitizeEndPos(rSt, aContentDataHd.GetRecEndFilePos()); + while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) ) + { + ReadDffRecordHeader( rSt, aHd ); + switch ( aHd.nRecType ) + { + case PPT_PST_ExtendedBuGraContainer : + { + auto nHdEndRecPos = DffPropSet::SanitizeEndPos(rSt, aHd.GetRecEndFilePos()); + while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nHdEndRecPos ) ) + { + DffRecordHeader aBuGraAtomHd; + ReadDffRecordHeader( rSt, aBuGraAtomHd ); + if ( aBuGraAtomHd.nRecType == PPT_PST_ExtendedBuGraAtom ) + { + sal_uInt16 nType; + rSt.ReadUInt16( nType ); + Graphic aGraphic; + if ( SvxMSDffManager::GetBLIPDirect( rSt, aGraphic ) ) + { + sal_uInt32 nInstance = aBuGraAtomHd.nRecInstance; + PPTBuGraEntry* pBuGra = new PPTBuGraEntry( std::move(aGraphic), nInstance ); + size_t n = 0; + size_t nBuGraCount = aBuGraList.size(); + if ( nBuGraCount ) + { + if ( aBuGraList[ nBuGraCount - 1 ]->nInstance < nInstance ) + n = nBuGraCount; + else + { // maybe the instances are not sorted, we sort it + for ( n = 0; n < nBuGraCount; n++ ) + { // sorting fields ( hi >> lo ) + if ( aBuGraList[ n ]->nInstance < nInstance ) + break; + } + } + } + if ( n < nBuGraCount ) { + aBuGraList.emplace( aBuGraList.begin() + n, pBuGra ); + } else { + aBuGraList.emplace_back( pBuGra ); + } + } +#ifdef DBG_UTIL + else OSL_FAIL( "PPTExParaProv::PPTExParaProv - bullet graphic is not valid (SJ)" ); +#endif + } +#ifdef DBG_UTIL + else OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom interpreting the PPT_PST_ExtendedBuGraContainer (SJ)" ); +#endif + if (!aBuGraAtomHd.SeekToEndOfRecord(rSt)) + break; + } + } + break; + + case PPT_PST_ExtendedPresRuleContainer : + aExtendedPresRules.Consume( rSt, aHd.GetRecEndFilePos() ); + break; +#ifdef DBG_UTIL + default : + OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom reading ppt2000 num rules (SJ)" ); + break; + case PPT_PST_MasterText : // first seen in: ms-tt02.ppt + case PPT_PST_SrKinsoku : + case PPT_PST_TextDefaults9Atom : + case PPT_PST_PresentationAdvisorFlags9Atom : + case PPT_PST_HtmlDocInfo9Atom : + case PPT_PST_GridSpacing10Atom : + case PPT_PST_CommentIndex10 : + case PPT_PST_DocToolbarStates10Atom : + break; +#endif + } + if (!aHd.SeekToEndOfRecord(rSt)) + break; + } + } + + if ( pHd && SdrPowerPointImport::SeekToContentOfProgTag( 9, rSt, *pHd, aContentDataHd ) ) + { // get the extended paragraph styles on mainmaster ( graphical bullets, num ruling ... ) + auto nEndRecPos = DffPropSet::SanitizeEndPos(rSt, aContentDataHd.GetRecEndFilePos()); + while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) ) + { + ReadDffRecordHeader( rSt, aHd ); + switch ( aHd.nRecType ) + { + case PPT_PST_ExtendedParagraphMasterAtom : + { + if ( aHd.nRecInstance < PPT_STYLESHEETENTRIES ) + { + sal_uInt16 nDepth = 0, i = 0; + rSt.ReadUInt16(nDepth); + nDepth = std::min(nDepth, nMaxPPTLevels); + auto nHdEndRecPos = DffPropSet::SanitizeEndPos(rSt, aHd.GetRecEndFilePos()); + while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nHdEndRecPos ) && ( i < nDepth ) ) + { + bStyles = true; + ReadPPTExtParaLevel( rSt, aExtParaSheet[ static_cast(aHd.nRecInstance) ].aExtParaLevel[ i++ ] ); + } +#ifdef DBG_UTIL + if ( rSt.Tell() != aHd.GetRecEndFilePos() ) + OSL_FAIL( "PPTExParaProv::PPTExParaProv - error reading PPT_PST_ExtendedParagraphMasterAtom (SJ)" ); +#endif + } +#ifdef DBG_UTIL + else OSL_FAIL( "PPTExParaProv::PPTExParaProv - instance out of range (SJ)" ); +#endif + } + break; + default : + OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom, assuming PPT_PST_ExtendedParagraphMasterAtom (SJ)" ); + break; + case PPT_PST_HashCodeAtom : + case PPT_PST_BuildList : + case PPT_PST_SlideFlags10Atom : + case PPT_PST_SlideTime10Atom : + case 0xf144 : + break; + } + if (!aHd.SeekToEndOfRecord(rSt)) + break; + } + } + rSt.Seek( nOldPos ); +} + +PPTExtParaProv::~PPTExtParaProv() +{ +} + +PPTNumberFormatCreator::PPTNumberFormatCreator( std::unique_ptr pParaProv ) + : nIsBullet(0) + , nBulletChar(0) + , nBulletFont(0) + , nBulletHeight(0) + , nBulletColor(0) + , nTextOfs(0) + , nBulletOfs(0) + , pExtParaProv(std::move(pParaProv)) +{ +} + +PPTNumberFormatCreator::~PPTNumberFormatCreator() +{ +} + +bool PPTNumberFormatCreator::ImplGetExtNumberFormat( SdrPowerPointImport const & rManager, + SvxNumberFormat& rNumberFormat, sal_uInt32 nLevel, TSS_Type nInstance, TSS_Type nDestinationInstance, + std::optional< sal_Int16 >& rStartNumbering, sal_uInt32 nFontHeight, PPTParagraphObj const * pPara ) +{ + bool bHardAttribute = ( nDestinationInstance == TSS_Type::Unknown ); + + sal_uInt32 nBuFlags = 0; + sal_uInt16 nHasAnm = 0; + sal_uInt32 nAnmScheme = 0xFFFF0003; + sal_uInt16 nBuBlip = 0xffff; + + const PPTExtParaProv* pParaProv = pExtParaProv.get(); + if ( !pExtParaProv ) + pParaProv = pPara ? pPara->mrStyleSheet.pExtParaProv.get() + : rManager.m_pPPTStyleSheet->pExtParaProv.get(); + if ( pPara ) + { + nBuFlags = pPara->mxParaSet->mnExtParagraphMask; + if ( nBuFlags ) + { + if ( nBuFlags & 0x00800000 ) + nBuBlip = pPara->mxParaSet->mnBuBlip; + if ( nBuFlags & 0x01000000 ) + nAnmScheme = pPara->mxParaSet->mnAnmScheme; + if ( nBuFlags & 0x02000000 ) + nHasAnm = pPara->mxParaSet->mnHasAnm; + bHardAttribute = true; + } + } + + if ( ( nBuFlags & 0x03800000 ) != 0x03800000 ) // merge style sheet + { + // we have to read the master attributes + if (pParaProv && nLevel < nMaxPPTLevels) + { + if ( pParaProv->bStyles ) + { + const PPTExtParaLevel& rLev = pParaProv->aExtParaSheet[ nInstance ].aExtParaLevel[ nLevel ]; + if ( rLev.mbSet ) + { + sal_uInt32 nMaBuFlags = rLev.mnExtParagraphMask; + + if ( (!( nBuFlags & 0x00800000)) && ( nMaBuFlags & 0x00800000 ) ) + { + if (!( nBuFlags & 0x02000000)) // if there is a BuStart without BuInstance, + nBuBlip = rLev.mnBuBlip; // then there is no graphical Bullet possible + } + if ( (!( nBuFlags & 0x01000000)) && ( nMaBuFlags & 0x01000000 ) ) + nAnmScheme = rLev.mnAnmScheme; + if ( (!( nBuFlags & 0x02000000)) && ( nMaBuFlags & 0x02000000 ) ) + nHasAnm = rLev.mnHasAnm; + nBuFlags |= nMaBuFlags; + } + } + } + } + if ( nBuBlip != 0xffff ) // set graphical bullet + { + Graphic aGraphic; + if ( pParaProv && pParaProv->GetGraphic( nBuBlip, aGraphic ) ) + { + SvxBrushItem aBrush( aGraphic, GPOS_MM, SID_ATTR_BRUSH ); + rNumberFormat.SetGraphicBrush( &aBrush ); + sal_uInt32 nHeight = static_cast( static_cast(nFontHeight) * 0.2540 * nBulletHeight + 0.5 ); + Size aPrefSize( aGraphic.GetPrefSize() ); + sal_uInt32 nWidth; + if (aPrefSize.Height()) + nWidth = ( nHeight * aPrefSize.Width() ) / aPrefSize.Height(); + else + nWidth = 0; + rNumberFormat.SetGraphicSize( Size( nWidth, nHeight ) ); + rNumberFormat.SetNumberingType ( SVX_NUM_BITMAP ); + } + } + else if ( nHasAnm ) + { + switch( static_cast< sal_uInt16 >( nAnmScheme ) ) + { + default : + case 0 : + { + rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 1 : + { + rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 2 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ARABIC ); + rNumberFormat.SetSuffix( ")" ); + } + break; + case 3 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ARABIC ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 4 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER ); + rNumberFormat.SetSuffix( ")" ); + rNumberFormat.SetPrefix( "(" ); + } + break; + case 5 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER ); + rNumberFormat.SetSuffix( ")" ); + } + break; + case 6 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 7 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 8 : + { + rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER ); + rNumberFormat.SetSuffix( ")" ); + rNumberFormat.SetPrefix( "(" ); + } + break; + case 9 : + { + rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER ); + rNumberFormat.SetSuffix( ")" ); + } + break; + case 10 : + { + rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER ); + rNumberFormat.SetSuffix( ")" ); + rNumberFormat.SetPrefix( "(" ); + } + break; + case 11 : + { + rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER ); + rNumberFormat.SetSuffix( ")" ); + } + break; + case 12 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ARABIC ); + rNumberFormat.SetSuffix( ")" ); + rNumberFormat.SetPrefix( "(" ); + } + break; + case 13 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ARABIC ); + } + break; + case 14 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER ); + rNumberFormat.SetSuffix( ")" ); + rNumberFormat.SetPrefix( "(" ); + } + break; + case 15 : + { + rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER ); + rNumberFormat.SetSuffix( ")" ); + } + break; + case 16: // Simplified Chinese. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH ); + } + break; + case 17: // Simplified Chinese with single-byte period. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 18: // Double byte circle numbers. + case 19: // Wingdings white circle numbers. + case 20: // Wingdings black circle numbers. + { + rNumberFormat.SetNumberingType( SVX_NUM_CIRCLE_NUMBER ); + } + break; + case 21: // Traditional Chinese. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH_TW ); + } + break; + case 22: // Traditional Chinese with single-byte period. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH_TW ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 25: // Bidi Hebrew 2 with ANSI minus symbol. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_HEBREW ); + rNumberFormat.SetSuffix( "-" ); + } + break; + case 26: // Japanese/Korean. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH ); + } + break; + case 27: // Japanese/Korean with single-byte period. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH ); + rNumberFormat.SetSuffix( "." ); + } + break; + case 28: // Double-byte Arabic numbers. + { + rNumberFormat.SetNumberingType( SVX_NUM_FULL_WIDTH_ARABIC ); + } + break; + case 29: // Double-byte Arabic numbers with double-byte period. + { + rNumberFormat.SetNumberingType( SVX_NUM_FULL_WIDTH_ARABIC ); + rNumberFormat.SetSuffix( OUString( u'\xff0e' ) ); + } + break; + case 38: // Japanese with double-byte period. + { + rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH ); // No such type. Instead with Lower Chinese Number + rNumberFormat.SetSuffix( OUString( u'\xff0e' ) ); + } + break; + } + rStartNumbering = std::optional< sal_Int16 >( nAnmScheme >> 16 ); + sal_Int16 nBuStart = *rStartNumbering; + //The Seventh bit of nBuFlags that specifies whether fBulletHasAutoNumber exists, + //and fBulletHasAutoNumber that specifies whether this paragraph has an automatic numbering scheme. + if ( ( nBuFlags & 0x02000000 ) && ( nBuStart != -1 )) + { + rNumberFormat.SetStart( static_cast(nBuStart) ); + } + } + return bHardAttribute; +} + +void PPTNumberFormatCreator::GetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat, sal_uInt32 nLevel, const PPTParaLevel& rParaLevel, const PPTCharLevel& rCharLevel, TSS_Type nInstance ) +{ + nIsBullet = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BulletOn ) ) != 0 ? 1 : 0; + nBulletChar = rParaLevel.mnBulletChar; + + bool bBuHardFont; + bBuHardFont = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0; + if ( bBuHardFont ) + nBulletFont = rParaLevel.mnBulletFont; + else + nBulletFont = rCharLevel.mnFont; + nBulletHeight = rParaLevel.mnBulletHeight; + nBulletColor = rParaLevel.mnBulletColor; + nTextOfs = rParaLevel.mnTextOfs; + nBulletOfs = rParaLevel.mnBulletOfs; + + std::optional< sal_Int16 > oStartNumbering; + ImplGetExtNumberFormat( rManager, rNumberFormat, nLevel, nInstance, TSS_Type::Unknown, oStartNumbering, rCharLevel.mnFontHeight, nullptr ); + if ( ( rNumberFormat.GetNumberingType() != SVX_NUM_BITMAP ) && ( nBulletHeight > 0x7fff ) ) + nBulletHeight = rCharLevel.mnFontHeight ? ((- static_cast(nBulletHeight)) * 100 ) / rCharLevel.mnFontHeight : 100; + ImplGetNumberFormat( rManager, rNumberFormat ); + switch ( rNumberFormat.GetNumberingType() ) + { + case SVX_NUM_CHARS_UPPER_LETTER : + case SVX_NUM_CHARS_LOWER_LETTER : + case SVX_NUM_ROMAN_UPPER : + case SVX_NUM_ROMAN_LOWER : + case SVX_NUM_ARABIC : + case SVX_NUM_CHARS_UPPER_LETTER_N : + case SVX_NUM_CHARS_LOWER_LETTER_N : + { + sal_uInt32 nFont = rCharLevel.mnFont; + const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nFont ); + if ( pFontEnityAtom ) + { + vcl::Font aFont; + aFont.SetCharSet( pFontEnityAtom->eCharSet ); + aFont.SetFamilyName( pFontEnityAtom->aName ); + aFont.SetFamily( pFontEnityAtom->eFamily ); + aFont.SetPitch( pFontEnityAtom->ePitch ); + rNumberFormat.SetBulletFont( &aFont ); + } + } + break; + default: break; + } +} + +bool PPTNumberFormatCreator::GetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat, PPTParagraphObj* pParaObj, + TSS_Type nDestinationInstance, std::optional< sal_Int16 >& rStartNumbering ) +{ + sal_uInt32 nHardCount = 0; + nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletOn, nIsBullet, nDestinationInstance ) ? 1 : 0; + nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletChar, nBulletChar, nDestinationInstance ) ? 1 : 0; + nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletFont, nBulletFont, nDestinationInstance ) ? 1 : 0; + nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletHeight, nBulletHeight, nDestinationInstance ) ? 1 : 0; + nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletColor, nBulletColor, nDestinationInstance ) ? 1 : 0; + nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_TextOfs, nTextOfs, nDestinationInstance ) ? 1 : 0; + nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletOfs, nBulletOfs, nDestinationInstance ) ? 1 : 0; + + if ( nIsBullet ) + rNumberFormat.SetNumberingType( SVX_NUM_CHAR_SPECIAL ); + + sal_uInt32 nFontHeight = 24; + PPTPortionObj* pPtr = pParaObj->First(); + if ( pPtr ) + pPtr->GetAttrib( PPT_CharAttr_FontHeight, nFontHeight, nDestinationInstance ); + if ( nIsBullet ) + nHardCount += ImplGetExtNumberFormat( rManager, rNumberFormat, pParaObj->mxParaSet->mnDepth, + pParaObj->mnInstance, nDestinationInstance, rStartNumbering, nFontHeight, pParaObj ) ? 1 : 0; + + if ( rNumberFormat.GetNumberingType() != SVX_NUM_BITMAP ) + pParaObj->UpdateBulletRelSize( nBulletHeight ); + if ( nHardCount ) + { + ImplGetNumberFormat( rManager, rNumberFormat ); + switch ( rNumberFormat.GetNumberingType() ) + { + case SVX_NUM_CHARS_UPPER_LETTER : + case SVX_NUM_CHARS_LOWER_LETTER : + case SVX_NUM_ROMAN_UPPER : + case SVX_NUM_ROMAN_LOWER : + case SVX_NUM_ARABIC : + case SVX_NUM_CHARS_UPPER_LETTER_N : + case SVX_NUM_CHARS_LOWER_LETTER_N : + { + if ( pPtr ) + { + sal_uInt32 nFont; + pPtr->GetAttrib( PPT_CharAttr_Font, nFont, nDestinationInstance ); + const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nFont ); + if ( pFontEnityAtom ) + { + vcl::Font aFont; + aFont.SetCharSet( pFontEnityAtom->eCharSet ); + aFont.SetFamilyName( pFontEnityAtom->aName ); + aFont.SetFamily( pFontEnityAtom->eFamily ); + aFont.SetPitch( pFontEnityAtom->ePitch ); + rNumberFormat.SetBulletFont( &aFont ); + } + } + } + break; + default: break; + } + } + return nHardCount != 0; +} + +void PPTNumberFormatCreator::ImplGetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat ) +{ + vcl::Font aFont; + const PptFontEntityAtom* pAtom = rManager.GetFontEnityAtom( nBulletFont ); + if ( pAtom ) + { + rtl_TextEncoding eCharSet( pAtom->eCharSet ); + aFont.SetFamilyName( pAtom->aName ); + aFont.SetCharSet( eCharSet ); + aFont.SetFamily( pAtom->eFamily ); + aFont.SetPitch( pAtom->ePitch ); + } + Color aCol( rManager.MSO_TEXT_CLR_ToColor( nBulletColor ) ); + aFont.SetColor( aCol ); + + sal_uInt16 nBuChar = static_cast(nBulletChar); + if ( aFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + { + nBuChar &= 0x00ff; + nBuChar |= 0xf000; + } + rNumberFormat.SetBulletFont( &aFont ); + rNumberFormat.SetBulletChar( nBuChar ); + rNumberFormat.SetBulletRelSize( static_cast(nBulletHeight) ); + rNumberFormat.SetBulletColor( aCol ); + sal_uInt32 nAbsLSpace = convertMasterUnitToMm100(nTextOfs); + sal_uInt32 nFirstLineOffset = nAbsLSpace - convertMasterUnitToMm100(nBulletOfs); + rNumberFormat.SetAbsLSpace( nAbsLSpace ); + rNumberFormat.SetFirstLineOffset( -static_cast(nFirstLineOffset) ); +} + +PPTCharSheet::PPTCharSheet( TSS_Type nInstance ) +{ + sal_uInt32 nColor = PPT_COLSCHEME_TEXT_UND_ZEILEN; + sal_uInt16 nFontHeight(0); + switch ( nInstance ) + { + case TSS_Type::PageTitle : + case TSS_Type::Title : + { + nColor = PPT_COLSCHEME_TITELTEXT; + nFontHeight = 44; + } + break; + case TSS_Type::Body : + case TSS_Type::Subtitle : + case TSS_Type::HalfBody : + case TSS_Type::QuarterBody : + nFontHeight = 32; + break; + case TSS_Type::Notes : + nFontHeight = 12; + break; + case TSS_Type::Unused : + case TSS_Type::TextInShape : + nFontHeight = 24; + break; + default: break; + } + for (PPTCharLevel & nDepth : maCharLevel) + { + nDepth.mnFlags = 0; + nDepth.mnFont = 0; + nDepth.mnAsianOrComplexFont = 0xffff; + nDepth.mnFontHeight = nFontHeight; + nDepth.mnFontColor = nColor; + nDepth.mnFontColorInStyleSheet = Color( static_cast(nColor), static_cast( nColor >> 8 ), static_cast( nColor >> 16 ) ); + nDepth.mnEscapement = 0; + } +} + +void PPTCharSheet::Read( SvStream& rIn, sal_uInt32 nLevel) +{ + // character attributes + sal_uInt32 nCMask(0); + sal_uInt16 nVal16; + rIn.ReadUInt32(nCMask); + + if ( nCMask & 0x0000FFFF ) + { + sal_uInt16 nBitAttr(0); + maCharLevel[ nLevel ].mnFlags &= ~static_cast(nCMask); + rIn.ReadUInt16( nBitAttr ); // Bit attributes (bold, underlined, ...) + maCharLevel[ nLevel ].mnFlags |= nBitAttr; + } + if ( nCMask & ( 1 << PPT_CharAttr_Font ) ) // 0x00010000 + rIn.ReadUInt16( maCharLevel[ nLevel ].mnFont ); + if ( nCMask & ( 1 << PPT_CharAttr_AsianOrComplexFont ) ) // 0x00200000 + rIn.ReadUInt16( maCharLevel[ nLevel ].mnAsianOrComplexFont ); + if ( nCMask & ( 1 << PPT_CharAttr_ANSITypeface ) ) // 0x00400000 + rIn.ReadUInt16( nVal16 ); + if ( nCMask & ( 1 << PPT_CharAttr_Symbol ) ) // 0x00800000 + rIn.ReadUInt16( nVal16 ); + if ( nCMask & ( 1 << PPT_CharAttr_FontHeight ) ) // 0x00020000 + rIn.ReadUInt16( maCharLevel[ nLevel ].mnFontHeight ); + if ( nCMask & ( 1 << PPT_CharAttr_FontColor ) ) // 0x00040000 + { + rIn.ReadUInt32( maCharLevel[ nLevel ].mnFontColor ); + if( ! (maCharLevel[ nLevel ].mnFontColor & 0xff000000 ) ) + maCharLevel[ nLevel ].mnFontColor = PPT_COLSCHEME_HINTERGRUND; + } + if ( nCMask & ( 1 << PPT_CharAttr_Escapement ) ) // 0x00080000 + rIn.ReadUInt16( maCharLevel[ nLevel ].mnEscapement ); + if ( nCMask & 0x00100000 ) // 0x00100000 + rIn.ReadUInt16( nVal16 ); + + nCMask >>= 24; + while( nCMask ) + { + if ( nCMask & 1 ) + { + OSL_FAIL( "PPTCharSheet::Read - unknown attribute, send me this document (SJ)" ); + rIn.ReadUInt16( nVal16 ); + } + nCMask >>= 1; + } +} + +PPTParaSheet::PPTParaSheet( TSS_Type nInstance ) +{ + sal_uInt16 nBuFlags = 0; + sal_uInt32 nBulletColor = 0x8000000; + sal_uInt16 nUpperDist = 0; + + switch ( nInstance ) + { + case TSS_Type::PageTitle : + case TSS_Type::Title : + nBulletColor = PPT_COLSCHEME_TITELTEXT; + break; + case TSS_Type::Body : + case TSS_Type::Subtitle : + case TSS_Type::HalfBody : + case TSS_Type::QuarterBody : + { + nBuFlags = 1; + nUpperDist = 0x14; + } + break; + case TSS_Type::Notes : + nUpperDist = 0x1e; + break; + default: break; + } + for (PPTParaLevel & i : maParaLevel) + { + i.mnBuFlags = nBuFlags; + i.mnBulletChar = 0x2022; + i.mnBulletFont = 0; + i.mnBulletHeight = 100; + i.mnBulletColor = nBulletColor; + i.mnAdjust = 0; + i.mnLineFeed = 100; + i.mnLowerDist = 0; + i.mnUpperDist = nUpperDist; + i.mnTextOfs = 0; + i.mnBulletOfs = 0; + i.mnDefaultTab = 0x240; + i.mnAsianLineBreak = 0; + i.mnBiDi = 0; + } +} + +void PPTParaSheet::Read( SdrPowerPointImport const & +#ifdef DBG_UTIL + rManager +#endif + , SvStream& rIn + , sal_uInt32 nLevel, bool bFirst ) +{ + // paragraph attributes + sal_uInt32 nPMask(0); + rIn.ReadUInt32(nPMask); + + sal_uInt16 nMask16 = static_cast(nPMask) & 0xf; + if ( nMask16 ) + { + sal_uInt16 nVal16(0); + rIn.ReadUInt16( nVal16 ); + maParaLevel[ nLevel ].mnBuFlags &=~ nMask16; + nVal16 &= nMask16; + maParaLevel[ nLevel ].mnBuFlags |= nVal16; + } + if ( nPMask & 0x0080 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletChar ); + if ( nPMask & 0x0010 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletFont ); + if ( nPMask & 0x0040 ) + { + sal_uInt16 nVal16(0); + rIn.ReadUInt16( nVal16 ); + maParaLevel[ nLevel ].mnBulletHeight = nVal16; + } + if ( nPMask & 0x0020 ) + { + sal_uInt32 nVal32(0); + rIn.ReadUInt32(nVal32); + maParaLevel[ nLevel ].mnBulletColor = nVal32; + } + if ( bFirst ) + { + if ( nPMask & 0xF00 ) + { + // AbsJust! + sal_uInt16 nVal16(0); + rIn.ReadUInt16( nVal16 ); + maParaLevel[ nLevel ].mnAdjust = nVal16 & 3; + } + if ( nPMask & 0x1000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnLineFeed ); + if ( nPMask & 0x2000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnUpperDist ); + if ( nPMask & 0x4000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnLowerDist ); + if ( nPMask & 0x8000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnTextOfs ); + if ( nPMask & 0x10000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletOfs ); + if ( nPMask & 0x20000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnDefaultTab ); + if ( nPMask & 0x200000 ) + { + sal_uInt16 nVal16; + sal_uInt32 nVal32; + // number of tabulators + rIn.ReadUInt16( nVal16 ); + if (!rIn.good() || rIn.remainingSize() / sizeof(nVal32) < nVal16) + return; + for (sal_uInt16 i = 0; i < nVal16; ++i) + rIn.ReadUInt32( nVal32 ); // reading the tabulators + } + if ( nPMask & 0x40000 ) + { + sal_uInt16 nVal16; + rIn.ReadUInt16( nVal16 ); + } + if ( nPMask & 0x80000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnAsianLineBreak ); + if ( nPMask & 0x100000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnBiDi ); + } + else + { + if ( nPMask & 0x800 ) + { + sal_uInt16 nVal16(0); + rIn.ReadUInt16( nVal16 ); + maParaLevel[ nLevel ].mnAdjust = nVal16 & 3; + } + if ( nPMask & 0x1000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnLineFeed ); + if ( nPMask & 0x2000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnUpperDist ); + if ( nPMask & 0x4000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnLowerDist ); + if ( nPMask & 0x8000 ) + { + sal_uInt16 nVal16; + rIn.ReadUInt16( nVal16 ); + } + if ( nPMask & 0x100 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnTextOfs ); + if ( nPMask & 0x200 ) + { + sal_uInt16 nVal16; + rIn.ReadUInt16( nVal16 ); + } + if ( nPMask & 0x400 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletOfs ); + if ( nPMask & 0x10000 ) + { + sal_uInt16 nVal16; + rIn.ReadUInt16( nVal16 ); + } + if ( nPMask & 0xe0000 ) + { + sal_uInt16 nFlagsToModifyMask = static_cast( ( nPMask >> 17 ) & 7 ); + sal_uInt16 nVal16(0); + rIn.ReadUInt16( nVal16 ); + // bits that are not involved to zero + nVal16 &= nFlagsToModifyMask; + // bits that are to change to zero + maParaLevel[ nLevel ].mnAsianLineBreak &=~nFlagsToModifyMask; + // now set the corresponding bits + maParaLevel[ nLevel ].mnAsianLineBreak |= nVal16; + } + if ( nPMask & 0x100000 ) + { + sal_uInt16 nVal16; + sal_uInt32 nVal32; + // number of tabulators + rIn.ReadUInt16( nVal16 ); + if (!rIn.good() || rIn.remainingSize() / sizeof(nVal32) < nVal16) + return; + for (sal_uInt16 i = 0; i < nVal16; ++i) + rIn.ReadUInt32( nVal32 ); // reading the tabulators + } + if ( nPMask & 0x200000 ) + rIn.ReadUInt16( maParaLevel[ nLevel ].mnBiDi ); + } + + nPMask >>= 22; + while( nPMask ) + { + if ( nPMask & 1 ) + { +#ifdef DBG_UTIL + if (!(rManager.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT)) + { + OSL_FAIL( "PPTParaSheet::Read - unknown attribute, send me this document (SJ)" ); + } +#endif + sal_uInt16 nVal16; + rIn.ReadUInt16( nVal16 ); + } + nPMask >>= 1; + } +} + +void PPTParaSheet::UpdateBulletRelSize( sal_uInt32 nLevel, sal_uInt16 nFontHeight ) +{ + if ( maParaLevel[ nLevel ].mnBulletHeight > 0x7fff ) // a negative value is the absolute bullet height + { + sal_Int16 nBulletRelSize = static_cast(maParaLevel[ nLevel ].mnBulletHeight); + nBulletRelSize = nFontHeight ? ((-nBulletRelSize) * 100 ) / nFontHeight : 100; + if ( nBulletRelSize < 0 ) //bullet size over flow + nBulletRelSize = 100; + maParaLevel[ nLevel ].mnBulletHeight = nBulletRelSize; + } +} + +PPTStyleSheet::PPTStyleSheet( const DffRecordHeader& rSlideHd, SvStream& rIn, SdrPowerPointImport& rManager, + const PPTTextParagraphStyleAtomInterpreter& rTxPFStyle, + const PPTTextSpecInfo& rTextSpecInfo ) : + + PPTNumberFormatCreator ( std::make_unique( rManager, rIn, &rSlideHd ) ), + maTxSI ( rTextSpecInfo ) +{ + sal_uInt32 nOldFilePos = rIn.Tell(); + + // default stylesheets + mpCharSheet[ TSS_Type::PageTitle ] = std::make_unique( TSS_Type::PageTitle ); + mpCharSheet[ TSS_Type::Body ] = std::make_unique( TSS_Type::Body ); + mpCharSheet[ TSS_Type::Notes ] = std::make_unique( TSS_Type::Notes ); + mpCharSheet[ TSS_Type::Unused ] = std::make_unique( TSS_Type::Unused ); // this entry is not used by ppt + mpCharSheet[ TSS_Type::TextInShape ] = std::make_unique( TSS_Type::TextInShape ); + mpParaSheet[ TSS_Type::PageTitle ] = std::make_unique( TSS_Type::PageTitle ); + mpParaSheet[ TSS_Type::Body ] = std::make_unique( TSS_Type::Body ); + mpParaSheet[ TSS_Type::Notes ] = std::make_unique( TSS_Type::Notes ); + mpParaSheet[ TSS_Type::Unused ] = std::make_unique( TSS_Type::Unused ); + mpParaSheet[ TSS_Type::TextInShape ] = std::make_unique( TSS_Type::TextInShape ); + // mpCharSheet[ TSS_Type::QuarterBody ], mpCharSheet[ TSS_Type::HalfBody ], mpCharSheet[ TSS_Type::Title ], mpCharSheet[ TSS_Type::Subtitle ] intentionally null + // mpParaSheet[ TSS_Type::QuarterBody ], mpParaSheet[ TSS_Type::HalfBody ], mpParaSheet[ TSS_Type::Title ], mpParaSheet[ TSS_Type::Subtitle ] intentionally null + + /* SJ: try to locate the txMasterStyleAtom in the Environment + + it seems that the environment TextStyle is having a higher priority + than the TextStyle that can be found within the master page + */ + bool bFoundTxMasterStyleAtom04 = false; + DffRecordHeader* pEnvHeader = rManager.aDocRecManager.GetRecordHeader( PPT_PST_Environment ); + if ( pEnvHeader ) + { + pEnvHeader->SeekToContent( rIn ); + DffRecordHeader aTxMasterStyleHd; + auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pEnvHeader->GetRecEndFilePos()); + while (rIn.Tell() < nEndRecPos) + { + ReadDffRecordHeader( rIn, aTxMasterStyleHd ); + if ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom ) + { + sal_uInt16 nLevelCnt(0); + rIn.ReadUInt16(nLevelCnt); + + sal_uInt16 nLev = 0; + bool bFirst = true; + bFoundTxMasterStyleAtom04 = true; + auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd.GetRecEndFilePos()); + while (rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt && nLev < nMaxPPTLevels) + { + if ( nLev ) + { + mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev ] = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev - 1 ]; + mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ] = mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev - 1 ]; + } + mpParaSheet[ TSS_Type::TextInShape ]->Read( rManager, rIn, nLev, bFirst ); + if ( !nLev ) + { + // set paragraph defaults for instance 4 (TSS_Type::TextInShape) + if ( rTxPFStyle.bValid ) + { + PPTParaLevel& rParaLevel = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ 0 ]; + rParaLevel.mnAsianLineBreak = 0; + if ( rTxPFStyle.bForbiddenRules ) + rParaLevel.mnAsianLineBreak |= 1; + if ( !rTxPFStyle.bLatinTextWrap ) + rParaLevel.mnAsianLineBreak |= 2; + if ( rTxPFStyle.bHangingPunctuation ) + rParaLevel.mnAsianLineBreak |= 4; + } + } + mpCharSheet[ TSS_Type::TextInShape ]->Read( rIn, nLev ); + mpParaSheet[ TSS_Type::TextInShape ]->UpdateBulletRelSize( nLev, mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ].mnFontHeight ); + bFirst = false; + nLev++; + } + break; + } + else + { + if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn)) + break; + } + } + } + + rSlideHd.SeekToContent( rIn ); + + DffRecordHeader aTxMasterStyleHd; + auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rSlideHd.GetRecEndFilePos()); + while (rIn.Tell() < nEndRecPos) + { + ReadDffRecordHeader( rIn, aTxMasterStyleHd ); + if ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom ) + break; + else + { + if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn)) + break; + } + } + while ( ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom ) && ( rIn.Tell() < nEndRecPos ) ) //TODO: aTxMasterStyleHd may be used without having been properly initialized + { + TSS_Type nInstance = static_cast(aTxMasterStyleHd.nRecInstance); + if ( ( nInstance <= TSS_Type::LAST ) && + ( ( nInstance != TSS_Type::TextInShape ) || !bFoundTxMasterStyleAtom04 ) ) + { + if ( nInstance > TSS_Type::TextInShape ) + { + mpCharSheet[ nInstance ].reset(); // be sure to delete the old one if this instance comes twice + mpParaSheet[ nInstance ].reset(); + + switch ( nInstance ) + { + case TSS_Type::Subtitle : + { + mpCharSheet[ TSS_Type::Subtitle ] = std::make_unique( *( mpCharSheet[ TSS_Type::Body ] ) ); + mpParaSheet[ TSS_Type::Subtitle ] = std::make_unique( *( mpParaSheet[ TSS_Type::Body ] ) ); + } + break; + case TSS_Type::Title : + { + mpCharSheet[ TSS_Type::Title ] = std::make_unique( *( mpCharSheet[ TSS_Type::PageTitle ] ) ); + mpParaSheet[ TSS_Type::Title ] = std::make_unique( *( mpParaSheet[ TSS_Type::PageTitle ] ) ); + } + break; + case TSS_Type::HalfBody : + { + mpCharSheet[ TSS_Type::HalfBody ] = std::make_unique( *( mpCharSheet[ TSS_Type::Body ] ) ); + mpParaSheet[ TSS_Type::HalfBody ] = std::make_unique( *( mpParaSheet[ TSS_Type::Body ] ) ); + } + break; + + case TSS_Type::QuarterBody : + { + mpCharSheet[ TSS_Type::QuarterBody ] = std::make_unique( *( mpCharSheet[ TSS_Type::Body ] ) ); + mpParaSheet[ TSS_Type::QuarterBody ] = std::make_unique( *( mpParaSheet[ TSS_Type::Body ] ) ); + } + break; + default: break; + } + } + sal_uInt16 nLevelCnt(0); + rIn.ReadUInt16(nLevelCnt); + if (nLevelCnt > nMaxPPTLevels) + { + OSL_FAIL( "PPTStyleSheet::Ppt-TextStylesheet has more than 5 levels! (SJ)" ); + nLevelCnt = nMaxPPTLevels; + } + sal_uInt16 nLev = 0; + bool bFirst = true; + + auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd.GetRecEndFilePos()); + while ( rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt ) + { + if ( nLev && ( nInstance < TSS_Type::Subtitle ) ) + { + mpParaSheet[ nInstance ]->maParaLevel[ nLev ] = mpParaSheet[ nInstance ]->maParaLevel[ nLev - 1 ]; + mpCharSheet[ nInstance ]->maCharLevel[ nLev ] = mpCharSheet[ nInstance ]->maCharLevel[ nLev - 1 ]; + } + + // Exception: Template 5, 6 (MasterTitle Title and SubTitle) + if ( nInstance >= TSS_Type::Subtitle ) + { + bFirst = false; + + sal_uInt16 nDontKnow; + rIn.ReadUInt16( nDontKnow ); + } + mpParaSheet[ nInstance ]->Read( rManager, rIn, nLev, bFirst ); + mpCharSheet[ nInstance ]->Read( rIn, nLev ); + mpParaSheet[ nInstance ]->UpdateBulletRelSize( nLev, mpCharSheet[ nInstance ]->maCharLevel[ nLev ].mnFontHeight ); + bFirst = false; + nLev++; + } +#ifdef DBG_UTIL + if (!(rManager.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT)) + { + if ( rIn.GetError() == ERRCODE_NONE ) + { + OStringBuffer aMsg; + if ( rIn.Tell() > aTxMasterStyleHd.GetRecEndFilePos() ) + { + aMsg.append("\n reading too many bytes:" + + OString::number(rIn.Tell() - aTxMasterStyleHd.GetRecEndFilePos())); + } + if ( rIn.Tell() < aTxMasterStyleHd.GetRecEndFilePos() ) + { + aMsg.append("\n reading too few bytes:" + + OString::number(aTxMasterStyleHd.GetRecEndFilePos() - rIn.Tell())); + } + if (aMsg.getLength()) + { + aMsg.insert(0, "PptStyleSheet::operator>>[]"); + OSL_FAIL(aMsg.getStr()); + } + } + if ( rIn.Tell() != aTxMasterStyleHd.GetRecEndFilePos() ) + SAL_WARN( "filter.ms", "SJ: Wrong number of bytes read during import of PPT style"); + } +#endif + } + if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn)) + break; + ReadDffRecordHeader( rIn, aTxMasterStyleHd ); + } + if ( !mpCharSheet[ TSS_Type::Subtitle ] ) + { + mpCharSheet[ TSS_Type::Subtitle ] = std::make_unique( *( mpCharSheet[ TSS_Type::Body ] ) ); + mpParaSheet[ TSS_Type::Subtitle ] = std::make_unique( *( mpParaSheet[ TSS_Type::Body ] ) ); + } + if ( !mpCharSheet[ TSS_Type::Title ] ) + { + mpCharSheet[ TSS_Type::Title ] = std::make_unique( *( mpCharSheet[ TSS_Type::PageTitle ] ) ); + mpParaSheet[ TSS_Type::Title ] = std::make_unique( *( mpParaSheet[ TSS_Type::PageTitle ] ) ); + } + if ( !mpCharSheet[ TSS_Type::HalfBody ] ) + { + mpCharSheet[ TSS_Type::HalfBody ] = std::make_unique( *( mpCharSheet[ TSS_Type::Body ] ) ); + mpParaSheet[ TSS_Type::HalfBody ] = std::make_unique( *( mpParaSheet[ TSS_Type::Body ] ) ); + } + if ( !mpCharSheet[ TSS_Type::QuarterBody ] ) + { + mpCharSheet[ TSS_Type::QuarterBody ] = std::make_unique( *( mpCharSheet[ TSS_Type::Body ] ) ); + mpParaSheet[ TSS_Type::QuarterBody ] = std::make_unique( *( mpParaSheet[ TSS_Type::Body ] ) ); + } + if ( !bFoundTxMasterStyleAtom04 ) + { // try to locate the txMasterStyleAtom in the Environment + DffRecordHeader* pEnvHeader2 = rManager.aDocRecManager.GetRecordHeader( PPT_PST_Environment ); + if ( pEnvHeader2 ) + { + pEnvHeader2->SeekToContent( rIn ); + DffRecordHeader aTxMasterStyleHd2; + auto nEnvEndRecPos = DffPropSet::SanitizeEndPos(rIn, pEnvHeader2->GetRecEndFilePos()); + while (rIn.Tell() < nEnvEndRecPos) + { + ReadDffRecordHeader( rIn, aTxMasterStyleHd2 ); + if ( aTxMasterStyleHd2.nRecType == PPT_PST_TxMasterStyleAtom ) + { + sal_uInt16 nLevelCnt; + rIn.ReadUInt16( nLevelCnt ); + + sal_uInt16 nLev = 0; + bool bFirst = true; + auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd2.GetRecEndFilePos()); + while ( rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt ) + { + if ( nLev ) + { + mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev ] = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev - 1 ]; + mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ] = mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev - 1 ]; + } + mpParaSheet[ TSS_Type::TextInShape ]->Read( rManager, rIn, nLev, bFirst ); + if ( !nLev ) + { + // set paragraph defaults for instance 4 (TSS_Type::TextInShape) + if ( rTxPFStyle.bValid ) + { + PPTParaLevel& rParaLevel = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ 0 ]; + rParaLevel.mnAsianLineBreak = 0; + if ( rTxPFStyle.bForbiddenRules ) + rParaLevel.mnAsianLineBreak |= 1; + if ( !rTxPFStyle.bLatinTextWrap ) + rParaLevel.mnAsianLineBreak |= 2; + if ( rTxPFStyle.bHangingPunctuation ) + rParaLevel.mnAsianLineBreak |= 4; + } + } + mpCharSheet[ TSS_Type::TextInShape ]->Read( rIn, nLev ); + mpParaSheet[ TSS_Type::TextInShape ]->UpdateBulletRelSize( nLev, mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ].mnFontHeight ); + bFirst = false; + nLev++; + } + break; + } + else + { + if (!aTxMasterStyleHd2.SeekToEndOfRecord(rIn)) + break; + } + } + } + } + rIn.Seek( nOldFilePos ); + + // will create the default numbulletitem for each instance + for ( auto i : o3tl::enumrange() ) + { + sal_uInt16 nLevels, nDepth = 0; + SvxNumRuleType eNumRuleType; + + switch ( i ) + { + case TSS_Type::PageTitle : + case TSS_Type::Title : + nLevels = 1; + eNumRuleType = SvxNumRuleType::NUMBERING; + break; + case TSS_Type::Subtitle : + nLevels = SVX_MAX_NUM; + eNumRuleType = SvxNumRuleType::NUMBERING; + break; + case TSS_Type::Body : + case TSS_Type::HalfBody : + case TSS_Type::QuarterBody : + nLevels = SVX_MAX_NUM; + eNumRuleType = SvxNumRuleType::PRESENTATION_NUMBERING; + break; + default : + case TSS_Type::Notes : + case TSS_Type::Unused : + case TSS_Type::TextInShape : + nLevels = SVX_MAX_NUM; + eNumRuleType = SvxNumRuleType::NUMBERING; + break; + } + SvxNumRule aRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::BULLET_COLOR, + nLevels, false, eNumRuleType ); + for ( sal_uInt16 nCount = 0; nDepth < nLevels; nCount++ ) + { + const PPTParaLevel& rParaLevel = mpParaSheet[ i ]->maParaLevel[ nCount ]; + const PPTCharLevel& rCharLevel = mpCharSheet[ i ]->maCharLevel[ nCount ]; + SvxNumberFormat aNumberFormat( SVX_NUM_CHAR_SPECIAL ); + aNumberFormat.SetBulletChar( ' ' ); + GetNumberFormat( rManager, aNumberFormat, nCount, rParaLevel, rCharLevel, i ); + aRule.SetLevel( nDepth++, aNumberFormat ); + if ( nCount >= 4 ) + { + for ( ;nDepth < nLevels; nDepth++ ) + aRule.SetLevel( nDepth, aNumberFormat ); + } + } + mpNumBulletItem[ i ] = std::make_unique( std::move(aRule), EE_PARA_NUMBULLET ); + } +} + +PPTStyleSheet::~PPTStyleSheet() +{ + for ( auto i : o3tl::enumrange() ) + { + mpCharSheet[i].reset(); + mpParaSheet[i].reset(); + mpNumBulletItem[i].reset(); + } +} + +PPTParaPropSet::PPTParaPropSet() + : mnOriginalTextPos(0) + , mxParaSet( new ImplPPTParaPropSet ) +{ + mxParaSet->mnHasAnm = 1; +} + +PPTParaPropSet::PPTParaPropSet( PPTParaPropSet const & rParaPropSet ) +{ + mxParaSet = rParaPropSet.mxParaSet; + mnOriginalTextPos = rParaPropSet.mnOriginalTextPos; +} + +PPTParaPropSet::~PPTParaPropSet() +{ +} + +PPTParaPropSet& PPTParaPropSet::operator=( const PPTParaPropSet& rParaPropSet ) +{ + if ( this != &rParaPropSet ) + { + mxParaSet = rParaPropSet.mxParaSet; + mnOriginalTextPos = rParaPropSet.mnOriginalTextPos; + } + return *this; +} + +PPTCharPropSet::PPTCharPropSet(sal_uInt32 nParagraph) + : mnOriginalTextPos(0) + , mnParagraph(nParagraph) +{ + mnHylinkOrigColor = 0; + mbIsHyperlink = false; + mbHardHylinkOrigColor = false; + mnLanguage[ 0 ] = mnLanguage[ 1 ] = mnLanguage[ 2 ] = LANGUAGE_SYSTEM; +} + +PPTCharPropSet::PPTCharPropSet( const PPTCharPropSet& rCharPropSet ) + : mpImplPPTCharPropSet( rCharPropSet.mpImplPPTCharPropSet ) +{ + mnHylinkOrigColor = rCharPropSet.mnHylinkOrigColor; + mbIsHyperlink = rCharPropSet.mbIsHyperlink; + mbHardHylinkOrigColor = rCharPropSet.mbHardHylinkOrigColor; + + mnParagraph = rCharPropSet.mnParagraph; + mnOriginalTextPos = rCharPropSet.mnOriginalTextPos; + maString = rCharPropSet.maString; + mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr ); + mnLanguage[ 0 ] = rCharPropSet.mnLanguage[ 0 ]; + mnLanguage[ 1 ] = rCharPropSet.mnLanguage[ 1 ]; + mnLanguage[ 2 ] = rCharPropSet.mnLanguage[ 2 ]; +} + +PPTCharPropSet::PPTCharPropSet( const PPTCharPropSet& rCharPropSet, sal_uInt32 nParagraph ) + : mpImplPPTCharPropSet(rCharPropSet.mpImplPPTCharPropSet) +{ + mnHylinkOrigColor = rCharPropSet.mnHylinkOrigColor; + mbIsHyperlink = rCharPropSet.mbIsHyperlink; + mbHardHylinkOrigColor = rCharPropSet.mbHardHylinkOrigColor; + + mnParagraph = nParagraph; + mnOriginalTextPos = rCharPropSet.mnOriginalTextPos; + maString = rCharPropSet.maString; + mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr ); + mnLanguage[ 0 ] = mnLanguage[ 1 ] = mnLanguage[ 2 ] = LANGUAGE_SYSTEM; +} + +PPTCharPropSet::~PPTCharPropSet() +{ +} + +PPTCharPropSet& PPTCharPropSet::operator=( const PPTCharPropSet& rCharPropSet ) +{ + if ( this != &rCharPropSet ) + { + mpImplPPTCharPropSet = rCharPropSet.mpImplPPTCharPropSet; + mnOriginalTextPos = rCharPropSet.mnOriginalTextPos; + mnParagraph = rCharPropSet.mnParagraph; + maString = rCharPropSet.maString; + mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr ); + } + return *this; +} + +void PPTCharPropSet::SetFont( sal_uInt16 nFont ) +{ + sal_uInt32 nMask = 1 << PPT_CharAttr_Font; + bool bDoNotMake = (mpImplPPTCharPropSet->mnAttrSet & nMask) != 0; + + if ( bDoNotMake ) + bDoNotMake = nFont == mpImplPPTCharPropSet->mnFont; + + if ( !bDoNotMake ) + { + mpImplPPTCharPropSet->mnFont = nFont; + mpImplPPTCharPropSet->mnAttrSet |= nMask; + } +} + +void PPTCharPropSet::SetColor( sal_uInt32 nColor ) +{ + mpImplPPTCharPropSet->mnColor = nColor; + mpImplPPTCharPropSet->mnAttrSet |= 1 << PPT_CharAttr_FontColor; +} + +PPTRuler::PPTRuler() + : nFlags(0) + , nDefaultTab(0x240) + , nTabCount(0) +{ +} + +PPTRuler::~PPTRuler() +{ +}; + + +PPTTextRulerInterpreter::PPTTextRulerInterpreter() : + mxImplRuler ( new PPTRuler() ) +{ +} + +PPTTextRulerInterpreter::PPTTextRulerInterpreter( PPTTextRulerInterpreter const & rRuler ) +{ + mxImplRuler = rRuler.mxImplRuler; +} + +PPTTextRulerInterpreter::PPTTextRulerInterpreter( sal_uInt32 nFileOfs, DffRecordHeader const & rHeader, SvStream& rIn ) : + mxImplRuler ( new PPTRuler() ) +{ + if ( nFileOfs == 0xffffffff ) + return; + + sal_uInt32 nOldPos = rIn.Tell(); + DffRecordHeader rHd; + if ( nFileOfs ) + { + rIn.Seek( nFileOfs ); + ReadDffRecordHeader( rIn, rHd ); + } + else + { + rHeader.SeekToContent( rIn ); + if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextRulerAtom, rHeader.GetRecEndFilePos(), &rHd ) ) + nFileOfs++; + } + if ( nFileOfs ) + { + bool bRecordOk = true; + + sal_Int16 nTCount(0); + sal_Int32 i; + rIn.ReadInt32( mxImplRuler->nFlags ); + + // number of indent levels, unused now + if ( mxImplRuler->nFlags & 2 ) + rIn.ReadInt16( nTCount ); + if ( mxImplRuler->nFlags & 1 ) + rIn.ReadUInt16( mxImplRuler->nDefaultTab ); + if ( mxImplRuler->nFlags & 4 ) + { + rIn.ReadInt16(nTCount); + + const size_t nMaxPossibleRecords = rIn.remainingSize() / (2*sizeof(sal_uInt16)); + const sal_uInt16 nTabCount(nTCount); + + bRecordOk = nTabCount <= nMaxPossibleRecords; + + if (nTCount && bRecordOk) + { + mxImplRuler->nTabCount = nTabCount; + mxImplRuler->pTab.reset( new PPTTabEntry[ mxImplRuler->nTabCount ] ); + for ( i = 0; i < nTCount; i++ ) + { + rIn.ReadUInt16( mxImplRuler->pTab[ i ].nOffset ) + .ReadUInt16( mxImplRuler->pTab[ i ].nStyle ); + } + } + } + + if (bRecordOk) + { + for ( i = 0; i < 5; i++ ) + { + if ( mxImplRuler->nFlags & ( 8 << i ) ) + rIn.ReadUInt16( mxImplRuler->nTextOfs[ i ] ); + if ( mxImplRuler->nFlags & ( 256 << i ) ) + rIn.ReadUInt16( mxImplRuler->nBulletOfs[ i ] ); + if( mxImplRuler->nBulletOfs[ i ] > 0x7fff) + { + // workaround + // when bullet offset is > 0x7fff, the paragraph should look like + // * first line text + // second line text + + // we add to bullet para indent 0xffff - bullet offset. It looks like + // best we can do for now + mxImplRuler->nTextOfs[ i ] += 0xffff - mxImplRuler->nBulletOfs[ i ]; + mxImplRuler->nBulletOfs[ i ] = 0; + } + } + } + } + rIn.Seek( nOldPos ); +} + +bool PPTTextRulerInterpreter::GetDefaultTab( sal_uInt16& nValue ) const +{ + if ( ! ( mxImplRuler->nFlags & 1 ) ) + return false; + nValue = mxImplRuler->nDefaultTab; + return true; +} + +bool PPTTextRulerInterpreter::GetTextOfs( sal_uInt32 nLevel, sal_uInt16& nValue ) const +{ + if ( ! ( ( nLevel < 5 ) && ( mxImplRuler->nFlags & ( 8 << nLevel ) ) ) ) + return false; + nValue = mxImplRuler->nTextOfs[ nLevel ]; + return true; +} + +bool PPTTextRulerInterpreter::GetBulletOfs( sal_uInt32 nLevel, sal_uInt16& nValue ) const +{ + if ( ! ( ( nLevel < 5 ) && ( mxImplRuler->nFlags & ( 256 << nLevel ) ) ) ) + return false; + nValue = mxImplRuler->nBulletOfs[ nLevel ]; + return true; +} + +PPTTextRulerInterpreter& PPTTextRulerInterpreter::operator=( const PPTTextRulerInterpreter& rRuler ) +{ + if ( this != &rRuler ) + { + mxImplRuler = rRuler.mxImplRuler; + } + return *this; +} + +PPTTextRulerInterpreter::~PPTTextRulerInterpreter() +{ +} + +PPTTextParagraphStyleAtomInterpreter::PPTTextParagraphStyleAtomInterpreter() : + bValid ( false ), + bForbiddenRules ( false ), + bHangingPunctuation ( false ), + bLatinTextWrap ( false ) +{ +} + +bool PPTTextParagraphStyleAtomInterpreter::Read( SvStream& rIn, const DffRecordHeader& rRecHd ) +{ + bValid = false; + rRecHd.SeekToContent( rIn ); + sal_uInt32 nDummy32, nFlags, nRecEndPos = rRecHd.GetRecEndFilePos(); + sal_uInt16 nDummy16; + + rIn.ReadUInt16( nDummy16 ) + .ReadUInt32( nFlags ); + + if ( nFlags & 0xf && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // BuFlags + if ( nFlags & 0x80 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // BuChar + if ( nFlags & 0x10 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // nBuFont; + if ( nFlags & 0x40 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // nBuHeight; + if ( nFlags & 0x0020 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt32( nDummy32 ); // nBuColor; + if ( nFlags & 0x800 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // AbsJust! + if ( nFlags & 0x400 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); + if ( nFlags & 0x200 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); + if ( nFlags & 0x100 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); + if ( nFlags & 0x1000 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // LineFeed + if ( nFlags & 0x2000 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // nUpperDist + if ( nFlags & 0x4000 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); // nLowerDist + if ( nFlags & 0x8000 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); + if ( nFlags & 0x10000 && ( rIn.Tell() < nRecEndPos ) ) + rIn.ReadUInt16( nDummy16 ); + if ( nFlags & 0xe0000 && ( rIn.Tell() < nRecEndPos ) ) + { + rIn.ReadUInt16( nDummy16 ); + if ( nFlags & 0x20000 ) + bForbiddenRules = ( nDummy16 & 1 ) == 1; + if ( nFlags & 0x40000 ) + bLatinTextWrap = ( nDummy16 & 2 ) == 0; + if ( nFlags & 0x80000 ) + bHangingPunctuation = ( nDummy16 & 4 ) == 4; + } + nFlags &=~ 0xfffff; + sal_uInt32 nMask = 0x100000; + while ( nFlags && nMask && ( rIn.Tell() < nRecEndPos ) ) + { + if ( nFlags & nMask ) + { + rIn.ReadUInt16( nDummy16 ); + nFlags ^= nMask; + } + nMask <<= 1; + } + bValid = rIn.Tell() == nRecEndPos; + return bValid; +} + +PPTTextSpecInfo::PPTTextSpecInfo( sal_uInt32 _nCharIdx ) : + nCharIdx ( _nCharIdx ), + nDontKnow ( 1 ) +{ + nLanguage[ 0 ] = LANGUAGE_PROCESS_OR_USER_DEFAULT; + nLanguage[ 1 ] = LANGUAGE_SYSTEM; + nLanguage[ 2 ] = LANGUAGE_SYSTEM; +} + +PPTTextSpecInfoAtomInterpreter::PPTTextSpecInfoAtomInterpreter() : + bValid ( false ) +{ +} + +bool PPTTextSpecInfoAtomInterpreter::Read( SvStream& rIn, const DffRecordHeader& rRecHd, + sal_uInt16 nRecordType, const PPTTextSpecInfo* pTextSpecDefault ) +{ + bValid = false; + sal_uInt32 nCharIdx = 0; + rRecHd.SeekToContent( rIn ); + + auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rRecHd.GetRecEndFilePos()); + while (rIn.Tell() < nEndRecPos && rIn.good()) + { + if ( nRecordType == PPT_PST_TextSpecInfoAtom ) + { + sal_uInt32 nCharCount(0); + rIn.ReadUInt32( nCharCount ); + nCharIdx += nCharCount; + } + + sal_uInt32 nFlags(0); + rIn.ReadUInt32(nFlags); + + PPTTextSpecInfo aEntry( nCharIdx ); + if ( pTextSpecDefault ) + { + aEntry.nDontKnow = pTextSpecDefault->nDontKnow; + aEntry.nLanguage[ 0 ] = pTextSpecDefault->nLanguage[ 0 ]; + aEntry.nLanguage[ 1 ] = pTextSpecDefault->nLanguage[ 1 ]; + aEntry.nLanguage[ 2 ] = pTextSpecDefault->nLanguage[ 2 ]; + } + for (sal_uInt32 i = 1; nFlags && i ; i <<= 1) + { + sal_uInt16 nLang = 0; + switch( nFlags & i ) + { + case 0 : break; + case 1 : rIn.ReadUInt16( aEntry.nDontKnow ); break; + case 2 : rIn.ReadUInt16( nLang ); break; + case 4 : rIn.ReadUInt16( nLang ); break; + default : + { + rIn.SeekRel( 2 ); + } + } + if ( nLang ) + { + // #i119985#, we could probably handle this better if we have a + // place to override the final language for weak + // characters/fields to fallback to, rather than the current + // application locale. Assuming that we can determine what the + // default fallback language for a given .ppt, etc is during + // load time. + if (i == 2) + { + aEntry.nLanguage[ 0 ] = aEntry.nLanguage[ 1 ] = aEntry.nLanguage[ 2 ] = LanguageType(nLang); + } + } + nFlags &= ~i; + } + aList.push_back( aEntry ); + } + bValid = rIn.Tell() == rRecHd.GetRecEndFilePos(); + return bValid; +} + +PPTTextSpecInfoAtomInterpreter::~PPTTextSpecInfoAtomInterpreter() +{ +} + +void StyleTextProp9::Read( SvStream& rIn ) +{ + rIn.ReadUInt32( mnExtParagraphMask ); + if ( mnExtParagraphMask & 0x800000 ) + rIn.ReadUInt16( mnBuBlip ); + if ( mnExtParagraphMask & 0x2000000 ) + rIn.ReadUInt16( mnHasAnm ); + if ( mnExtParagraphMask & 0x1000000 ) + rIn.ReadUInt32( mnAnmScheme ); + if ( mnExtParagraphMask & 0x4000000 ) + rIn.ReadUInt32( mpfPP10Ext ); + rIn.ReadUInt32( mnExtCharacterMask ); + if ( mnExtCharacterMask & 0x100000 ) + rIn.ReadUInt32( mncfPP10Ext ); + rIn.ReadUInt32( mnSpecialInfoMask ); + if ( mnSpecialInfoMask & 0x20 ) + rIn.ReadUInt32( mnPP10Ext ); + if ( mnSpecialInfoMask & 0x40 ) + rIn.ReadUInt16( mfBidi ); +} + +PPTStyleTextPropReader::PPTStyleTextPropReader( SvStream& rIn, const DffRecordHeader& rTextHeader, + PPTTextRulerInterpreter const & rRuler, const DffRecordHeader& rExtParaHd, TSS_Type nInstance ) +{ + Init(rIn, rTextHeader, rRuler, rExtParaHd, nInstance); +} + +void PPTStyleTextPropReader::ReadParaProps( SvStream& rIn, const DffRecordHeader& rTextHeader, + const OUString& aString, PPTTextRulerInterpreter const & rRuler, + sal_uInt32& nCharCount, bool& bTextPropAtom ) +{ + sal_uInt32 nMask = 0; //TODO: nMask initialized here to suppress warning for now, see corresponding TODO below + sal_uInt32 nCharReadCnt = 0; + sal_uInt16 nDummy16; + + sal_uInt16 nStringLen = aString.getLength(); + + DffRecordHeader aTextHd2; + rTextHeader.SeekToContent( rIn ); + if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_StyleTextPropAtom, rTextHeader.GetRecEndFilePos(), &aTextHd2 ) ) + bTextPropAtom = true; + while ( nCharReadCnt <= nStringLen ) + { + PPTParaPropSet aParaPropSet; + ImplPPTParaPropSet& aSet = *aParaPropSet.mxParaSet; + if ( bTextPropAtom ) + { + rIn.ReadUInt32( nCharCount ) + .ReadUInt16( aParaPropSet.mxParaSet->mnDepth ); // indent depth + + aParaPropSet.mxParaSet->mnDepth = // taking care of about using not more than 9 outliner levels + std::min(sal_uInt16(8), + aParaPropSet.mxParaSet->mnDepth); + + nCharCount--; + + rIn.ReadUInt32( nMask ); + aSet.mnAttrSet = nMask & 0x207df7; + sal_uInt16 nBulFlg = 0; + if ( nMask & 0xF ) + rIn.ReadUInt16( nBulFlg ); // Bullet-HardAttr-Flags + aSet.mpArry[ PPT_ParaAttr_BulletOn ] = ( nBulFlg & 1 ) ? 1 : 0; + aSet.mpArry[ PPT_ParaAttr_BuHardFont ] = ( nBulFlg & 2 ) ? 1 : 0; + aSet.mpArry[ PPT_ParaAttr_BuHardColor ] = ( nBulFlg & 4 ) ? 1 : 0; + + // NOTE: one might think that the hard-coded numbers here are the + // same as the PPT_ParaAttr_* constants, but it's NOT always true! + if ( nMask & 0x0080 ) // buChar + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletChar ] ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletChar); + } + } + if ( nMask & 0x0010 ) // buTypeface + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletFont ] ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletFont); + } + } + if ( nMask & 0x0040 ) // buSize + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletHeight ] ); + if (!rIn.good() + || !((nMask & (1 << PPT_ParaAttr_BuHardHeight)) + && (nBulFlg & (1 << PPT_ParaAttr_BuHardHeight)))) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletHeight); + } + } + if ( nMask & 0x0020 ) // buColor + { + sal_uInt32 nVal32; + rIn.ReadUInt32( nVal32 ); + if (!rIn.good()) + { + aSet.mnBulletColor = 0; // no flag for this? default it + } + else + { + sal_uInt32 nHiByte; + nHiByte = nVal32 >> 24; + if ( nHiByte <= 8 ) + nVal32 = nHiByte | PPT_COLSCHEME; + aSet.mnBulletColor = nVal32; + } + } + if ( nMask & 0x0800 ) // pfAlignment + { + rIn.ReadUInt16( nDummy16 ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_Adjust); + } + else + { + aSet.mpArry[ PPT_ParaAttr_Adjust ] = nDummy16 & 3; + } + } + if ( nMask & 0x1000 ) // pfLineSpacing + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_LineFeed ] ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_LineFeed); + } + } + if ( nMask & 0x2000 ) // pfSpaceBefore + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_UpperDist ] ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_UpperDist); + } + } + if ( nMask & 0x4000 ) // pfSpaceAfter + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_LowerDist ] ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_LowerDist); + } + } + if ( nMask & 0x100 ) // pfLeftMargin + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_TextOfs ] ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_TextOfs); + } + else + { + aSet.mnAttrSet |= 1 << PPT_ParaAttr_TextOfs; + } + } + if ( nMask & 0x400 ) // pfIndent + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletOfs ] ); + if (!rIn.good()) + { + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletOfs); + } + else + { + aSet.mnAttrSet |= 1 << PPT_ParaAttr_BulletOfs; + } + } + if ( nMask & 0x8000 ) // pfDefaultTabSize + { + rIn.ReadUInt16( nDummy16 ); + if (!rIn.good()) + { + // TODO? + } + } + if ( nMask & 0x100000 ) // pfTabStops + { + sal_uInt16 i, nDistance, nAlignment, nNumberOfTabStops = 0; + rIn.ReadUInt16( nNumberOfTabStops ); + if (!rIn.good()) + { + // TODO? + } + else + { + const size_t nMinRecordSize = 4; + const size_t nMaxRecords = rIn.remainingSize() / nMinRecordSize; + if (nNumberOfTabStops > nMaxRecords) + { + SAL_WARN("filter.ms", "Parsing error: " << nMaxRecords << + " max possible entries, but " << nNumberOfTabStops << " claimed, truncating"); + nNumberOfTabStops = nMaxRecords; + } + for (i = 0; i < nNumberOfTabStops; ++i) + { + rIn.ReadUInt16( nDistance ) + .ReadUInt16( nAlignment ); + } + } + } + if ( nMask & 0x10000 ) // pfBaseLine + { + rIn.ReadUInt16( nDummy16 ); + if (!rIn.good()) + { + // TODO? + } + } + if ( nMask & 0xe0000 ) // pfCharWrap, pfWordWrap, pfOverflow + { + rIn.ReadUInt16( nDummy16 ); + if (!rIn.good()) + { // clear flag to avoid invalid access + aSet.mnAttrSet &= ~((1 << PPT_ParaAttr_AsianLB_1) + | (1 << PPT_ParaAttr_AsianLB_2) + | (1 << PPT_ParaAttr_AsianLB_3)); + } + else + { + if (nMask & 0x20000) + aSet.mpArry[PPT_ParaAttr_AsianLB_1] = nDummy16 & 1; + if (nMask & 0x40000) + aSet.mpArry[PPT_ParaAttr_AsianLB_2] = (nDummy16 >> 1) & 1; + if (nMask & 0x80000) + aSet.mpArry[PPT_ParaAttr_AsianLB_3] = (nDummy16 >> 2) & 1; + aSet.mnAttrSet |= ((nMask >> 17) & 7) << PPT_ParaAttr_AsianLB_1; + } + } + if ( nMask & 0x200000 ) // pfTextDirection + { + rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BiDi ] ); + if (!rIn.good()) + { // clear flag to avoid invalid access + aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BiDi); + } + } + } + else + nCharCount = nStringLen; + + //if the textofs attr has been read at above, need not to reset. + if ( ( !( aSet.mnAttrSet & 1 << PPT_ParaAttr_TextOfs ) ) && rRuler.GetTextOfs( aParaPropSet.mxParaSet->mnDepth, aSet.mpArry[ PPT_ParaAttr_TextOfs ] ) ) + aSet.mnAttrSet |= 1 << PPT_ParaAttr_TextOfs; + if ( ( !( aSet.mnAttrSet & 1 << PPT_ParaAttr_BulletOfs ) ) && rRuler.GetBulletOfs( aParaPropSet.mxParaSet->mnDepth, aSet.mpArry[ PPT_ParaAttr_BulletOfs ] ) ) + aSet.mnAttrSet |= 1 << PPT_ParaAttr_BulletOfs; + if ( rRuler.GetDefaultTab( aSet.mpArry[ PPT_ParaAttr_DefaultTab ] ) ) + aSet.mnAttrSet |= 1 << PPT_ParaAttr_DefaultTab; + + if ( ( nCharCount > nStringLen ) || ( nStringLen < nCharReadCnt + nCharCount ) ) + { + bTextPropAtom = false; + nCharCount = nStringLen - nCharReadCnt; + // please fix the right hand side of + // PPTParaPropSet& PPTParaPropSet::operator=(PPTParaPropSet&), + // it should be a const reference + PPTParaPropSet aTmpPPTParaPropSet; + aParaPropSet = aTmpPPTParaPropSet; + OSL_FAIL( "SJ:PPTStyleTextPropReader::could not get this PPT_PST_StyleTextPropAtom by reading the paragraph attributes" ); + } + PPTParaPropSet* pPara = new PPTParaPropSet( aParaPropSet ); + pPara->mnOriginalTextPos = nCharReadCnt; + aParaPropList.emplace_back( pPara ); + if ( nCharCount ) + { + sal_uInt32 nCount; + const sal_Unicode* pDat = aString.getStr() + nCharReadCnt; + for ( nCount = 0; nCount < nCharCount; nCount++ ) + { + if ( pDat[ nCount ] == 0xd ) + { + pPara = new PPTParaPropSet( aParaPropSet ); + pPara->mnOriginalTextPos = nCharReadCnt + nCount + 1; + aParaPropList.emplace_back( pPara ); + } + } + } + nCharReadCnt += nCharCount + 1; + } +} + +void PPTStyleTextPropReader::ReadCharProps( SvStream& rIn, PPTCharPropSet& aCharPropSet, const OUString& aString, + sal_uInt32& nCharCount, sal_uInt32 nCharReadCnt, + bool& bTextPropAtom, sal_uInt32 nExtParaPos, + const std::vector< StyleTextProp9 >& aStyleTextProp9, + sal_uInt32& nExtParaFlags, sal_uInt16& nBuBlip, + sal_uInt16& nHasAnm, sal_uInt32& nAnmScheme ) +{ + sal_uInt16 nStringLen = aString.getLength(); + + sal_uInt16 nDummy16; + rIn.ReadUInt16( nDummy16 ); + nCharCount = (rIn.good()) ? nDummy16 : 0; + rIn.ReadUInt16( nDummy16 ); + + sal_Int32 nCharsToRead = nStringLen - ( nCharReadCnt + nCharCount ); + if ( nCharsToRead < 0 ) + { + nCharCount = nStringLen - nCharReadCnt; + if ( nCharsToRead < -1 ) + { + bTextPropAtom = false; + OSL_FAIL( "SJ:PPTStyleTextPropReader::could not get this PPT_PST_StyleTextPropAtom by reading the character attributes" ); + } + } + ImplPPTCharPropSet& aSet = *aCharPropSet.mpImplPPTCharPropSet; + + // character attributes + sal_uInt32 nMask(0); + rIn.ReadUInt32( nMask ); + if ( static_cast(nMask) ) + { + aSet.mnAttrSet |= static_cast(nMask); + rIn.ReadUInt16( aSet.mnFlags ); + } + if ( nMask & 0x10000 ) // cfTypeface + { + rIn.ReadUInt16( aSet.mnFont ); + aSet.mnAttrSet |= 1 << PPT_CharAttr_Font; + } + if ( nMask & 0x200000 ) // cfFEOldTypeface + { + rIn.ReadUInt16( aSet.mnAsianOrComplexFont ); + aSet.mnAttrSet |= 1 << PPT_CharAttr_AsianOrComplexFont; + } + if ( nMask & 0x400000 ) // cfANSITypeface + { + rIn.ReadUInt16( aSet.mnANSITypeface ); + aSet.mnAttrSet |= 1 << PPT_CharAttr_ANSITypeface; + } + if ( nMask & 0x800000 ) // cfSymbolTypeface + { + rIn.ReadUInt16( aSet.mnSymbolFont ); + aSet.mnAttrSet |= 1 << PPT_CharAttr_Symbol; + } + if ( nMask & 0x20000 ) // cfSize + { + rIn.ReadUInt16( aSet.mnFontHeight ); + aSet.mnAttrSet |= 1 << PPT_CharAttr_FontHeight; + } + if ( nMask & 0x40000 ) // cfColor + { + sal_uInt32 nVal(0); + rIn.ReadUInt32( nVal ); + if ( !( nVal & 0xff000000 ) ) + nVal = PPT_COLSCHEME_HINTERGRUND; + aSet.mnColor = nVal; + aSet.mnAttrSet |= 1 << PPT_CharAttr_FontColor; + } + if ( nMask & 0x80000 ) // cfPosition + { + rIn.ReadUInt16( aSet.mnEscapement ); + aSet.mnAttrSet |= 1 << PPT_CharAttr_Escapement; + } + if ( !nExtParaPos ) + return; + + sal_uInt32 nExtBuInd = nMask & 0x3c00; + if ( nExtBuInd ) + nExtBuInd = ( aSet.mnFlags & 0x3c00 ) >> 10; + if ( nExtBuInd < aStyleTextProp9.size() ) + { + nExtParaFlags = aStyleTextProp9[ nExtBuInd ].mnExtParagraphMask; + nBuBlip = aStyleTextProp9[ nExtBuInd ].mnBuBlip; + nHasAnm = aStyleTextProp9[ nExtBuInd ].mnHasAnm; + nAnmScheme = aStyleTextProp9[ nExtBuInd ].mnAnmScheme; + } +} + +void PPTStyleTextPropReader::Init( SvStream& rIn, const DffRecordHeader& rTextHeader, + PPTTextRulerInterpreter const & rRuler, const DffRecordHeader& rExtParaHd, TSS_Type nInstance ) +{ + sal_uInt32 nOldPos = rIn.Tell(); + sal_uInt32 nExtParaPos = ( rExtParaHd.nRecType == PPT_PST_ExtendedParagraphAtom ) ? rExtParaHd.nFilePos + 8 : 0; + + std::vector< StyleTextProp9 > aStyleTextProp9; + if ( rExtParaHd.nRecType == PPT_PST_ExtendedParagraphAtom ) + { + rIn.Seek( rExtParaHd.nFilePos + 8 ); + + auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rExtParaHd.GetRecEndFilePos()); + while( ( rIn.GetError() == ERRCODE_NONE ) && ( rIn.Tell() < nEndRecPos ) ) + { + aStyleTextProp9.emplace_back(); + aStyleTextProp9.back().Read( rIn ); + } + rIn.Seek( nOldPos ); + } + + OUString aString; + DffRecordHeader aTextHd; + ReadDffRecordHeader( rIn, aTextHd ); + sal_uInt32 nMaxLen = aTextHd.nRecLen; + if ( nMaxLen >= 0xFFFF ) + nMaxLen = 0xFFFE; + + if( aTextHd.nRecType == PPT_PST_TextCharsAtom ) + { + std::vector aBuf(( nMaxLen >> 1 ) + 1); + void* pDest = aBuf.data(); + auto nRead = rIn.ReadBytes(pDest, nMaxLen); + if (nRead != nMaxLen) + memset(static_cast(pDest) + nRead, 0, nMaxLen - nRead); + nMaxLen >>= 1; + aBuf[nMaxLen] = 0; + + sal_uInt32 i; + sal_Unicode* pPtr = aBuf.data(); + +#ifdef OSL_BIGENDIAN + sal_Unicode nTemp; + for ( i = 0; i < nMaxLen; i++ ) + { + nTemp = *pPtr; + *pPtr++ = ( nTemp << 8 ) | ( nTemp >> 8 ); + } + pPtr = aBuf.data(); +#endif + + for ( i = 0; i < nMaxLen; pPtr++, i++ ) + { + sal_Unicode nChar = *pPtr; + if ( !nChar ) + break; + if ( ( nChar & 0xff00 ) == 0xf000 ) // in this special case we got a symbol + aSpecMarkerList.push_back( static_cast( i | PPT_SPEC_SYMBOL ) ); + else if ( nChar == 0xd ) + { + if ( nInstance == TSS_Type::PageTitle ) + *pPtr = 0xb; + else + aSpecMarkerList.push_back( static_cast( i | PPT_SPEC_NEWLINE ) ); + } + } + if ( i ) + aString = OUString(aBuf.data(), i); + } + else if( aTextHd.nRecType == PPT_PST_TextBytesAtom ) + { + std::unique_ptr pBuf(new char[ nMaxLen + 1 ]); + nMaxLen = rIn.ReadBytes(pBuf.get(), nMaxLen); + pBuf[ nMaxLen ] = 0; + char* pPtr = pBuf.get(); + for (;;) + { + char cLo = *pPtr; + if ( cLo == 0 ) + break; + if ( cLo == 0xd ) + { + if ( nInstance == TSS_Type::PageTitle ) + *pPtr = 0xb; + else + aSpecMarkerList.push_back( static_cast( (pPtr - pBuf.get()) | PPT_SPEC_NEWLINE ) ); + } + pPtr++; + } + sal_Int32 nLen = pPtr - pBuf.get(); + if ( nLen ) + aString = OUString( pBuf.get(), nLen, RTL_TEXTENCODING_MS_1252 ); + } + else + { + // no chars, but potentially char/para props? + sal_uInt32 nCharCount; + bool bTextPropAtom = false; + ReadParaProps( rIn, rTextHeader, aString, rRuler, nCharCount, bTextPropAtom ); + + if ( bTextPropAtom ) + { + // yeah, StyleTextProp is there, read it all & push to + // aParaPropList + PPTCharPropSet aCharPropSet(0); + aCharPropSet.mnOriginalTextPos = 0; + + sal_uInt32 nExtParaFlags = 0, nAnmScheme = 0; + sal_uInt16 nBuBlip = 0xffff, nHasAnm = 0; + ReadCharProps( rIn, aCharPropSet, aString, nCharCount, 0/*nCharReadCnt*/, + bTextPropAtom, nExtParaPos, aStyleTextProp9, nExtParaFlags, + nBuBlip, nHasAnm, nAnmScheme ); + + aCharPropList.push_back(std::make_unique(aCharPropSet, 0)); + } + } + + if ( !aString.isEmpty() ) + { + sal_uInt32 nCharCount; + bool bTextPropAtom = false; + + ReadParaProps( rIn, rTextHeader, aString, rRuler, nCharCount, bTextPropAtom ); + + bool bEmptyParaPossible = true; + sal_uInt32 nCharReadCnt = 0; + sal_uInt32 nCurrentPara = 0; + size_t i = 1; // points to the next element to process + sal_uInt32 nCurrentSpecMarker = aSpecMarkerList.empty() ? 0 : aSpecMarkerList[0]; + sal_uInt32 nStringLen = aString.getLength(); + + while ( nCharReadCnt < nStringLen ) + { + sal_uInt32 nExtParaFlags = 0, nLatestParaUpdate = 0xffffffff, nAnmScheme = 0; + sal_uInt16 nBuBlip = 0xffff, nHasAnm = 0; + + PPTCharPropSet aCharPropSet( nCurrentPara ); + if ( bTextPropAtom ) + { + ReadCharProps( rIn, aCharPropSet, aString, nCharCount, nCharReadCnt, + bTextPropAtom, nExtParaPos, aStyleTextProp9, nExtParaFlags, + nBuBlip, nHasAnm, nAnmScheme ); + if (!rIn.good()) + break; + } + else + nCharCount = nStringLen; + + sal_uInt32 nLen; + while( nCharCount ) + { + if ( nExtParaPos && ( nLatestParaUpdate != nCurrentPara ) && ( nCurrentPara < aParaPropList.size() ) ) + { + PPTParaPropSet* pPropSet = aParaPropList[ nCurrentPara ].get(); + pPropSet->mxParaSet->mnExtParagraphMask = nExtParaFlags; + if ( nExtParaFlags & 0x800000 ) + pPropSet->mxParaSet->mnBuBlip = nBuBlip; + if ( nExtParaFlags & 0x01000000 ) + pPropSet->mxParaSet->mnAnmScheme = nAnmScheme; + if ( nExtParaFlags & 0x02000000 ) + pPropSet->mxParaSet->mnHasAnm = nHasAnm; + nLatestParaUpdate = nCurrentPara; + } + aCharPropSet.mnOriginalTextPos = nCharReadCnt; + if ( nCurrentSpecMarker && ( ( nCurrentSpecMarker & 0xffff ) < ( nCharReadCnt + nCharCount ) ) ) + { + if ( nCurrentSpecMarker & PPT_SPEC_NEWLINE ) + { + nLen = ( nCurrentSpecMarker & 0xffff ) - nCharReadCnt; + if ( nLen ) + aCharPropSet.maString = aString.copy( nCharReadCnt, nLen ); + else if ( bEmptyParaPossible ) + aCharPropSet.maString.clear(); + if ( nLen || bEmptyParaPossible ) + aCharPropList.push_back( + std::make_unique(aCharPropSet, nCurrentPara)); + nCurrentPara++; + nLen++; + nCharReadCnt += nLen; + nCharCount -= nLen; + bEmptyParaPossible = true; + } + else if ( nCurrentSpecMarker & PPT_SPEC_SYMBOL ) + { + if ( ( nCurrentSpecMarker & 0xffff ) != nCharReadCnt ) + { + nLen = ( nCurrentSpecMarker & 0xffff ) - nCharReadCnt; + aCharPropSet.maString = aString.copy(nCharReadCnt, nLen); + aCharPropList.push_back( + std::make_unique(aCharPropSet, nCurrentPara)); + nCharCount -= nLen; + nCharReadCnt += nLen; + } + PPTCharPropSet* pCPropSet = new PPTCharPropSet( aCharPropSet, nCurrentPara ); + pCPropSet->maString = aString.copy(nCharReadCnt, 1); + if ( aCharPropSet.mpImplPPTCharPropSet->mnAttrSet & ( 1 << PPT_CharAttr_Symbol ) ) + pCPropSet->SetFont( aCharPropSet.mpImplPPTCharPropSet->mnSymbolFont ); + aCharPropList.emplace_back( pCPropSet ); + nCharCount--; + nCharReadCnt++; + bEmptyParaPossible = false; + } + nCurrentSpecMarker = ( i < aSpecMarkerList.size() ) ? aSpecMarkerList[ i++ ] : 0; + } + else + { + if (nCharReadCnt > o3tl::make_unsigned(aString.getLength())) + aCharPropSet.maString = OUString(); + else + { + sal_Int32 nStrLen = nCharCount; + sal_Int32 nMaxStrLen = aString.getLength() - nCharReadCnt; + if (nStrLen > nMaxStrLen) + nStrLen = nMaxStrLen; + aCharPropSet.maString = aString.copy(nCharReadCnt, nStrLen); + } + aCharPropList.push_back( + std::make_unique(aCharPropSet, nCurrentPara)); + nCharReadCnt += nCharCount; + bEmptyParaPossible = false; + break; + } + } + } + if ( !aCharPropList.empty() && ( aCharPropList.back()->mnParagraph != nCurrentPara ) ) + { + PPTCharPropSet* pCharPropSet = new PPTCharPropSet( *aCharPropList.back(), nCurrentPara ); + pCharPropSet->maString.clear(); + pCharPropSet->mnOriginalTextPos = nStringLen - 1; + aCharPropList.emplace_back( pCharPropSet ); + } + } + rIn.Seek( nOldPos ); +} + +PPTStyleTextPropReader::~PPTStyleTextPropReader() +{ +} + +PPTPortionObj::PPTPortionObj( const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt32 nDepth ) : + PPTCharPropSet ( 0 ), + mrStyleSheet ( rStyleSheet ), + mnInstance ( nInstance ), + mnDepth ( std::min( nDepth, 4 ) ) +{ +} + +PPTPortionObj::PPTPortionObj( const PPTCharPropSet& rCharPropSet, const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt32 nDepth ) : + PPTCharPropSet ( rCharPropSet ), + mrStyleSheet ( rStyleSheet ), + mnInstance ( nInstance ), + mnDepth ( std::min( nDepth, 4 ) ) +{ +} + +PPTPortionObj::PPTPortionObj( const PPTPortionObj& rPortionObj ) : + PPTCharPropSet ( rPortionObj ), + mrStyleSheet ( rPortionObj.mrStyleSheet ), + mnInstance ( rPortionObj.mnInstance ), + mnDepth ( rPortionObj.mnDepth ) +{ +} + +PPTPortionObj::~PPTPortionObj() +{ +} + +bool PPTPortionObj::GetAttrib( sal_uInt32 nAttr, sal_uInt32& rRetValue, TSS_Type nDestinationInstance ) const +{ + sal_uInt32 nMask = 1 << nAttr; + rRetValue = 0; + + bool bIsHardAttribute = ( ( mpImplPPTCharPropSet->mnAttrSet & nMask ) != 0 ); + + if ( bIsHardAttribute ) + { + switch ( nAttr ) + { + case PPT_CharAttr_Bold : + case PPT_CharAttr_Italic : + case PPT_CharAttr_Underline : + case PPT_CharAttr_Shadow : + case PPT_CharAttr_Strikeout : + case PPT_CharAttr_Embossed : + rRetValue = ( mpImplPPTCharPropSet->mnFlags & nMask ) ? 1 : 0; + break; + case PPT_CharAttr_Font : + rRetValue = mpImplPPTCharPropSet->mnFont; + break; + case PPT_CharAttr_AsianOrComplexFont : + rRetValue = mpImplPPTCharPropSet->mnAsianOrComplexFont; + break; + case PPT_CharAttr_FontHeight : + rRetValue = mpImplPPTCharPropSet->mnFontHeight; + break; + case PPT_CharAttr_FontColor : + rRetValue = mpImplPPTCharPropSet->mnColor; + break; + case PPT_CharAttr_Escapement : + rRetValue = mpImplPPTCharPropSet->mnEscapement; + break; + default : + OSL_FAIL( "SJ:PPTPortionObj::GetAttrib ( hard attribute does not exist )" ); + } + } + else + { + const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ]; + PPTCharLevel* pCharLevel = nullptr; + if ( ( nDestinationInstance == TSS_Type::Unknown ) + || ( mnDepth && ( ( mnInstance == TSS_Type::Subtitle ) || ( mnInstance == TSS_Type::TextInShape ) ) ) ) + bIsHardAttribute = true; + else if ( nDestinationInstance != mnInstance ) + pCharLevel = &mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[ mnDepth ]; + switch( nAttr ) + { + case PPT_CharAttr_Bold : + case PPT_CharAttr_Italic : + case PPT_CharAttr_Underline : + case PPT_CharAttr_Shadow : + case PPT_CharAttr_Strikeout : + case PPT_CharAttr_Embossed : + { + rRetValue = ( rCharLevel.mnFlags & nMask ) ? 1 : 0; + if ( pCharLevel ) + { + sal_uInt32 nTmp = ( pCharLevel->mnFlags & nMask ) ? 1 : 0; + if ( rRetValue != nTmp ) + bIsHardAttribute = true; + } + } + break; + case PPT_CharAttr_Font : + { + rRetValue = rCharLevel.mnFont; + if ( pCharLevel && ( rRetValue != pCharLevel->mnFont ) ) + bIsHardAttribute = true; + } + break; + case PPT_CharAttr_AsianOrComplexFont : + { + rRetValue = rCharLevel.mnAsianOrComplexFont; + if ( pCharLevel && ( rRetValue != pCharLevel->mnAsianOrComplexFont ) ) + bIsHardAttribute = true; + } + break; + case PPT_CharAttr_FontHeight : + { + rRetValue = rCharLevel.mnFontHeight; + if ( pCharLevel && ( rRetValue != pCharLevel->mnFontHeight ) ) + bIsHardAttribute = true; + } + break; + case PPT_CharAttr_FontColor : + { + rRetValue = rCharLevel.mnFontColor; + if ( pCharLevel && ( rRetValue != pCharLevel->mnFontColor ) ) + bIsHardAttribute = true; + } + break; + case PPT_CharAttr_Escapement : + { + rRetValue = rCharLevel.mnEscapement; + if ( pCharLevel && ( rRetValue != pCharLevel->mnEscapement ) ) + bIsHardAttribute = true; + } + break; + default : + OSL_FAIL( "SJ:PPTPortionObj::GetAttrib ( attribute does not exist )" ); + } + } + return bIsHardAttribute; +} + +void PPTPortionObj::ApplyTo( SfxItemSet& rSet, SdrPowerPointImport& rManager, TSS_Type nDestinationInstance ) +{ + ApplyTo( rSet, rManager, nDestinationInstance, nullptr ); +} + +void PPTPortionObj::ApplyTo( SfxItemSet& rSet, SdrPowerPointImport& rManager, TSS_Type nDestinationInstance, const PPTTextObj* pTextObj ) +{ + sal_uInt32 nVal; + if ( GetAttrib( PPT_CharAttr_Bold, nVal, nDestinationInstance ) ) + { + rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) ); + rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) ); + rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) ); + } + if ( GetAttrib( PPT_CharAttr_Italic, nVal, nDestinationInstance ) ) + { + rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) ); + rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC_CJK ) ); + rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC_CTL ) ); + } + if ( GetAttrib( PPT_CharAttr_Underline, nVal, nDestinationInstance ) ) + rSet.Put( SvxUnderlineItem( nVal != 0 ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) ); + + if ( GetAttrib( PPT_CharAttr_Shadow, nVal, nDestinationInstance ) ) + rSet.Put( SvxShadowedItem( nVal != 0, EE_CHAR_SHADOW ) ); + + if ( GetAttrib( PPT_CharAttr_Strikeout, nVal, nDestinationInstance ) ) + rSet.Put( SvxCrossedOutItem( nVal != 0 ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) ); + + sal_uInt32 nAsianFontId = 0xffff; + if ( GetAttrib( PPT_CharAttr_AsianOrComplexFont, nAsianFontId, nDestinationInstance ) ) + { + if ( nAsianFontId != 0xffff ) + { + const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nAsianFontId ); + if ( pFontEnityAtom ) + { + rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, + OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CJK ) ); + rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, + OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CTL ) ); + } + } + } + if ( GetAttrib( PPT_CharAttr_Font, nVal, nDestinationInstance ) ) + { + const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nVal ); + if ( pFontEnityAtom ) + { + rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO ) ); + + // #i119475# bullet font info for CJK and CTL + if ( RTL_TEXTENCODING_SYMBOL == pFontEnityAtom->eCharSet ) + { + rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CJK ) ); + rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CTL ) ); + } + } + } + if ( GetAttrib( PPT_CharAttr_FontHeight, nVal, nDestinationInstance ) ) // Schriftgrad in Point + { + sal_uInt32 nHeight = rManager.ScalePoint( nVal ); + rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) ); + rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) ); + rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) ); + } + + if ( GetAttrib( PPT_CharAttr_Embossed, nVal, nDestinationInstance ) ) + rSet.Put( SvxCharReliefItem( nVal != 0 ? FontRelief::Embossed : FontRelief::NONE, EE_CHAR_RELIEF ) ); + if ( nVal ) /* if Embossed is set, the font color depends to the fillstyle/color of the object, + if the object has no fillstyle, the font color depends to fillstyle of the background */ + { + Color aDefColor( COL_BLACK ); + sal_uInt32 eFillType = mso_fillSolid; + if ( rManager.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ) & 0x10 ) + eFillType = rManager.GetPropertyValue(DFF_Prop_fillType, mso_fillSolid); + else + eFillType = mso_fillBackground; + switch( eFillType ) + { + case mso_fillShade : + case mso_fillShadeCenter : + case mso_fillShadeShape : + case mso_fillShadeScale : + case mso_fillShadeTitle : + case mso_fillSolid : + aDefColor = rManager.MSO_CLR_ToColor( rManager.GetPropertyValue( DFF_Prop_fillColor, 0 ) ); + break; + case mso_fillPattern : + aDefColor = rManager.MSO_CLR_ToColor( rManager.GetPropertyValue( DFF_Prop_fillBackColor, 0 ) ); + break; + case mso_fillTexture : + { + Graphic aGraf; + if ( rManager.GetBLIP( rManager.GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf ) ) + { + Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() ); + Size aSize( aBmp.GetSizePixel() ); + if ( aSize.Width() && aSize.Height() ) + { + if ( aSize.Width () > 64 ) + aSize.setWidth( 64 ); + if ( aSize.Height() > 64 ) + aSize.setHeight( 64 ); + + Bitmap::ScopedReadAccess pAcc(aBmp); + if( pAcc ) + { + sal_uLong nRt = 0, nGn = 0, nBl = 0; + const tools::Long nWidth = aSize.Width(); + const tools::Long nHeight = aSize.Height(); + + if( pAcc->HasPalette() ) + { + for( tools::Long nY = 0; nY < nHeight; nY++ ) + { + Scanline pScanline = pAcc->GetScanline( nY ); + for( tools::Long nX = 0; nX < nWidth; nX++ ) + { + const BitmapColor& rCol = pAcc->GetPaletteColor( pAcc->GetIndexFromData( pScanline, nX ) ); + nRt+=rCol.GetRed(); nGn+=rCol.GetGreen(); nBl+=rCol.GetBlue(); + } + } + } + else + { + for( tools::Long nY = 0; nY < nHeight; nY++ ) + { + Scanline pScanline = pAcc->GetScanline( nY ); + for( tools::Long nX = 0; nX < nWidth; nX++ ) + { + const BitmapColor aCol( pAcc->GetPixelFromData( pScanline, nX ) ); + nRt+=aCol.GetRed(); nGn+=aCol.GetGreen(); nBl+=aCol.GetBlue(); + } + } + } + pAcc.reset(); + sal_uInt32 nC = aSize.Width() * aSize.Height(); + nRt /= nC; + nGn /= nC; + nBl /= nC; + aDefColor = Color(sal_uInt8( nRt ), sal_uInt8( nGn ),sal_uInt8( nBl ) ); + } + } + } + } + break; + case mso_fillBackground : + { + if ( pTextObj ) // the textobject is needed + { + const SfxItemSet* pItemSet = pTextObj->GetBackground(); + if ( pItemSet ) + { + const XFillStyleItem* pFillStyleItem = pItemSet->GetItemIfSet( XATTR_FILLSTYLE, false ); + if ( pFillStyleItem ) + { + drawing::FillStyle eFillStyle = pFillStyleItem->GetValue(); + switch( eFillStyle ) + { + case drawing::FillStyle_SOLID : + { + const XColorItem* pFillColorItem = pItemSet->GetItemIfSet( XATTR_FILLCOLOR, false ); + if ( pFillColorItem ) + aDefColor = pFillColorItem->GetColorValue(); + } + break; + case drawing::FillStyle_GRADIENT : + { + const XFillGradientItem* pGradientItem = pItemSet->GetItemIfSet( XATTR_FILLGRADIENT, false ); + if ( pGradientItem ) + aDefColor = pGradientItem->GetGradientValue().GetStartColor(); + } + break; + case drawing::FillStyle_HATCH : + case drawing::FillStyle_BITMAP : + aDefColor = COL_WHITE; + break; + default: break; + } + } + } + } + } + break; + default: break; + } + rSet.Put( SvxColorItem( aDefColor, EE_CHAR_COLOR ) ); + } + else + { + if ( GetAttrib( PPT_CharAttr_FontColor, nVal, nDestinationInstance ) ) // text color (4Byte-Arg) + { + Color aCol( rManager.MSO_TEXT_CLR_ToColor( nVal ) ); + rSet.Put( SvxColorItem( aCol, EE_CHAR_COLOR ) ); + if ( nDestinationInstance == TSS_Type::Unknown ) + mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ].mnFontColorInStyleSheet = aCol; + } + else if ( nVal & 0x0f000000 ) // this is not a hard attribute, but maybe the page has a different colorscheme, + { // so that in this case we must use a hard color attribute + Color aCol( rManager.MSO_TEXT_CLR_ToColor( nVal ) ); + Color& aColorInSheet = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ].mnFontColorInStyleSheet; + if ( aColorInSheet != aCol ) + rSet.Put( SvxColorItem( aCol, EE_CHAR_COLOR ) ); + } + } + + if ( GetAttrib( PPT_CharAttr_Escapement, nVal, nDestinationInstance ) ) // super-/subscript in % + { + sal_uInt16 nEsc = 0; + sal_uInt8 nProp = 100; + + if ( nVal ) + { + nEsc = static_cast(nVal); + nProp = DFLT_ESC_PROP; + } + SvxEscapementItem aItem( nEsc, nProp, EE_CHAR_ESCAPEMENT ); + rSet.Put( aItem ); + } + if ( mnLanguage[ 0 ] ) + rSet.Put( SvxLanguageItem( mnLanguage[ 0 ], EE_CHAR_LANGUAGE ) ); + if ( mnLanguage[ 1 ] ) + rSet.Put( SvxLanguageItem( mnLanguage[ 1 ], EE_CHAR_LANGUAGE_CJK ) ); + if ( mnLanguage[ 2 ] ) + rSet.Put( SvxLanguageItem( mnLanguage[ 2 ], EE_CHAR_LANGUAGE_CTL ) ); +} + +SvxFieldItem* PPTPortionObj::GetTextField() +{ + if ( mpFieldItem ) + return new SvxFieldItem( *mpFieldItem ); + return nullptr; +} + +namespace +{ + sal_uInt16 sanitizeForMaxPPTLevels(sal_uInt16 nDepth) + { + if (nDepth >= nMaxPPTLevels) + { + SAL_WARN("filter.ms", "Para Style Sheet depth " << nDepth << " but " << nMaxPPTLevels - 1 << " is max possible"); + nDepth = nMaxPPTLevels - 1; + } + return nDepth; + } +} + +PPTParagraphObj::PPTParagraphObj( const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt16 nDepth ) : + PPTNumberFormatCreator ( nullptr ), + mrStyleSheet ( rStyleSheet ), + mnInstance ( nInstance ), + mnCurrentObject ( 0 ) +{ + mxParaSet->mnDepth = sanitizeForMaxPPTLevels(nDepth); +} + +PPTParagraphObj::PPTParagraphObj( PPTStyleTextPropReader& rPropReader, + size_t const nCurParaPos, size_t& rnCurCharPos, + const PPTStyleSheet& rStyleSheet, + TSS_Type nInstance, PPTTextRulerInterpreter const & rRuler ) : + PPTParaPropSet ( *rPropReader.aParaPropList[nCurParaPos] ), + PPTNumberFormatCreator ( nullptr ), + PPTTextRulerInterpreter ( rRuler ), + mrStyleSheet ( rStyleSheet ), + mnInstance ( nInstance ), + mnCurrentObject ( 0 ) +{ + if (rnCurCharPos >= rPropReader.aCharPropList.size()) + return; + + sal_uInt32 const nCurrentParagraph = + rPropReader.aCharPropList[rnCurCharPos]->mnParagraph; + for (; rnCurCharPos < rPropReader.aCharPropList.size() && + rPropReader.aCharPropList[rnCurCharPos]->mnParagraph == nCurrentParagraph; + ++rnCurCharPos) + { + PPTCharPropSet *const pCharPropSet = + rPropReader.aCharPropList[rnCurCharPos].get(); + std::unique_ptr pPPTPortion(new PPTPortionObj( + *pCharPropSet, rStyleSheet, nInstance, mxParaSet->mnDepth)); + m_PortionList.push_back(std::move(pPPTPortion)); + } +} + +PPTParagraphObj::~PPTParagraphObj() +{ +} + +void PPTParagraphObj::AppendPortion( PPTPortionObj& rPPTPortion ) +{ + m_PortionList.push_back( + std::make_unique(rPPTPortion)); +} + +void PPTParagraphObj::UpdateBulletRelSize( sal_uInt32& nBulletRelSize ) const +{ + if ( nBulletRelSize <= 0x7fff ) // a negative value is the absolute bullet height + return; + + sal_uInt16 nFontHeight = 0; + if (!m_PortionList.empty()) + { + PPTPortionObj const& rPortion = *m_PortionList.front(); + if (rPortion.mpImplPPTCharPropSet->mnAttrSet & (1 << PPT_CharAttr_FontHeight)) + { + nFontHeight = rPortion.mpImplPPTCharPropSet->mnFontHeight; + } + } + // if we do not have a hard attributed fontheight, the fontheight is taken from the style + if ( !nFontHeight ) + { + nFontHeight = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[sanitizeForMaxPPTLevels(mxParaSet->mnDepth)].mnFontHeight; + } + nBulletRelSize = nFontHeight ? ((- static_cast(nBulletRelSize)) * 100 ) / nFontHeight : 100; +} + +bool PPTParagraphObj::GetAttrib( sal_uInt32 nAttr, sal_uInt32& rRetValue, TSS_Type nDestinationInstance ) +{ + sal_uInt32 nMask = 1 << nAttr; + rRetValue = 0; + + if ( nAttr > 21 ) + { + OSL_FAIL( "SJ:PPTParagraphObj::GetAttrib - attribute does not exist" ); + return false; + } + + bool bIsHardAttribute = ( ( mxParaSet->mnAttrSet & nMask ) != 0 ); + + sal_uInt16 nDepth = sanitizeForMaxPPTLevels(mxParaSet->mnDepth); + + if ( bIsHardAttribute ) + { + if ( nAttr == PPT_ParaAttr_BulletColor ) + { + bool bHardBulletColor; + if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardColor ) ) + bHardBulletColor = mxParaSet->mpArry[ PPT_ParaAttr_BuHardColor ] != 0; + else + bHardBulletColor = ( mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth].mnBuFlags + & ( 1 << PPT_ParaAttr_BuHardColor ) ) != 0; + if ( bHardBulletColor ) + rRetValue = mxParaSet->mnBulletColor; + else + { + rRetValue = PPT_COLSCHEME_TEXT_UND_ZEILEN; + if ((nDestinationInstance != TSS_Type::Unknown) && !m_PortionList.empty()) + { + PPTPortionObj const& rPortion = *m_PortionList.front(); + if (rPortion.mpImplPPTCharPropSet->mnAttrSet & (1 << PPT_CharAttr_FontColor)) + { + rRetValue = rPortion.mpImplPPTCharPropSet->mnColor; + } + else + { + rRetValue = mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[nDepth].mnFontColor; + } + } + } + } + else if ( nAttr == PPT_ParaAttr_BulletFont ) + { + bool bHardBuFont; + if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardFont ) ) + bHardBuFont = mxParaSet->mpArry[ PPT_ParaAttr_BuHardFont ] != 0; + else + bHardBuFont = ( mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth].mnBuFlags + & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0; + if ( bHardBuFont ) + rRetValue = mxParaSet->mpArry[ PPT_ParaAttr_BulletFont ]; + else + { + // it is the font used which assigned to the first character of the following text + rRetValue = 0; + if ((nDestinationInstance != TSS_Type::Unknown) && !m_PortionList.empty()) + { + PPTPortionObj const& rPortion = *m_PortionList.front(); + if (rPortion.mpImplPPTCharPropSet->mnAttrSet & ( 1 << PPT_CharAttr_Font ) ) + { + rRetValue = rPortion.mpImplPPTCharPropSet->mnFont; + } + else + { + rRetValue = mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[nDepth].mnFont; + } + } + } + } + else + rRetValue = mxParaSet->mpArry[ nAttr ]; + } + else + { + const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth]; + + PPTParaLevel* pParaLevel = nullptr; + if ( ( nDestinationInstance == TSS_Type::Unknown ) + || ( nDepth && ( ( mnInstance == TSS_Type::Subtitle ) || ( mnInstance == TSS_Type::TextInShape ) ) ) ) + bIsHardAttribute = true; + else if ( nDestinationInstance != mnInstance ) + pParaLevel = &mrStyleSheet.mpParaSheet[ nDestinationInstance ]->maParaLevel[nDepth]; + switch ( nAttr ) + { + case PPT_ParaAttr_BulletOn : + { + rRetValue = rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BulletOn ); + if ( pParaLevel ) + { + if ( rRetValue != ( static_cast(pParaLevel->mnBuFlags) & ( 1 << PPT_ParaAttr_BulletOn ) ) ) + bIsHardAttribute = true; + } + } + break; + case PPT_ParaAttr_BuHardFont : + case PPT_ParaAttr_BuHardColor : + case PPT_ParaAttr_BuHardHeight : + OSL_FAIL( "SJ:PPTParagraphObj::GetAttrib - this attribute does not make sense" ); + break; + case PPT_ParaAttr_BulletChar : + { + rRetValue = rParaLevel.mnBulletChar; + if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletChar ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_BulletFont : + { + bool bHardBuFont; + if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardFont ) ) + bHardBuFont = mxParaSet->mpArry[ PPT_ParaAttr_BuHardFont ] != 0; + else + bHardBuFont = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0; + if ( bHardBuFont ) + { + rRetValue = rParaLevel.mnBulletFont; + if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletFont ) ) + bIsHardAttribute = true; + } + else + { + if (!m_PortionList.empty()) + { + PPTPortionObj const& rPortion = *m_PortionList.front(); + bIsHardAttribute = rPortion.GetAttrib( + PPT_CharAttr_Font, rRetValue, nDestinationInstance); + } + else + { + rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFont; + bIsHardAttribute = true; + } + } + } + break; + case PPT_ParaAttr_BulletHeight : + { + rRetValue = rParaLevel.mnBulletHeight; + if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletHeight ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_BulletColor : + { + bool bHardBulletColor; + if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardColor ) ) + bHardBulletColor = mxParaSet->mpArry[ PPT_ParaAttr_BuHardColor ] != 0; + else + bHardBulletColor = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) ) != 0; + if ( bHardBulletColor ) + { + rRetValue = rParaLevel.mnBulletColor; + if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletColor ) ) + bIsHardAttribute = true; + } + else + { + if (!m_PortionList.empty()) + { + PPTPortionObj const& rPortion = *m_PortionList.front(); + if (rPortion.mbIsHyperlink ) + { + if( rPortion.mbHardHylinkOrigColor ) + rRetValue = rPortion.mnHylinkOrigColor; + else + rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFontColor; + bIsHardAttribute = true; + } + else + { + bIsHardAttribute = rPortion.GetAttrib( PPT_CharAttr_FontColor, rRetValue, nDestinationInstance ); + } + } + else + { + rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFontColor; + bIsHardAttribute = true; + } + } + } + break; + case PPT_ParaAttr_Adjust : + { + rRetValue = rParaLevel.mnAdjust; + if ( pParaLevel && ( rRetValue != pParaLevel->mnAdjust ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_LineFeed : + { + rRetValue = rParaLevel.mnLineFeed; + if ( pParaLevel && ( rRetValue != pParaLevel->mnLineFeed ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_UpperDist : + { + rRetValue = rParaLevel.mnUpperDist; + if ( pParaLevel && ( rRetValue != pParaLevel->mnUpperDist ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_LowerDist : + { + rRetValue = rParaLevel.mnLowerDist; + if ( pParaLevel && ( rRetValue != pParaLevel->mnLowerDist ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_TextOfs : + { + rRetValue = rParaLevel.mnTextOfs; + if ( pParaLevel && ( rRetValue != pParaLevel->mnTextOfs ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_BulletOfs : + { + rRetValue = rParaLevel.mnBulletOfs; + if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletOfs ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_DefaultTab : + { + rRetValue = rParaLevel.mnDefaultTab; + if ( pParaLevel && ( rRetValue != pParaLevel->mnDefaultTab ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_AsianLB_1 : + { + rRetValue = rParaLevel.mnAsianLineBreak & 1; + if ( pParaLevel && ( rRetValue != ( static_cast(pParaLevel->mnAsianLineBreak) & 1 ) ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_AsianLB_2 : + { + rRetValue = ( rParaLevel.mnAsianLineBreak >> 1 ) & 1; + if ( pParaLevel && ( rRetValue != ( ( static_cast(pParaLevel->mnAsianLineBreak) >> 1 ) & 1 ) ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_AsianLB_3 : + { + rRetValue = ( rParaLevel.mnAsianLineBreak >> 2 ) & 1; + if ( pParaLevel && ( rRetValue != ( ( static_cast(pParaLevel->mnAsianLineBreak) >> 2 ) & 1 ) ) ) + bIsHardAttribute = true; + } + break; + case PPT_ParaAttr_BiDi : + { + rRetValue = rParaLevel.mnBiDi; + if ( pParaLevel && ( rRetValue != pParaLevel->mnBiDi ) ) + bIsHardAttribute = true; + } + break; + } + } + return bIsHardAttribute; +} + +void PPTParagraphObj::ApplyTo( SfxItemSet& rSet, std::optional< sal_Int16 >& rStartNumbering, SdrPowerPointImport const & rManager, TSS_Type nDestinationInstance ) +{ + sal_Int16 nVal2; + sal_uInt32 nVal, nUpperDist, nLowerDist; + TSS_Type nInstance = nDestinationInstance != TSS_Type::Unknown ? nDestinationInstance : mnInstance; + + if ( ( nDestinationInstance != TSS_Type::Unknown ) || ( mxParaSet->mnDepth <= 1 ) ) + { + SvxNumBulletItem* pNumBulletItem = mrStyleSheet.mpNumBulletItem[ nInstance ].get(); + if ( pNumBulletItem ) + { + SvxNumberFormat aNumberFormat( SVX_NUM_NUMBER_NONE ); + if ( GetNumberFormat( rManager, aNumberFormat, this, nDestinationInstance, rStartNumbering ) ) + { + if ( aNumberFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE ) + { + aNumberFormat.SetAbsLSpace( 0 ); + aNumberFormat.SetFirstLineOffset( 0 ); + aNumberFormat.SetCharTextDistance( 0 ); + aNumberFormat.SetFirstLineIndent( 0 ); + aNumberFormat.SetIndentAt( 0 ); + } + SvxNumBulletItem aNewNumBulletItem( *pNumBulletItem ); + SvxNumRule& rRule = aNewNumBulletItem.GetNumRule(); + rRule.SetLevel( mxParaSet->mnDepth, aNumberFormat ); + for (sal_uInt16 i = 0; i < rRule.GetLevelCount(); ++i) + { + if ( i != mxParaSet->mnDepth ) + { + sal_uInt16 n = sanitizeForMaxPPTLevels(i); + + SvxNumberFormat aNumberFormat2( rRule.GetLevel( i ) ); + const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ nInstance ]->maParaLevel[ n ]; + const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ nInstance ]->maCharLevel[ n ]; + sal_uInt32 nColor; + if ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) ) + nColor = rParaLevel.mnBulletColor; + else + nColor = rCharLevel.mnFontColor; + aNumberFormat2.SetBulletColor( rManager.MSO_TEXT_CLR_ToColor( nColor ) ); + rRule.SetLevel( i, aNumberFormat2 ); + } + } + rSet.Put( aNewNumBulletItem ); + } + } + } + + sal_uInt32 nIsBullet2, _nTextOfs, _nBulletOfs; + GetAttrib(PPT_ParaAttr_BulletOn, nIsBullet2, nDestinationInstance); + GetAttrib(PPT_ParaAttr_TextOfs, _nTextOfs, nDestinationInstance); + GetAttrib(PPT_ParaAttr_BulletOfs, _nBulletOfs, nDestinationInstance); + if ( !nIsBullet2 ) + { + SvxLRSpaceItem aLRSpaceItem( EE_PARA_LRSPACE ); + auto const nAbsLSpace = convertMasterUnitToMm100(_nTextOfs); + auto const nFirstLineOffset = nAbsLSpace - convertMasterUnitToMm100(_nBulletOfs); + aLRSpaceItem.SetLeft( nAbsLSpace ); + aLRSpaceItem.SetTextFirstLineOffsetValue( -nFirstLineOffset ); + rSet.Put( aLRSpaceItem ); + } + else + { + SvxLRSpaceItem aLRSpaceItem( EE_PARA_LRSPACE ); + aLRSpaceItem.SetLeft( 0 ); + aLRSpaceItem.SetTextFirstLineOffsetValue( 0 ); + rSet.Put( aLRSpaceItem ); + } + if ( GetAttrib( PPT_ParaAttr_Adjust, nVal, nDestinationInstance ) ) + { + if ( nVal <= 3 ) + { // paragraph adjustment + static SvxAdjust const aAdj[ 4 ] = { SvxAdjust::Left, SvxAdjust::Center, SvxAdjust::Right, SvxAdjust::Block }; + rSet.Put( SvxAdjustItem( aAdj[ nVal ], EE_PARA_JUST ) ); + } + } + + if ( GetAttrib( PPT_ParaAttr_AsianLB_1, nVal, nDestinationInstance ) ) + rSet.Put(SvxForbiddenRuleItem(nVal != 0, EE_PARA_FORBIDDENRULES)); + if ( GetAttrib( PPT_ParaAttr_AsianLB_3, nVal, nDestinationInstance ) ) + rSet.Put(SvxHangingPunctuationItem(nVal != 0, EE_PARA_HANGINGPUNCTUATION)); + + if ( GetAttrib( PPT_ParaAttr_BiDi, nVal, nDestinationInstance ) ) + rSet.Put( SvxFrameDirectionItem( nVal == 1 ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) ); + + // LineSpacing + PPTPortionObj* pPortion = First(); + bool bIsHardAttribute = GetAttrib( PPT_ParaAttr_LineFeed, nVal, nDestinationInstance ); + nVal2 = static_cast(nVal); + sal_uInt32 nFont = sal_uInt32(); + if ( pPortion && pPortion->GetAttrib( PPT_CharAttr_Font, nFont, nDestinationInstance ) ) + bIsHardAttribute = true; + + if ( bIsHardAttribute ) + { + SdrTextFixedCellHeightItem aHeightItem(true); + aHeightItem.SetWhich(SDRATTR_TEXT_USEFIXEDCELLHEIGHT); + rSet.Put( aHeightItem ); + SvxLineSpacingItem aItem( 200, EE_PARA_SBL ); + if ( nVal2 <= 0 ) { + aItem.SetLineHeight( static_cast( rManager.ScalePoint( -nVal2 ) / 8 ) ); + aItem.SetLineSpaceRule( SvxLineSpaceRule::Fix ); + aItem.SetInterLineSpaceRule(SvxInterLineSpaceRule::Off); + } else + { + sal_uInt16 nPropLineSpace = static_cast(nVal2); + aItem.SetPropLineSpace( nPropLineSpace ); + aItem.SetLineSpaceRule( SvxLineSpaceRule::Auto ); + } + rSet.Put( aItem ); + } + + // Paragraph Spacing + bIsHardAttribute = ( static_cast(GetAttrib( PPT_ParaAttr_UpperDist, nUpperDist, nDestinationInstance )) + + static_cast(GetAttrib( PPT_ParaAttr_LowerDist, nLowerDist, nDestinationInstance )) ) != 0; + if ( ( nUpperDist > 0 ) || ( nLowerDist > 0 ) ) + { + if (!m_PortionList.empty()) + { + sal_uInt32 nFontHeight = 0; + m_PortionList.back()->GetAttrib( + PPT_CharAttr_FontHeight, nFontHeight, nDestinationInstance); + if ( static_cast(nUpperDist) > 0 ) + nUpperDist = - static_cast( ( nFontHeight * nUpperDist * 100 ) / 1000 ); + if ( static_cast(nLowerDist) > 0 ) + nLowerDist = - static_cast( ( nFontHeight * nLowerDist * 100 ) / 1000 ); + } + bIsHardAttribute = true; + } + if ( bIsHardAttribute ) + { + SvxULSpaceItem aULSpaceItem( EE_PARA_ULSPACE ); + nVal2 = static_cast(nUpperDist); + if ( nVal2 <= 0 ) + aULSpaceItem.SetUpper(static_cast(convertMasterUnitToMm100(-nVal2))); + else + { + aULSpaceItem.SetUpperValue( 0 ); + aULSpaceItem.SetPropUpper( static_cast(nUpperDist) == 100 ? 101 : static_cast(nUpperDist) ); + } + nVal2 = static_cast(nLowerDist); + if ( nVal2 <= 0 ) + aULSpaceItem.SetLower(static_cast(convertMasterUnitToMm100(-nVal2))); + else + { + aULSpaceItem.SetLowerValue( 0 ); + aULSpaceItem.SetPropLower( static_cast(nLowerDist) == 100 ? 101 : static_cast(nLowerDist) ); + } + rSet.Put( aULSpaceItem ); + } + + sal_uInt32 i, nDefaultTab, nTab, nTextOfs2 = 0; + sal_uInt32 nLatestManTab = 0; + GetAttrib( PPT_ParaAttr_TextOfs, nTextOfs2, nDestinationInstance ); + GetAttrib( PPT_ParaAttr_BulletOfs, nTab, nDestinationInstance ); + GetAttrib( PPT_ParaAttr_DefaultTab, nDefaultTab, nDestinationInstance ); + + SvxTabStopItem aTabItem( 0, 0, SvxTabAdjust::Default, EE_PARA_TABS ); + if ( GetTabCount() ) + { + for ( i = 0; i < GetTabCount(); i++ ) + { + SvxTabAdjust eTabAdjust; + nTab = GetTabOffsetByIndex( static_cast(i) ); + switch( GetTabStyleByIndex( static_cast(i) ) ) + { + case 1 : eTabAdjust = SvxTabAdjust::Center; break; + case 2 : eTabAdjust = SvxTabAdjust::Right; break; + case 3 : eTabAdjust = SvxTabAdjust::Decimal; break; + default : eTabAdjust = SvxTabAdjust::Left; + } + aTabItem.Insert(SvxTabStop(convertMasterUnitToMm100(nTab), eTabAdjust)); + } + nLatestManTab = nTab; + } + if ( nIsBullet2 == 0 ) + aTabItem.Insert( SvxTabStop( sal_uInt16(0) ) ); + if ( nDefaultTab ) + { + nTab = std::max( nTextOfs2, nLatestManTab ); + nTab /= nDefaultTab; + nTab = nDefaultTab * ( 1 + nTab ); + for ( i = 0; ( i < 20 ) && ( nTab < 0x1b00 ); i++ ) + { + aTabItem.Insert( SvxTabStop( convertMasterUnitToMm100(nTab))); + nTab += nDefaultTab; + } + } + rSet.Put( aTabItem ); +} + +sal_uInt32 PPTParagraphObj::GetTextSize() +{ + sal_uInt32 nCount, nRetValue = 0; + for (const std::unique_ptr & i : m_PortionList) + { + PPTPortionObj const& rPortionObj = *i; + nCount = rPortionObj.Count(); + if ((!nCount) && rPortionObj.mpFieldItem) + nCount++; + nRetValue += nCount; + } + return nRetValue; +} + +PPTPortionObj* PPTParagraphObj::First() +{ + mnCurrentObject = 0; + if (m_PortionList.empty()) + return nullptr; + return m_PortionList.front().get(); +} + +PPTPortionObj* PPTParagraphObj::Next() +{ + sal_uInt32 i = mnCurrentObject + 1; + if (i >= m_PortionList.size()) + return nullptr; + mnCurrentObject++; + return m_PortionList[i].get(); +} + +PPTFieldEntry::~PPTFieldEntry() +{ +} + +void PPTFieldEntry::GetDateTime( const sal_uInt32 nVal, SvxDateFormat& eDateFormat, SvxTimeFormat& eTimeFormat ) +{ + eDateFormat = SvxDateFormat::AppDefault; + eTimeFormat = SvxTimeFormat::AppDefault; + // evaluate ID + switch( nVal ) + { + case 0: + case 6: + eDateFormat = SvxDateFormat::A; + break; + case 1: + eDateFormat = SvxDateFormat::F; + break; + case 2: + case 3: + eDateFormat = SvxDateFormat::D; + break; + case 4: + case 5: + eDateFormat = SvxDateFormat::C; + break; + case 7: + eDateFormat = SvxDateFormat::A; + [[fallthrough]]; + case 9: + eTimeFormat = SvxTimeFormat::HH24_MM; + break; + case 8: + eDateFormat = SvxDateFormat::A; + [[fallthrough]]; + case 11: + eTimeFormat = SvxTimeFormat::HH12_MM; + break; + case 10: + eTimeFormat = SvxTimeFormat::HH24_MM_SS; + break; + case 12: + eTimeFormat = SvxTimeFormat::HH12_MM_SS; + break; + } +} + +void PPTFieldEntry::SetDateTime( sal_uInt32 nVal ) +{ + SvxDateFormat eDateFormat; + SvxTimeFormat eTimeFormat; + GetDateTime( nVal, eDateFormat, eTimeFormat ); + if ( eDateFormat != SvxDateFormat::AppDefault ) + xField1.reset(new SvxFieldItem(SvxDateField( Date( Date::SYSTEM ), SvxDateType::Var, eDateFormat ), EE_FEATURE_FIELD)); + if ( eTimeFormat != SvxTimeFormat::AppDefault ) + { + std::unique_ptr xFieldItem(new SvxFieldItem(SvxExtTimeField( tools::Time( tools::Time::SYSTEM ), SvxTimeType::Var, eTimeFormat ), EE_FEATURE_FIELD)); + if (xField1) + xField2 = std::move(xFieldItem); + else + xField1 = std::move(xFieldItem); + } +} + +PPTTextObj::PPTTextObj( SvStream& rIn, SdrPowerPointImport& rSdrPowerPointImport, PptSlidePersistEntry& rPersistEntry, DffObjData const * pObjData ) : + mxImplTextObj ( new ImplPPTTextObj( rPersistEntry ) ) +{ + mxImplTextObj->mnShapeId = 0; + mxImplTextObj->mnShapeMaster = 0; + mxImplTextObj->mnDestinationInstance = mxImplTextObj->mnInstance = TSS_Type::TextInShape; + mxImplTextObj->mnCurrentObject = 0; + mxImplTextObj->mnParagraphCount = 0; + mxImplTextObj->mnTextFlags = 0; + mxImplTextObj->meShapeType = ( pObjData && pObjData->bShapeType ) ? pObjData->eShapeType : mso_sptMin; + + DffRecordHeader aExtParaHd; + aExtParaHd.nRecType = 0; // set empty + + + DffRecordHeader aShapeContainerHd; + ReadDffRecordHeader( rIn, aShapeContainerHd ); + + if ( !(( pObjData == nullptr ) || ( pObjData->bShapeType )) ) + return; + + PPTExtParaProv* pExtParaProv = rSdrPowerPointImport.m_pPPTStyleSheet->pExtParaProv.get(); + if ( pObjData ) + { + mxImplTextObj->mnShapeId = pObjData->nShapeId; + if ( pObjData->nSpFlags & ShapeFlag::HaveMaster ) + mxImplTextObj->mnShapeMaster = rSdrPowerPointImport.GetPropertyValue( DFF_Prop_hspMaster, 0 ); + } + // ClientData + if ( rSdrPowerPointImport.maShapeRecords.SeekToContent( rIn, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) ) + { + sal_uInt32 nOldPos = rIn.Tell(); + DffRecordHeader& aClientDataContainerHd = *rSdrPowerPointImport.maShapeRecords.Current(); + DffRecordHeader aPlaceHolderAtomHd; + if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_OEPlaceholderAtom, aClientDataContainerHd.GetRecEndFilePos(), &aPlaceHolderAtomHd ) ) + { + mxImplTextObj->mpPlaceHolderAtom.reset( new PptOEPlaceholderAtom ); + ReadPptOEPlaceholderAtom( rIn, *( mxImplTextObj->mpPlaceHolderAtom ) ); + } + rIn.Seek( nOldPos ); + DffRecordHeader aProgTagHd; + if ( SdrPowerPointImport::SeekToContentOfProgTag( 9, rIn, aClientDataContainerHd, aProgTagHd ) ) + { + ReadDffRecordHeader( rIn, aExtParaHd ); + } + } + + // ClientTextBox + if ( !rSdrPowerPointImport.maShapeRecords.SeekToContent( rIn, DFF_msofbtClientTextbox, SEEK_FROM_CURRENT_AND_RESTART ) ) + return; + + bool bStatus = true; + + + DffRecordHeader aClientTextBoxHd( *rSdrPowerPointImport.maShapeRecords.Current() ); + sal_uInt32 nTextRulerAtomOfs = 0; // case of zero -> this atom may be found in aClientDataContainerHd; + // case of -1 -> there is no atom of this kind + // else -> this is the fileofs where we can get it + + // checkout if this is a referenced + // textobj, if so the we will patch + // the ClientTextBoxHd for a + // equivalent one + DffRecordHeader aTextHd; + if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_OutlineTextRefAtom, aClientTextBoxHd.GetRecEndFilePos(), &aTextHd ) ) + { + sal_uInt32 nRefNum; + rIn.ReadUInt32( nRefNum ); + + if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextRulerAtom, aClientTextBoxHd.GetRecEndFilePos() ) ) + nTextRulerAtomOfs = rIn.Tell(); + else + nTextRulerAtomOfs = 0xffffffff; + + switch( rSdrPowerPointImport.m_eCurrentPageKind ) + { + case PPT_NOTEPAGE : + case PPT_MASTERPAGE : + case PPT_SLIDEPAGE : + break; + default : + bStatus = false; + } + if ( bStatus ) + { + sal_uInt32 nSlideId = rSdrPowerPointImport.GetCurrentPageId(); + if ( !nSlideId ) + bStatus = false; + else + { + if ( !aExtParaHd.nRecType ) + { + sal_uInt32 nOldPos = rIn.Tell(); + // try to locate the referenced ExtendedParaHd + DffRecordHeader* pHd = pExtParaProv-> + aExtendedPresRules.GetRecordHeader( PPT_PST_ExtendedParagraphHeaderAtom, + SEEK_FROM_CURRENT_AND_RESTART ); + DffRecordHeader aPresRuleHd; + DffRecordHeader* pFirst = pHd; + + while ( pHd ) + { + pHd->SeekToContent( rIn ); + sal_uInt32 nTmpSlideId(0), nTmpRef; + rIn.ReadUInt32( nTmpSlideId ) + .ReadUInt32( nTmpRef ); // this seems to be the instance + + if ( ( nTmpSlideId == nSlideId ) && ( pHd->nRecInstance == nRefNum ) ) + { + if (!pHd->SeekToEndOfRecord(rIn)) + break; + ReadDffRecordHeader( rIn, aPresRuleHd ); + if ( aPresRuleHd.nRecType == PPT_PST_ExtendedParagraphAtom ) + { + aExtParaHd = aPresRuleHd; + break; + } + } + pHd = pExtParaProv-> + aExtendedPresRules.GetRecordHeader( PPT_PST_ExtendedParagraphHeaderAtom, + SEEK_FROM_CURRENT_AND_RESTART ); + if ( pHd == pFirst ) + break; + } + rIn.Seek( nOldPos ); + } + // now pHd points to the right SlideListWithText Container + PptSlidePersistList* pPageList = rSdrPowerPointImport.GetPageList( rSdrPowerPointImport.m_eCurrentPageKind ); + PptSlidePersistEntry* pE = nullptr; + if ( pPageList && ( rSdrPowerPointImport.m_nCurrentPageNum < pPageList->size() ) ) + pE = &(*pPageList)[ rSdrPowerPointImport.m_nCurrentPageNum ]; + if ( (!pE) || (!pE->nSlidePersistStartOffset) || ( pE->aPersistAtom.nSlideId != nSlideId ) ) + bStatus = false; + else + { + auto nOffset(pE->nSlidePersistStartOffset); + bStatus = (nOffset == rIn.Seek(nOffset)); + // now we got the right page and are searching for the right + // TextHeaderAtom + auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pE->nSlidePersistEndOffset); + while (bStatus && rIn.Tell() < nEndRecPos) + { + ReadDffRecordHeader( rIn, aClientTextBoxHd ); + if ( aClientTextBoxHd.nRecType == PPT_PST_TextHeaderAtom ) + { + if ( aClientTextBoxHd.nRecInstance == nRefNum ) + { + aClientTextBoxHd.SeekToEndOfRecord( rIn ); + break; + } + } + if (!aClientTextBoxHd.SeekToEndOfRecord(rIn)) + break; + } + if ( rIn.Tell() > pE->nSlidePersistEndOffset ) + bStatus = false; + else + { // patching the RecordHeader + aClientTextBoxHd.nFilePos -= DFF_COMMON_RECORD_HEADER_SIZE; + aClientTextBoxHd.nRecLen += DFF_COMMON_RECORD_HEADER_SIZE; + aClientTextBoxHd.nRecType = DFF_msofbtClientTextbox; + aClientTextBoxHd.nRecVer = DFF_PSFLAG_CONTAINER; + + // we have to calculate the correct record len + DffRecordHeader aTmpHd; + nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pE->nSlidePersistEndOffset); + while (rIn.Tell() < nEndRecPos) + { + ReadDffRecordHeader( rIn, aTmpHd ); + if ( ( aTmpHd.nRecType == PPT_PST_SlidePersistAtom ) || ( aTmpHd.nRecType == PPT_PST_TextHeaderAtom ) ) + break; + if (!aTmpHd.SeekToEndOfRecord(rIn)) + break; + aClientTextBoxHd.nRecLen += aTmpHd.nRecLen + DFF_COMMON_RECORD_HEADER_SIZE; + } + aClientTextBoxHd.SeekToContent( rIn ); + } + } + } + } + } + + if ( !bStatus ) + return; + + if ( !SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextHeaderAtom, aClientTextBoxHd.GetRecEndFilePos(), &aTextHd ) ) + return; + + // TextHeaderAtom is always the first Atom + sal_uInt16 nTmp(0); + rIn.ReadUInt16(nTmp); // this number tells us the TxMasterStyleAtom Instance + if (nTmp > 8) + nTmp = 4; + TSS_Type nInstance = static_cast(nTmp); + aTextHd.SeekToEndOfRecord( rIn ); + mxImplTextObj->mnInstance = nInstance; + + sal_uInt32 nFilePos = rIn.Tell(); + if ( !(rSdrPowerPointImport.SeekToRec2( PPT_PST_TextBytesAtom, + PPT_PST_TextCharsAtom, + aClientTextBoxHd.GetRecEndFilePos() ) + || SvxMSDffManager::SeekToRec( rIn, + PPT_PST_StyleTextPropAtom, + aClientTextBoxHd.GetRecEndFilePos() )) ) + return; + + PPTTextRulerInterpreter aTextRulerInterpreter( nTextRulerAtomOfs, aClientTextBoxHd, rIn ); + + PPTStyleTextPropReader aStyleTextPropReader( rIn, aClientTextBoxHd, + aTextRulerInterpreter, aExtParaHd, nInstance ); + sal_uInt32 nParagraphs = mxImplTextObj->mnParagraphCount = aStyleTextPropReader.aParaPropList.size(); + if ( !nParagraphs ) + return; + + // the language settings will be merged into the list of PPTCharPropSet + DffRecordHeader aTextSpecInfoHd; + PPTTextSpecInfoAtomInterpreter aTextSpecInfoAtomInterpreter; + if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextSpecInfoAtom, + aClientTextBoxHd.GetRecEndFilePos(), &aTextSpecInfoHd ) ) + { + if ( aTextSpecInfoAtomInterpreter.Read( rIn, aTextSpecInfoHd, PPT_PST_TextSpecInfoAtom, + &(rSdrPowerPointImport.m_pPPTStyleSheet->maTxSI) ) ) + { + size_t nI = 0; + for (const PPTTextSpecInfo& rSpecInfo : aTextSpecInfoAtomInterpreter.aList) + { + sal_uInt32 nCharIdx = rSpecInfo.nCharIdx; + + // portions and text have to been split in some cases + for ( ; nI < aStyleTextPropReader.aCharPropList.size(); ++nI) + { + PPTCharPropSet* pSet = aStyleTextPropReader.aCharPropList[nI].get(); + if (pSet->mnOriginalTextPos >= nCharIdx) + break; + pSet->mnLanguage[0] = rSpecInfo.nLanguage[0]; + pSet->mnLanguage[1] = rSpecInfo.nLanguage[1]; + pSet->mnLanguage[2] = rSpecInfo.nLanguage[2]; + // test if the current portion needs to be split + if (pSet->maString.getLength() <= 1) + continue; + sal_Int32 nIndexOfNextPortion = pSet->maString.getLength() + pSet->mnOriginalTextPos; + sal_Int32 nNewLen = nIndexOfNextPortion - nCharIdx; + if (nNewLen <= 0) + continue; + sal_Int32 nOldLen = pSet->maString.getLength() - nNewLen; + if (nOldLen <= 0) + continue; + OUString aString(pSet->maString); + PPTCharPropSet* pNew = new PPTCharPropSet(*pSet); + pSet->maString = aString.copy(0, nOldLen); + pNew->maString = aString.copy(nOldLen, nNewLen); + pNew->mnOriginalTextPos += nOldLen; + aStyleTextPropReader.aCharPropList.emplace(aStyleTextPropReader.aCharPropList.begin() + nI + 1, pNew); + } + } + } +#ifdef DBG_UTIL + else + { + if (!(rSdrPowerPointImport.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT)) + { + OSL_FAIL( "SdrTextSpecInfoAtomInterpreter::Ctor(): parsing error, this document needs to be analysed (SJ)" ); + } + } +#endif + } + // now will search for possible textextensions such as date/time fields + // or ParaTabStops and append them on this textobj + rIn.Seek( nFilePos ); + ::std::vector< std::unique_ptr > FieldList; + auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, aClientTextBoxHd.GetRecEndFilePos()); + while (rIn.Tell() < nEndRecPos) + { + ReadDffRecordHeader( rIn, aTextHd ); + sal_uInt16 nVal = 0; + std::unique_ptr xEntry; + switch ( aTextHd.nRecType ) + { + case PPT_PST_DateTimeMCAtom : + { + xEntry.reset(new PPTFieldEntry); + rIn.ReadUInt16(xEntry->nPos) + .ReadUInt16( nVal ) + .ReadUInt16( nVal ); + xEntry->SetDateTime( nVal & 0xff ); + } + break; + + case PPT_PST_FooterMCAtom : + { + xEntry.reset(new PPTFieldEntry); + rIn.ReadUInt16(xEntry->nPos); + xEntry->xField1.reset(new SvxFieldItem(SvxFooterField(), EE_FEATURE_FIELD)); + } + break; + + case PPT_PST_HeaderMCAtom : + { + xEntry.reset(new PPTFieldEntry); + rIn.ReadUInt16(xEntry->nPos); + xEntry->xField1.reset(new SvxFieldItem(SvxHeaderField(), EE_FEATURE_FIELD)); + } + break; + + case PPT_PST_GenericDateMCAtom : + { + xEntry.reset(new PPTFieldEntry); + rIn.ReadUInt16(xEntry->nPos); + xEntry->xField1.reset(new SvxFieldItem(SvxDateTimeField(), EE_FEATURE_FIELD)); + if (rPersistEntry.xHeaderFooterEntry) // sj: #i34111# on master pages it is possible + { // that there is no HeaderFooterEntry available + if (rPersistEntry.xHeaderFooterEntry->nAtom & 0x20000) // auto date time + xEntry->SetDateTime(rPersistEntry.xHeaderFooterEntry->nAtom & 0xff); + else + xEntry->xString = rPersistEntry.xHeaderFooterEntry->pPlaceholder[nVal]; + } + } + break; + + case PPT_PST_SlideNumberMCAtom : + case PPT_PST_RTFDateTimeMCAtom : + { + xEntry.reset(new PPTFieldEntry); + if ( aTextHd.nRecLen >= 4 ) + { + rIn.ReadUInt16(xEntry->nPos) + .ReadUInt16( nVal ); + + // evaluate ID + //SvxFieldItem* pFieldItem = NULL; + switch( aTextHd.nRecType ) + { + case PPT_PST_SlideNumberMCAtom: + xEntry->xField1.reset(new SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD)); + break; + + case PPT_PST_RTFDateTimeMCAtom: + { + // Rude workaround for one special case reported + // by a customer. (#i75203#) + + // Don't even attempt to handle the general use + // case for PPT_PST_RTFDateTimeMCAtom (a generic + // MS style date/time format string). Just handle + // the special case where the format string + // contains only one or several possibly empty + // quoted strings. I.e. something that doesn't + // expand to any date or time at all, but to a + // fixed string. How on earth somebody manages to + // produce such things in PPT slides I have no + // idea. + if (nVal == 0) + { + OUStringBuffer aStr; + bool inquote = false; + for (int nLen = 0; nLen < 64; ++nLen) + { + sal_Unicode n(0); + rIn.ReadUtf16( n ); + + // Collect quoted characters into aStr + if ( n == '\'') + inquote = !inquote; + else if (!n) + { + // End of format string + xEntry->xString = aStr.makeStringAndClear(); + break; + } + else if (!inquote) + { + // Non-quoted character, i.e. a real + // format specifier. We don't handle + // those. Sorry. + break; + } + else + { + aStr.append(OUStringChar(n)); + } + } + } + if (!xEntry->xString) + { + // Handle as previously + xEntry->xField1.reset(new SvxFieldItem( SvxDateField( Date( Date::SYSTEM ), SvxDateType::Fix ), EE_FEATURE_FIELD )); + } + } + } + } + } + break; + + case PPT_PST_InteractiveInfo : + { + DffRecordHeader aHdInteractiveInfoAtom; + if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_InteractiveInfoAtom, aTextHd.GetRecEndFilePos(), &aHdInteractiveInfoAtom ) ) + { + PptInteractiveInfoAtom aInteractiveInfoAtom; + ReadPptInteractiveInfoAtom( rIn, aInteractiveInfoAtom ); + for (const SdHyperlinkEntry& rHyperlink : rSdrPowerPointImport.m_aHyperList) + { + if ( rHyperlink.nIndex == aInteractiveInfoAtom.nExHyperlinkId ) + { + if (!aTextHd.SeekToEndOfRecord(rIn)) + { + break; + } + ReadDffRecordHeader( rIn, aTextHd ); + if ( aTextHd.nRecType != PPT_PST_TxInteractiveInfoAtom ) + { + aTextHd.SeekToBegOfRecord( rIn ); + continue; + } + else + { + sal_uInt32 nStartPos, nEndPos; + rIn.ReadUInt32( nStartPos ) + .ReadUInt32( nEndPos ); + if ( nEndPos ) + { + xEntry.reset(new PPTFieldEntry); + xEntry->nPos = static_cast(nStartPos); + xEntry->nTextRangeEnd = static_cast(nEndPos); + OUString aTarget( rHyperlink.aTarget ); + if ( !rHyperlink.aConvSubString.isEmpty() ) + { + aTarget += "#" + rHyperlink.aConvSubString; + } + xEntry->xField1.reset(new SvxFieldItem( SvxURLField( aTarget, OUString(), SvxURLFormat::Repr ), EE_FEATURE_FIELD )); + } + } + break; + } + } + } + } + break; + } + if (!aTextHd.SeekToEndOfRecord(rIn)) + break; + if (xEntry) + { + // sorting fields ( hi >> lo ) + auto it = std::find_if(FieldList.begin(), FieldList.end(), + [&xEntry](const std::unique_ptr& rxField) { + return rxField->nPos < xEntry->nPos; }); + if ( it != FieldList.end() ) { + FieldList.insert(it, std::move(xEntry)); + } else { + FieldList.push_back( std::move(xEntry)); + } + } + } + if ( !FieldList.empty() ) + { + auto FE = FieldList.begin(); + auto& aCharPropList = aStyleTextPropReader.aCharPropList; + + sal_Int32 i = nParagraphs - 1; + sal_Int32 n = aCharPropList.size() - 1; + + // at this point we just have a list of textportions(aCharPropList) + // the next while loop tries to resolve the list of fields(pFieldList) + while( ( FE < FieldList.end() ) && ( n >= 0 ) && ( i >= 0 ) ) + { + PPTCharPropSet* pSet = aCharPropList[n].get(); + OUString aString( pSet->maString ); + sal_uInt32 nCount = aString.getLength(); + sal_uInt32 nPos = pSet->mnOriginalTextPos + nCount; + while ( ( FE < FieldList.end() ) && nCount-- ) + { + nPos--; + FE = std::find_if(FE, FieldList.end(), + [&nPos](const std::unique_ptr& rxField) {return rxField->nPos <= nPos;}); + if (FE == FieldList.end()) + break; + + if ( (*FE)->nPos == nPos ) + { + if ( aString[nCount] == 0x2a ) + { + sal_uInt32 nBehind = aString.getLength() - ( nCount + 1 ); + pSet->maString.clear(); + if ( nBehind ) + { + PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet ); + pNewCPS->maString = aString.copy( nCount + 1, nBehind ); + aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS ); + } + if ( (*FE)->xField2 ) + { + PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet ); + pNewCPS->mpFieldItem = std::move((*FE)->xField2); + aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS ); + + pNewCPS = new PPTCharPropSet( *pSet ); + pNewCPS->maString = " "; + aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS ); + } + if ( nCount ) + { + PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet ); + pNewCPS->maString = aString.copy( 0, nCount ); + aCharPropList.emplace( aCharPropList.begin() + n++, pNewCPS ); + } + if ( (*FE)->xField1 ) + { + pSet->mpFieldItem = std::move((*FE)->xField1); + } + else if ( (*FE)->xString ) + pSet->maString = *(*FE)->xString; + } + else + { + if ( (*FE)->nTextRangeEnd ) // text range hyperlink + { + sal_uInt32 nHyperLen = (*FE)->nTextRangeEnd - nPos; + if ( nHyperLen ) + { + PPTCharPropSet* pBefCPS = nullptr; + if ( nCount ) + { + pBefCPS = new PPTCharPropSet( *pSet ); + pSet->maString = pSet->maString.copy(nCount); + } + sal_uInt32 nIdx = n; + sal_Int32 nHyperLenLeft = nHyperLen; + + while ( ( aCharPropList.size() > nIdx ) && nHyperLenLeft ) + { + // the textrange hyperlink can take more than 1 paragraph + // the solution here is to clone the hyperlink... + + PPTCharPropSet* pCurrent = aCharPropList[ nIdx ].get(); + sal_Int32 nNextStringLen = pCurrent->maString.getLength(); + + DBG_ASSERT( (*FE)->xField1, "missing field!" ); + if (!(*FE)->xField1) + break; + + const SvxURLField* pField = static_cast((*FE)->xField1->GetField()); + + pCurrent->mbIsHyperlink = true; + pCurrent->mnHylinkOrigColor = pCurrent->mpImplPPTCharPropSet->mnColor; + pCurrent->mbHardHylinkOrigColor = ( ( pCurrent->mpImplPPTCharPropSet->mnAttrSet >>PPT_CharAttr_FontColor ) & 1)>0; + + // add missing attribute to show underline property + pCurrent->mpImplPPTCharPropSet->mnAttrSet |= 1 << PPT_CharAttr_Underline; + pCurrent->mpImplPPTCharPropSet->mnFlags = 1 << PPT_CharAttr_Underline; + + if ( pCurrent->mpFieldItem ) + { + pCurrent->SetColor( PPT_COLSCHEME_A_UND_HYPERLINK ); + if ( dynamic_cast< const SvxURLField* >(pCurrent->mpFieldItem->GetField()) != nullptr) + break; + nHyperLenLeft--; + } + else if ( nNextStringLen ) + { + if ( nNextStringLen <= nHyperLenLeft ) + { + pCurrent->mpFieldItem.reset( new SvxFieldItem( SvxURLField( pField->GetURL(), pCurrent->maString, SvxURLFormat::Repr ), EE_FEATURE_FIELD ) ); + nHyperLenLeft -= nNextStringLen; + + if ( nHyperLenLeft ) + { + // if the next portion is in a higher paragraph, + // the textrange is to decrease (because of the LineBreak character) + if ( aCharPropList.size() > ( nIdx + 1 ) ) + { + PPTCharPropSet* pNext = aCharPropList[ nIdx + 1 ].get(); + if ( pNext->mnParagraph > pCurrent->mnParagraph ) + nHyperLenLeft--; + } + } + } + else + { + PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pCurrent ); + pNewCPS->maString = pCurrent->maString.copy( nHyperLenLeft,( nNextStringLen - nHyperLenLeft ) ); + aCharPropList.emplace( aCharPropList.begin() + nIdx + 1, pNewCPS ); + OUString aRepresentation = pCurrent->maString.copy( 0, nHyperLenLeft ); + pCurrent->mpFieldItem.reset( new SvxFieldItem( SvxURLField( pField->GetURL(), aRepresentation, SvxURLFormat::Repr ), EE_FEATURE_FIELD ) ); + nHyperLenLeft = 0; + } + pCurrent->maString.clear(); + pCurrent->SetColor( PPT_COLSCHEME_A_UND_HYPERLINK ); + } + nIdx++; + } + (*FE)->xField1.reset(); + + if ( pBefCPS ) + { + pBefCPS->maString = aString.copy( 0, nCount ); + aCharPropList.emplace( aCharPropList.begin() + n, pBefCPS ); + n++; + } + } + } + } + break; + } + } + n--; + } + } + mxImplTextObj->maParagraphList.resize( nParagraphs ); + for (size_t nCurCharPos = 0, nCurPos = 0; + nCurPos < aStyleTextPropReader.aParaPropList.size(); + ++nCurPos) + { + mxImplTextObj->maParagraphList[ nCurPos ].reset( + new PPTParagraphObj( + aStyleTextPropReader, nCurPos, nCurCharPos, + *rSdrPowerPointImport.m_pPPTStyleSheet, + nInstance, aTextRulerInterpreter ) ); + + sal_uInt32 nParaAdjust, nFlags = 0; + mxImplTextObj->maParagraphList[ nCurPos ]->GetAttrib( PPT_ParaAttr_Adjust, nParaAdjust, GetInstance() ); + + switch ( nParaAdjust ) + { + case 0 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT; break; + case 1 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER; break; + case 2 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT; break; + case 3 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK; break; + } + mxImplTextObj->mnTextFlags |= nFlags; + } +} + +PPTTextObj::PPTTextObj( PPTTextObj const & rTextObj ) +{ + mxImplTextObj = rTextObj.mxImplTextObj; +} + +PPTTextObj::~PPTTextObj() +{ +} + +PPTParagraphObj* PPTTextObj::First() +{ + mxImplTextObj->mnCurrentObject = 0; + if ( !mxImplTextObj->mnParagraphCount ) + return nullptr; + return mxImplTextObj->maParagraphList[ 0 ].get(); +} + +PPTParagraphObj* PPTTextObj::Next() +{ + sal_uInt32 i = mxImplTextObj->mnCurrentObject + 1; + if ( i >= mxImplTextObj->mnParagraphCount ) + return nullptr; + mxImplTextObj->mnCurrentObject++; + return mxImplTextObj->maParagraphList[ i ].get(); +} + +const SfxItemSet* PPTTextObj::GetBackground() const +{ + if ( mxImplTextObj->mrPersistEntry.pBObj ) + return &mxImplTextObj->mrPersistEntry.pBObj->GetMergedItemSet(); + else + return nullptr; +} + +PPTTextObj& PPTTextObj::operator=( const PPTTextObj& rTextObj ) +{ + if ( this != &rTextObj ) + { + mxImplTextObj = rTextObj.mxImplTextObj; + } + return *this; +} + +static bool IsLine( const SdrObject* pObj ) +{ + auto pSdrPathObj = dynamic_cast< const SdrPathObj* >(pObj); + return pSdrPathObj && pSdrPathObj->IsLine() && pSdrPathObj->GetPointCount() == 2; +} + +static bool GetCellPosition( const SdrObject* pObj, const o3tl::sorted_vector< sal_Int32 >& rRows, const o3tl::sorted_vector< sal_Int32 >& rColumns, + sal_Int32& nTableIndex, sal_Int32& nRow, sal_Int32& nRowCount, sal_Int32& nColumn, sal_Int32& nColumnCount ) +{ + tools::Rectangle aSnapRect( pObj->GetSnapRect() ); + bool bCellObject = ( aSnapRect.GetWidth() > 1 ) && ( aSnapRect.GetHeight() > 1 ); + if ( bCellObject ) + { + auto aRowIter = rRows.find( aSnapRect.Top() ); + auto aColumnIter = rColumns.find( aSnapRect.Left() ); + if ( ( aRowIter == rRows.end() ) || ( aColumnIter == rColumns.end() ) ) + bCellObject = false; + else + { + nRowCount = 1; + nRow = std::distance( rRows.begin(), aRowIter ); + while( ++aRowIter != rRows.end() ) + { + if ( *aRowIter >= aSnapRect.Bottom() ) + break; + nRowCount++; + } + nColumnCount = 1; + nColumn = std::distance( rColumns.begin(), aColumnIter ); + while( ++aColumnIter != rColumns.end() ) + { + if ( *aColumnIter >= aSnapRect.Right() ) + break; + nColumnCount++; + } + nTableIndex = nRow * rColumns.size() + nColumn; + } + } + return bCellObject; +} + +#define LinePositionLeft 0x01000000 +#define LinePositionTop 0x02000000 +#define LinePositionRight 0x04000000 +#define LinePositionBottom 0x08000000 +#define LinePositionTLBR 0x10000000 +#define LinePositionBLTR 0x20000000 + + +static void GetRowPositions( const tools::Rectangle& rSnapRect, const o3tl::sorted_vector< sal_Int32 >& rRows, + const o3tl::sorted_vector< sal_Int32 >& rColumns, std::vector< sal_Int32 >& rPositions, sal_Int32 nColumn, sal_Int32 nFlags ) +{ + auto aRow = rRows.find( rSnapRect.Top() ); + if ( aRow == rRows.end() ) + return; + + sal_Int32 nRow = std::distance( rRows.begin(), aRow ); + while( ( aRow != rRows.end() ) && ((*aRow) < rSnapRect.Bottom() ) ) + { + if ( nFlags & LinePositionLeft ) + rPositions.push_back( ( ( nRow * rColumns.size() ) + nColumn ) | LinePositionLeft ); + if ( nFlags & LinePositionRight ) + rPositions.push_back( ( ( nRow * rColumns.size() ) + ( nColumn - 1 ) ) | LinePositionRight ); + + ++nRow; + ++aRow; + } +} + + +static void GetColumnPositions( const tools::Rectangle& rSnapRect, + const o3tl::sorted_vector< sal_Int32 >& rColumns, std::vector< sal_Int32 >& rPositions, sal_Int32 nRow, sal_Int32 nFlags ) +{ + auto aColumn = rColumns.find( rSnapRect.Left() ); + if ( aColumn == rColumns.end() ) + return; + + sal_Int32 nColumn = std::distance( rColumns.begin(), aColumn ); + while( ( aColumn != rColumns.end() ) && ((*aColumn) < rSnapRect.Right() ) ) + { + if ( nFlags & LinePositionTop ) + rPositions.push_back( ( ( nRow * rColumns.size() ) + nColumn ) | LinePositionTop ); + if ( nFlags & LinePositionBottom ) + rPositions.push_back( ( ( ( nRow - 1 ) * rColumns.size() ) + nColumn ) | LinePositionBottom ); + + ++nColumn; + ++aColumn; + } +} + +static void GetLinePositions( const SdrObject* pObj, const o3tl::sorted_vector< sal_Int32 >& rRows, const o3tl::sorted_vector< sal_Int32 >& rColumns, + std::vector< sal_Int32 >& rPositions, const tools::Rectangle& rGroupSnap ) +{ + tools::Rectangle aSnapRect( pObj->GetSnapRect() ); + if ( aSnapRect.Left() == aSnapRect.Right() ) + { + auto aColumn = rColumns.find( aSnapRect.Left() ); + if ( ( aColumn != rColumns.end() ) || ( aSnapRect.Left() == rGroupSnap.Right() ) ) + { + sal_Int32 nColumn, nFlags; + if ( aColumn != rColumns.end() ) + { + nColumn = std::distance( rColumns.begin(), aColumn ); + nFlags = LinePositionLeft; + if ( aColumn != rColumns.begin() ) + nFlags |= LinePositionRight; + } + else + { + nColumn = rColumns.size(); + nFlags = LinePositionRight; + } + GetRowPositions( aSnapRect, rRows, rColumns, rPositions, nColumn, nFlags ); + } + } + else if ( aSnapRect.Top() == aSnapRect.Bottom() ) + { + auto aRow = rRows.find( aSnapRect.Top() ); + if ( ( aRow != rRows.end() ) || ( aSnapRect.Top() == rGroupSnap.Bottom() ) ) + { + sal_Int32 nRow, nFlags; + if ( aRow != rRows.end() ) + { + nRow = std::distance( rRows.begin(), aRow ); + nFlags = LinePositionTop; + if ( aRow != rRows.begin() ) + nFlags |= LinePositionBottom; + } + else + { + nRow = rRows.size(); + nFlags = LinePositionBottom; + } + GetColumnPositions( aSnapRect, rColumns, rPositions, nRow, nFlags ); + } + } + else + { + sal_uInt32 nPosition = 0; + Point aPt1( static_cast(pObj)->GetPoint( 0 ) ); + Point aPt2( static_cast(pObj)->GetPoint( 1 ) ); + if ( aPt1.X() < aPt2.X() ) + nPosition |= aPt1.Y() < aPt2.Y() ? LinePositionTLBR : LinePositionBLTR; + else + nPosition |= aPt1.Y() < aPt2.Y() ? LinePositionBLTR : LinePositionTLBR; + + auto aRow = rRows.find( std::min(aPt1.Y(), aPt2.Y() ) ); + auto aColumn = rColumns.find( std::min(aPt1.X(), aPt2.X() ) ); + if ( ( aRow != rRows.end() ) && ( aColumn != rColumns.end() ) ) + { + nPosition |= ( std::distance( rRows.begin(), aRow ) * rColumns.size() ) + std::distance( rColumns.begin(), aColumn ); + rPositions.push_back( nPosition ); + } + } +} + +static void CreateTableRows( const Reference< XTableRows >& xTableRows, const o3tl::sorted_vector< sal_Int32 >& rRows, sal_Int32 nTableBottom ) +{ + if ( rRows.size() > 1 ) + xTableRows->insertByIndex( 0, rRows.size() - 1 ); + + auto aIter = rRows.begin(); + sal_Int32 nLastPosition( *aIter ); + for ( sal_Int32 n = 0; n < xTableRows->getCount(); n++ ) + { + sal_Int32 nHeight; + if ( ++aIter != rRows.end() ) + { + if (o3tl::checked_sub(*aIter, nLastPosition, nHeight)) + throw lang::IllegalArgumentException(); + nLastPosition = *aIter; + } + else + { + if (o3tl::checked_sub(nTableBottom, nLastPosition, nHeight)) + throw lang::IllegalArgumentException(); + } + + Reference< XPropertySet > xPropSet( xTableRows->getByIndex( n ), UNO_QUERY_THROW ); + xPropSet->setPropertyValue( "Height", Any( nHeight ) ); + } +} + +static void CreateTableColumns( const Reference< XTableColumns >& xTableColumns, const o3tl::sorted_vector< sal_Int32 >& rColumns, sal_Int32 nTableRight ) +{ + if ( rColumns.size() > 1 ) + xTableColumns->insertByIndex( 0, rColumns.size() - 1 ); + + auto aIter = rColumns.begin(); + sal_Int32 nLastPosition( *aIter ); + for ( sal_Int32 n = 0; n < xTableColumns->getCount(); n++ ) + { + sal_Int32 nWidth; + if ( ++aIter != rColumns.end() ) + { + if (o3tl::checked_sub(*aIter, nLastPosition, nWidth)) + throw lang::IllegalArgumentException(); + nLastPosition = *aIter; + } + else + { + if (o3tl::checked_sub(nTableRight, nLastPosition, nWidth)) + throw lang::IllegalArgumentException(); + } + + Reference< XPropertySet > xPropSet( xTableColumns->getByIndex( n ), UNO_QUERY_THROW ); + xPropSet->setPropertyValue( "Width", Any( nWidth ) ); + } +} + +static void MergeCells( const Reference< XTable >& xTable, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan ) +{ + DBG_ASSERT( (nColSpan > 1) || (nRowSpan > 1), "nonsense parameter!!" ); + DBG_ASSERT( (nCol >= 0) && (nCol < xTable->getColumnCount()) && (nRow >= 0) && (nRow < xTable->getRowCount()), "the cell does not exists!!" ); + DBG_ASSERT( (nColSpan >= 1) && ((nCol + nColSpan - 1) < xTable->getColumnCount()), "nColSpan botch!" ); + DBG_ASSERT( (nRowSpan >= 1) && ((nRow + nRowSpan - 1) < xTable->getRowCount()), "nRowSpan botch!" ); + + if( xTable.is() ) try + { + Reference< XMergeableCellRange > xRange( xTable->createCursorByRange( xTable->getCellRangeByPosition( nCol, nRow,nCol + nColSpan - 1, nRow + nRowSpan - 1 ) ), UNO_QUERY_THROW ); + if( xRange->isMergeable() ) + xRange->merge(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("filter.ms"); + } +} + +static void ApplyCellAttributes( const SdrObject* pObj, Reference< XCell > const & xCell ) +{ + try + { + Reference< XPropertySet > xPropSet( xCell, UNO_QUERY_THROW ); + + const sal_Int32 nLeftDist(pObj->GetMergedItem(SDRATTR_TEXT_LEFTDIST).GetValue()); + const sal_Int32 nRightDist(pObj->GetMergedItem(SDRATTR_TEXT_RIGHTDIST).GetValue()); + const sal_Int32 nUpperDist(pObj->GetMergedItem(SDRATTR_TEXT_UPPERDIST).GetValue()); + const sal_Int32 nLowerDist(pObj->GetMergedItem(SDRATTR_TEXT_LOWERDIST).GetValue()); + xPropSet->setPropertyValue( "TextUpperDistance", Any( nUpperDist ) ); + xPropSet->setPropertyValue( "TextRightDistance", Any( nRightDist ) ); + xPropSet->setPropertyValue( "TextLeftDistance", Any( nLeftDist ) ); + xPropSet->setPropertyValue( "TextLowerDistance", Any( nLowerDist ) ); + + const SdrTextVertAdjust eTextVertAdjust(pObj->GetMergedItem(SDRATTR_TEXT_VERTADJUST).GetValue()); + drawing::TextVerticalAdjust eVA( drawing::TextVerticalAdjust_TOP ); + if ( eTextVertAdjust == SDRTEXTVERTADJUST_CENTER ) + eVA = drawing::TextVerticalAdjust_CENTER; + else if ( eTextVertAdjust == SDRTEXTVERTADJUST_BOTTOM ) + eVA = drawing::TextVerticalAdjust_BOTTOM; + xPropSet->setPropertyValue( "TextVerticalAdjust", Any( eVA ) ); + + //set textHorizontalAdjust and TextWritingMode attr + const sal_Int32 eHA(pObj->GetMergedItem(SDRATTR_TEXT_HORZADJUST).GetValue()); + const SvxFrameDirection eDirection = pObj->GetMergedItem(EE_PARA_WRITINGDIR).GetValue(); + xPropSet->setPropertyValue( "TextHorizontalAdjust" , Any( eHA ) ); + if ( eDirection == SvxFrameDirection::Vertical_RL_TB ) + {//vertical writing + xPropSet->setPropertyValue( "TextWritingMode" , Any( css::text::WritingMode_TB_RL ) ); + } + drawing::FillStyle eFillStyle(pObj->GetMergedItem( XATTR_FILLSTYLE ).GetValue()); + css::drawing::FillStyle eFS( css::drawing::FillStyle_NONE ); + switch( eFillStyle ) + { + case drawing::FillStyle_SOLID : + { + eFS = css::drawing::FillStyle_SOLID; + Color aFillColor( pObj->GetMergedItem( XATTR_FILLCOLOR ).GetColorValue() ); + xPropSet->setPropertyValue( "FillColor", Any( aFillColor ) ); + } + break; + case drawing::FillStyle_GRADIENT : + { + eFS = css::drawing::FillStyle_GRADIENT; + XGradient aXGradient(pObj->GetMergedItem(XATTR_FILLGRADIENT).GetGradientValue()); + + css::awt::Gradient aGradient; + aGradient.Style = aXGradient.GetGradientStyle(); + aGradient.StartColor = static_cast(aXGradient.GetStartColor()); + aGradient.EndColor = static_cast(aXGradient.GetEndColor()); + aGradient.Angle = static_cast(aXGradient.GetAngle()); + aGradient.Border = aXGradient.GetBorder(); + aGradient.XOffset = aXGradient.GetXOffset(); + aGradient.YOffset = aXGradient.GetYOffset(); + aGradient.StartIntensity = aXGradient.GetStartIntens(); + aGradient.EndIntensity = aXGradient.GetEndIntens(); + aGradient.StepCount = aXGradient.GetSteps(); + + xPropSet->setPropertyValue( "FillGradient", Any( aGradient ) ); + } + break; + case drawing::FillStyle_HATCH : + eFS = css::drawing::FillStyle_HATCH; + break; + case drawing::FillStyle_BITMAP : + { + eFS = css::drawing::FillStyle_BITMAP; + + const XFillBitmapItem & rXFillBitmapItem(pObj->GetMergedItem( XATTR_FILLBITMAP )); + uno::Reference xGraphic = rXFillBitmapItem.GetGraphicObject().GetGraphic().GetXGraphic(); + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + xPropSet->setPropertyValue("FillBitmap", uno::Any(xBitmap)); + + const XFillBmpStretchItem & rStretchItem(pObj->GetMergedItem( XATTR_FILLBMP_STRETCH )); + const XFillBmpTileItem & rTileItem(pObj->GetMergedItem( XATTR_FILLBMP_TILE )); + if( rTileItem.GetValue() ) + xPropSet->setPropertyValue("FillBitmapMode", uno::Any(drawing::BitmapMode_REPEAT)); + else if( rStretchItem.GetValue() ) + xPropSet->setPropertyValue("FillBitmapMode", uno::Any(drawing::BitmapMode_STRETCH)); + else + xPropSet->setPropertyValue("FillBitmapMode", uno::Any(drawing::BitmapMode_NO_REPEAT)); + } + break; + default: + case drawing::FillStyle_NONE : + eFS = css::drawing::FillStyle_NONE; + break; + + } + xPropSet->setPropertyValue( "FillStyle", Any( eFS ) ); + if ( eFillStyle != drawing::FillStyle_NONE ) + { + sal_Int16 nFillTransparence( pObj->GetMergedItem( XATTR_FILLTRANSPARENCE ).GetValue() ); + xPropSet->setPropertyValue( "FillTransparence", Any( nFillTransparence ) ); + } + } + catch( const Exception& ) + { + } +} + +static void ApplyCellLineAttributes( const SdrObject* pLine, Reference< XTable > const & xTable, const std::vector< sal_Int32 >& vPositions, sal_Int32 nColumns ) +{ + try + { + drawing::LineStyle eLineStyle(pLine->GetMergedItem( XATTR_LINESTYLE ).GetValue()); + css::table::BorderLine2 aBorderLine; + switch( eLineStyle ) + { + case drawing::LineStyle_DASH : + case drawing::LineStyle_SOLID : + { + Color aLineColor( pLine->GetMergedItem( XATTR_LINECOLOR ).GetColorValue() ); + aBorderLine.Color = sal_Int32(aLineColor); + // Avoid width = 0, the min value should be 1. + sal_Int32 nLineWidth = std::max(sal_Int32(1), pLine->GetMergedItem(XATTR_LINEWIDTH) .GetValue() / 4); + aBorderLine.LineWidth = static_cast< sal_Int16 >( nLineWidth ); + aBorderLine.LineStyle = eLineStyle == drawing::LineStyle_SOLID ? table::BorderLineStyle::SOLID : table::BorderLineStyle::DASHED; + } + break; + default: + case drawing::LineStyle_NONE : + { + aBorderLine.LineWidth = 0; + aBorderLine.LineStyle = table::BorderLineStyle::NONE; + } + break; + } + for (auto const& vPos : vPositions) + { + sal_Int32 nPosition = vPos & 0xffffff; + sal_Int32 nFlags = vPos &~0xffffff; + sal_Int32 nRow = nPosition / nColumns; + sal_Int32 nColumn = nPosition - ( nRow * nColumns ); + Reference< XCell > xCell( xTable->getCellByPosition( nColumn, nRow ) ); + Reference< XPropertySet > xPropSet( xCell, UNO_QUERY_THROW ); + + if ( nFlags & LinePositionLeft ) + xPropSet->setPropertyValue( "LeftBorder", Any( aBorderLine ) ); + if ( nFlags & LinePositionTop ) + xPropSet->setPropertyValue( "TopBorder", Any( aBorderLine ) ); + if ( nFlags & LinePositionRight ) + xPropSet->setPropertyValue( "RightBorder", Any( aBorderLine ) ); + if ( nFlags & LinePositionBottom ) + xPropSet->setPropertyValue( "BottomBorder", Any( aBorderLine ) ); + if ( nFlags & LinePositionTLBR ) + xPropSet->setPropertyValue( "DiagonalTLBR", Any( true ) ); + if ( nFlags & LinePositionBLTR ) + xPropSet->setPropertyValue( "DiagonalBLTR", Any( true ) ); + } + } + catch( const Exception& ) + { + } +} + +SdrObject* SdrPowerPointImport::CreateTable(SdrObject* pGroup, const sal_uInt32* pTableArry, SvxMSDffSolverContainer* pSolverContainer, std::vector& rBackgroundColoredObjects) +{ + SdrObject* pRet = pGroup; + + sal_uInt32 nRows = pTableArry[ 1 ]; + if (!nRows) + return pRet; + + const SdrObjGroup* pObjGroup = dynamic_cast(pGroup); + if (!pObjGroup) + return pRet; + + SdrObjList* pSubList(pObjGroup->GetSubList()); + if (!pSubList) + return pRet; + + o3tl::sorted_vector< sal_Int32 > aRows; + o3tl::sorted_vector< sal_Int32 > aColumns; + + SdrObjListIter aGroupIter( pSubList, SdrIterMode::DeepNoGroups, false ); + while( aGroupIter.IsMore() ) + { + const SdrObject* pObj( aGroupIter.Next() ); + if ( !IsLine( pObj ) ) + { + tools::Rectangle aSnapRect( pObj->GetSnapRect() ); + aRows.insert( aSnapRect.Top() ); + aColumns.insert( aSnapRect.Left() ); + } + } + + if (aRows.empty()) + return pRet; + + sdr::table::SdrTableObj* pTable = new sdr::table::SdrTableObj(*pSdrModel); + pTable->uno_lock(); + Reference< XTable > xTable( pTable->getTable() ); + + try + { + CreateTableRows( xTable->getRows(), aRows, pGroup->GetSnapRect().Bottom() ); + CreateTableColumns( xTable->getColumns(), aColumns, pGroup->GetSnapRect().Right() ); + + sal_Int32 nCellCount = aRows.size() * aColumns.size(); + std::unique_ptr pMergedCellIndexTable(new sal_Int32[ nCellCount ]); + for ( sal_Int32 i = 0; i < nCellCount; i++ ) + pMergedCellIndexTable[ i ] = i; + + aGroupIter.Reset(); + while( aGroupIter.IsMore() ) + { + SdrObject* pObj( aGroupIter.Next() ); + if ( !IsLine( pObj ) ) + { + sal_Int32 nTableIndex = 0; + sal_Int32 nRow = 0; + sal_Int32 nRowCount = 0; + sal_Int32 nColumn = 0; + sal_Int32 nColumnCount = 0; + if ( GetCellPosition( pObj, aRows, aColumns, nTableIndex, nRow, nRowCount, nColumn, nColumnCount ) ) + { + Reference< XCell > xCell( xTable->getCellByPosition( nColumn, nRow ) ); + + ApplyCellAttributes( pObj, xCell ); + + if ( ( nRowCount > 1 ) || ( nColumnCount > 1 ) ) // cell merging + { + MergeCells( xTable, nColumn, nRow, nColumnCount, nRowCount ); + for ( sal_Int32 nRowIter = 0; nRowIter < nRowCount; nRowIter++ ) + { + for ( sal_Int32 nColumnIter = 0; nColumnIter < nColumnCount; nColumnIter++ ) + { // now set the correct index for the merged cell + pMergedCellIndexTable[ ( ( nRow + nRowIter ) * aColumns.size() ) + nColumn + nColumnIter ] = nTableIndex; + } + } + } + + // applying text + OutlinerParaObject* pParaObject = pObj->GetOutlinerParaObject(); + if ( pParaObject ) + { + SdrText* pSdrText = pTable->getText( nTableIndex ); + if ( pSdrText ) + pSdrText->SetOutlinerParaObject(*pParaObject); + } + } + } + } + aGroupIter.Reset(); + while( aGroupIter.IsMore() ) + { + SdrObject* pObj( aGroupIter.Next() ); + if ( IsLine( pObj ) ) + { + std::vector< sal_Int32 > vPositions; // containing cell indexes + cell position + GetLinePositions( pObj, aRows, aColumns, vPositions, pGroup->GetSnapRect() ); + + // correcting merged cell position + for (auto & vPos : vPositions) + { + sal_Int32 nOldPosition = vPos & 0xffff; + sal_Int32 nOldFlags = vPos & 0xffff0000; + sal_Int32 nNewPosition = pMergedCellIndexTable[ nOldPosition ] | nOldFlags; + vPos = nNewPosition; + } + ApplyCellLineAttributes( pObj, xTable, vPositions, aColumns.size() ); + } + } + pMergedCellIndexTable.reset(); + + // we are replacing the whole group object by a single table object, so + // possibly connections to the group object have to be removed. + if ( pSolverContainer ) + { + for (auto & pPtr : pSolverContainer->aCList) + { + // check connections to the group object + if ( pPtr->pAObj == pGroup ) + pPtr->pAObj = nullptr; + if ( pPtr->pBObj == pGroup ) + pPtr->pBObj = nullptr; + + // check connections to all its subobjects + SdrObjListIter aIter( *pGroup, SdrIterMode::DeepWithGroups ); + while( aIter.IsMore() ) + { + SdrObject* pPartObj = aIter.Next(); + if ( pPtr->pAObj == pPartObj ) + pPtr->pAObj = nullptr; + if ( pPtr->pBObj == pPartObj ) + pPtr->pBObj = nullptr; + } + //In MS, the one_row_one_col table is made up of five + //shape,the connector is connected to some part of a + //table. But for us, the connector is connected to the + //whole group table,so the connector obj is a group + //table when export by us. We should process this + //situation when importing. + if ( pPtr->pAObj == pGroup ) + pPtr->pAObj = pTable; + if ( pPtr->pBObj == pGroup ) + pPtr->pBObj = pTable; + } + } + pTable->uno_unlock(); + pTable->SetSnapRect( pGroup->GetSnapRect() ); + pRet = pTable; + + //Remove Objects from shape map + SdrObjListIter aIter( *pGroup, SdrIterMode::DeepWithGroups ); + while( aIter.IsMore() ) + { + SdrObject* pPartObj = aIter.Next(); + removeShapeId(pPartObj); + // ofz#41510 make sure rBackgroundColoredObjects doesn't contain deleted objects + std::replace(rBackgroundColoredObjects.begin(), rBackgroundColoredObjects.end(), pPartObj, pRet); + } + + SdrObject::Free( pGroup ); + } + catch( const Exception& ) + { + pTable->uno_unlock(); + SdrObject* pObj = pTable; + SdrObject::Free( pObj ); + } + + return pRet; +} + +bool SdrPowerPointImport::IsVerticalText() const +{ + bool bVerticalText = false; + if ( IsProperty( DFF_Prop_txflTextFlow ) ) + { + auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF; + switch( eTextFlow ) + { + case mso_txflTtoBA : // Top to Bottom @-font, above -> below + case mso_txflTtoBN : // Top to Bottom non-@, above -> below + case mso_txflVertN : // Vertical, non-@, above -> below + bVerticalText = !bVerticalText; + break; + default: break; + } + } + + return bVerticalText; +} + +void SdrPowerPointImport::ApplyTextAnchorAttributes( PPTTextObj const & rTextObj, SfxItemSet& rSet ) const +{ + SdrTextVertAdjust eTVA; + SdrTextHorzAdjust eTHA; + + sal_uInt32 nTextFlags = rTextObj.GetTextFlags(); + + nTextFlags &= PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT + | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK; + + if ( IsVerticalText() ) + { + eTVA = SDRTEXTVERTADJUST_BLOCK; + eTHA = SDRTEXTHORZADJUST_CENTER; + + // read text anchor + auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop); + + switch( eTextAnchor ) + { + case mso_anchorTop: + case mso_anchorTopCentered: + eTHA = SDRTEXTHORZADJUST_RIGHT; + break; + + case mso_anchorMiddle : + case mso_anchorMiddleCentered: + eTHA = SDRTEXTHORZADJUST_CENTER; + break; + + case mso_anchorBottom: + case mso_anchorBottomCentered: + eTHA = SDRTEXTHORZADJUST_LEFT; + break; + + default: + break; + } + // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction + switch ( eTextAnchor ) + { + case mso_anchorTopCentered : + case mso_anchorMiddleCentered : + case mso_anchorBottomCentered : + { + // check if it is sensible to use the centered alignment + sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT; + if ( ( nTextFlags & nMask ) != nMask ) // if the textobject has left or also right aligned paragraphs + eTVA = SDRTEXTVERTADJUST_CENTER; // the text has to be displayed using the full width; + } + break; + + default : + { + if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT ) + eTVA = SDRTEXTVERTADJUST_TOP; + else if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT ) + eTVA = SDRTEXTVERTADJUST_BOTTOM; + } + break; + } + } + else + { + eTVA = SDRTEXTVERTADJUST_CENTER; + eTHA = SDRTEXTHORZADJUST_BLOCK; + + // read text anchor + auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop); + + switch( eTextAnchor ) + { + case mso_anchorTop: + case mso_anchorTopCentered: + eTVA = SDRTEXTVERTADJUST_TOP; + break; + + case mso_anchorMiddle : + case mso_anchorMiddleCentered: + eTVA = SDRTEXTVERTADJUST_CENTER; + break; + + case mso_anchorBottom: + case mso_anchorBottomCentered: + eTVA = SDRTEXTVERTADJUST_BOTTOM; + break; + + default: + break; + } + + // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction + switch ( eTextAnchor ) + { + case mso_anchorTopCentered : + case mso_anchorMiddleCentered : + case mso_anchorBottomCentered : + { + // check if it is sensible to use the centered alignment + sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT; + if ( ( nTextFlags & nMask ) != nMask ) // if the textobject has left or also right aligned paragraphs + eTHA = SDRTEXTHORZADJUST_CENTER; // the text has to be displayed using the full width; + } + break; + + default : + { + if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT ) + eTHA = SDRTEXTHORZADJUST_LEFT; + else if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT ) + eTHA = SDRTEXTHORZADJUST_RIGHT; + } + break; + } + } + rSet.Put( SdrTextVertAdjustItem( eTVA ) ); + rSet.Put( SdrTextHorzAdjustItem( eTHA ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/svxmsbas2.cxx b/filter/source/msfilter/svxmsbas2.cxx new file mode 100644 index 000000000..8a4ce43f1 --- /dev/null +++ b/filter/source/msfilter/svxmsbas2.cxx @@ -0,0 +1,80 @@ +/* -*- 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 + +#include +#include +#include +#include +#include + +using namespace com::sun::star; + +ErrCode SvxImportMSVBasic::SaveOrDelMSVBAStorage( bool bSaveInto, + const OUString& rStorageName ) +{ + ErrCode nRet = ERRCODE_NONE; + uno::Reference < embed::XStorage > xSrcRoot( rDocSh.GetStorage() ); + OUString aDstStgName( GetMSBasicStorageName() ); + tools::SvRef xVBAStg( SotStorage::OpenOLEStorage( xSrcRoot, aDstStgName, + StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL ) ); + if( xVBAStg.is() && !xVBAStg->GetError() ) + { + xVBAStg = nullptr; + if( bSaveInto ) + { +#if HAVE_FEATURE_SCRIPTING + BasicManager *pBasicMan = rDocSh.GetBasicManager(); + if( pBasicMan && pBasicMan->IsBasicModified() ) + nRet = ERRCODE_SVX_MODIFIED_VBASIC_STORAGE; +#endif + tools::SvRef xSrc = SotStorage::OpenOLEStorage( xSrcRoot, aDstStgName, StreamMode::STD_READ ); + tools::SvRef xDst = xRoot->OpenSotStorage( rStorageName, StreamMode::READWRITE | StreamMode::TRUNC ); + xSrc->CopyTo( xDst.get() ); + xDst->Commit(); + ErrCode nError = xDst->GetError(); + if ( nError == ERRCODE_NONE ) + nError = xSrc->GetError(); + if ( nError != ERRCODE_NONE ) + xRoot->SetError( nError ); + } + } + + return nRet; +} + +// check if the MS-VBA-Storage exists in the RootStorage of the DocShell. +// If it exists, then return the WarningId for losing the information. +ErrCode SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( SfxObjectShell &rDocSh) +{ + uno::Reference < embed::XStorage > xSrcRoot( rDocSh.GetStorage() ); + tools::SvRef xVBAStg( SotStorage::OpenOLEStorage( xSrcRoot, GetMSBasicStorageName(), + StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL )); + return ( xVBAStg.is() && !xVBAStg->GetError() ) + ? ERRCODE_SVX_VBASIC_STORAGE_EXIST + : ERRCODE_NONE; +} + +OUString SvxImportMSVBasic::GetMSBasicStorageName() +{ + return "_MS_VBA_Macros"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/util.cxx b/filter/source/msfilter/util.cxx new file mode 100644 index 000000000..aea2f816b --- /dev/null +++ b/filter/source/msfilter/util.cxx @@ -0,0 +1,1340 @@ +/* -*- 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/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace msfilter::util { + +rtl_TextEncoding getBestTextEncodingFromLocale(const css::lang::Locale &rLocale) +{ + // Obviously not comprehensive, feel free to expand these, they're for ultimate fallbacks + // in last-ditch broken-file-format cases to guess the right 8bit encodings + const OUString &rLanguage = rLocale.Language; + if (rLanguage == "cs" || rLanguage == "hu" || rLanguage == "pl") + return RTL_TEXTENCODING_MS_1250; + if (rLanguage == "ru" || rLanguage == "uk") + return RTL_TEXTENCODING_MS_1251; + if (rLanguage == "el") + return RTL_TEXTENCODING_MS_1253; + if (rLanguage == "tr") + return RTL_TEXTENCODING_MS_1254; + if (rLanguage == "lt") + return RTL_TEXTENCODING_MS_1257; + if (rLanguage == "th") + return RTL_TEXTENCODING_MS_874; + if (rLanguage == "vi") + return RTL_TEXTENCODING_MS_1258; + return RTL_TEXTENCODING_MS_1252; +} + +::Color BGRToRGB(sal_uInt32 nColor) +{ + sal_uInt8 + r(static_cast(nColor&0xFF)), + g(static_cast((nColor>>8)&0xFF)), + b(static_cast((nColor>>16)&0xFF)), + t(static_cast((nColor>>24)&0xFF)); + return ::Color(ColorTransparency, t, r, g, b); +} + +DateTime DTTM2DateTime( tools::Long lDTTM ) +{ + /* + mint short :6 0000003F minutes (0-59) + hr short :5 000007C0 hours (0-23) + dom short :5 0000F800 days of month (1-31) + mon short :4 000F0000 months (1-12) + yr short :9 1FF00000 years (1900-2411)-1900 + wdy short :3 E0000000 weekday(Sunday=0 + Monday=1 + ( wdy can be ignored ) Tuesday=2 + Wednesday=3 + Thursday=4 + Friday=5 + Saturday=6) + */ + DateTime aDateTime(Date( 0 ), ::tools::Time( 0 )); + if( lDTTM ) + { + sal_uInt16 lMin = static_cast(lDTTM & 0x0000003F); + lDTTM >>= 6; + sal_uInt16 lHour= static_cast(lDTTM & 0x0000001F); + lDTTM >>= 5; + sal_uInt16 lDay = static_cast(lDTTM & 0x0000001F); + lDTTM >>= 5; + sal_uInt16 lMon = static_cast(lDTTM & 0x0000000F); + lDTTM >>= 4; + sal_uInt16 lYear= static_cast(lDTTM & 0x000001FF) + 1900; + aDateTime = DateTime(Date(lDay, lMon, lYear), tools::Time(lHour, lMin)); + } + return aDateTime; +} + +sal_Unicode bestFitOpenSymbolToMSFont(sal_Unicode cChar, + rtl_TextEncoding& rChrSet, OUString& rFontName) +{ + std::unique_ptr pConvert(CreateStarSymbolToMSMultiFont()); + OUString sFont = pConvert->ConvertChar(cChar); + pConvert.reset(); + if (!sFont.isEmpty()) + { + cChar = static_cast< sal_Unicode >(cChar | 0xF000); + rFontName = sFont; + rChrSet = RTL_TEXTENCODING_SYMBOL; + } + else if (cChar < 0xE000 || cChar > 0xF8FF) + { + /* + Ok we can't fit into a known windows unicode font, but + we are not in the private area, so we are a + standardized symbol, so turn off the symbol bit and + let words own font substitution kick in + */ + rChrSet = RTL_TEXTENCODING_UNICODE; + sal_Int32 nIndex = 0; + rFontName = ::GetNextFontToken(rFontName, nIndex); + } + else + { + /* + Well we don't have an available substitution, and we're + in our private area, so give up and show a standard + bullet symbol + */ + rFontName = "Wingdings"; + cChar = u'\x6C'; + } + return cChar; +} + + +OString ConvertColor( const Color &rColor ) +{ + static constexpr OStringLiteral AUTO( "auto" ); + + if ( rColor == COL_AUTO ) + return AUTO; + + const char pHexDigits[] = "0123456789ABCDEF"; + char pBuffer[] = "000000"; + + pBuffer[0] = pHexDigits[ ( rColor.GetRed() >> 4 ) & 0x0F ]; + pBuffer[1] = pHexDigits[ rColor.GetRed() & 0x0F ]; + pBuffer[2] = pHexDigits[ ( rColor.GetGreen() >> 4 ) & 0x0F ]; + pBuffer[3] = pHexDigits[ rColor.GetGreen() & 0x0F ]; + pBuffer[4] = pHexDigits[ ( rColor.GetBlue() >> 4 ) & 0x0F ]; + pBuffer[5] = pHexDigits[ rColor.GetBlue() & 0x0F ]; + + return OString( pBuffer ); +} + +OUString ConvertColorOU( const Color &rColor ) +{ + static constexpr OUStringLiteral AUTO( u"auto" ); + + if ( rColor == COL_AUTO ) + return AUTO; + + const char pHexDigits[] = "0123456789ABCDEF"; + sal_Unicode pBuffer[] = u"000000"; + + pBuffer[0] = pHexDigits[ ( rColor.GetRed() >> 4 ) & 0x0F ]; + pBuffer[1] = pHexDigits[ rColor.GetRed() & 0x0F ]; + pBuffer[2] = pHexDigits[ ( rColor.GetGreen() >> 4 ) & 0x0F ]; + pBuffer[3] = pHexDigits[ rColor.GetGreen() & 0x0F ]; + pBuffer[4] = pHexDigits[ ( rColor.GetBlue() >> 4 ) & 0x0F ]; + pBuffer[5] = pHexDigits[ rColor.GetBlue() & 0x0F ]; + + return OUString( pBuffer ); +} + +#define IN2MM100( v ) static_cast< sal_Int32 >( (v) * 2540.0 + 0.5 ) +#define MM2MM100( v ) static_cast< sal_Int32 >( (v) * 100.0 + 0.5 ) + +// see XclPaperSize pPaperSizeTable in calc and aDinTab in i18nutil +const ApiPaperSize spPaperSizeTable[] = +{ + { 0, 0 }, // 0 - (undefined) + { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 1 - Letter paper + { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 2 - Letter small paper + { IN2MM100( 11 ), IN2MM100( 17 ) }, // 3 - Tabloid paper + { IN2MM100( 17 ), IN2MM100( 11 ) }, // 4 - Ledger paper + { IN2MM100( 8.5 ), IN2MM100( 14 ) }, // 5 - Legal paper + { IN2MM100( 5.5 ), IN2MM100( 8.5 ) }, // 6 - Statement paper + { IN2MM100( 7.25 ), IN2MM100( 10.5 ) }, // 7 - Executive paper + { MM2MM100( 297 ), MM2MM100( 420 ) }, // 8 - A3 paper + { MM2MM100( 210 ), MM2MM100( 297 ) }, // 9 - A4 paper + { MM2MM100( 210 ), MM2MM100( 297 ) }, // 10 - A4 small paper + { MM2MM100( 148 ), MM2MM100( 210 ) }, // 11 - A5 paper + /* for JIS vs ISO B confusion see: + https://docs.microsoft.com/en-us/windows/win32/intl/paper-sizes + http://wiki.openoffice.org/wiki/DefaultPaperSize comments + http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf */ + { MM2MM100( 257 ), MM2MM100( 364 ) }, // 12 - B4 (JIS) paper + { MM2MM100( 182 ), MM2MM100( 257 ) }, // 13 - B5 (JIS) paper + { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 14 - Folio paper + { MM2MM100( 215 ), MM2MM100( 275 ) }, // 15 - Quarto paper + { IN2MM100( 10 ), IN2MM100( 14 ) }, // 16 - Standard paper + { IN2MM100( 11 ), IN2MM100( 17 ) }, // 17 - Standard paper + { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 18 - Note paper + { IN2MM100( 3.875 ), IN2MM100( 8.875 ) }, // 19 - #9 envelope + { IN2MM100( 4.125 ), IN2MM100( 9.5 ) }, // 20 - #10 envelope + { IN2MM100( 4.5 ), IN2MM100( 10.375 ) }, // 21 - #11 envelope + { IN2MM100( 4.75 ), IN2MM100( 11 ) }, // 22 - #12 envelope + { IN2MM100( 5 ), IN2MM100( 11.5 ) }, // 23 - #14 envelope + { IN2MM100( 17 ), IN2MM100( 22 ) }, // 24 - C paper + { IN2MM100( 22 ), IN2MM100( 34 ) }, // 25 - D paper + { IN2MM100( 34 ), IN2MM100( 44 ) }, // 26 - E paper + { MM2MM100( 110 ), MM2MM100( 220 ) }, // 27 - DL envelope + { MM2MM100( 162 ), MM2MM100( 229 ) }, // 28 - C5 envelope + { MM2MM100( 324 ), MM2MM100( 458 ) }, // 29 - C3 envelope + { MM2MM100( 229 ), MM2MM100( 324 ) }, // 30 - C4 envelope + { MM2MM100( 114 ), MM2MM100( 162 ) }, // 31 - C6 envelope + { MM2MM100( 114 ), MM2MM100( 229 ) }, // 32 - C65 envelope + { MM2MM100( 250 ), MM2MM100( 353 ) }, // 33 - B4 envelope + { MM2MM100( 176 ), MM2MM100( 250 ) }, // 34 - B5 envelope + { MM2MM100( 176 ), MM2MM100( 125 ) }, // 35 - B6 envelope + { MM2MM100( 110 ), MM2MM100( 230 ) }, // 36 - Italy envelope + { IN2MM100( 3.875 ), IN2MM100( 7.5 ) }, // 37 - Monarch envelope + { IN2MM100( 3.625 ), IN2MM100( 6.5 ) }, // 38 - 6 3/4 envelope + { IN2MM100( 14.875 ), IN2MM100( 11 ) }, // 39 - US standard fanfold + { IN2MM100( 8.5 ), IN2MM100( 12 ) }, // 40 - German standard fanfold + { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 41 - German legal fanfold + { MM2MM100( 250 ), MM2MM100( 353 ) }, // 42 - ISO B4 + { MM2MM100( 200 ), MM2MM100( 148 ) }, // 43 - Japanese double postcard + { IN2MM100( 9 ), IN2MM100( 11 ) }, // 44 - Standard paper + { IN2MM100( 10 ), IN2MM100( 11 ) }, // 45 - Standard paper + { IN2MM100( 15 ), IN2MM100( 11 ) }, // 46 - Standard paper + { MM2MM100( 220 ), MM2MM100( 220 ) }, // 47 - Invite envelope + { 0, 0 }, // 48 - (undefined) + { 0, 0 }, // 49 - (undefined) + /* See: https://docs.microsoft.com/en-us/windows/win32/intl/paper-sizes */ + { IN2MM100( 9.5 ), IN2MM100( 12 ) }, // 50 - Letter extra paper + { IN2MM100( 9.5 ), IN2MM100( 15 ) }, // 51 - Legal extra paper + { IN2MM100( 11.69 ), IN2MM100( 18 ) }, // 52 - Tabloid extra paper + { MM2MM100( 235 ), MM2MM100( 322 ) }, // 53 - A4 extra paper + { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 54 - Letter transverse paper + { MM2MM100( 210 ), MM2MM100( 297 ) }, // 55 - A4 transverse paper + { IN2MM100( 9.5 ), IN2MM100( 12 ) }, // 56 - Letter extra transverse paper + { MM2MM100( 227 ), MM2MM100( 356 ) }, // 57 - SuperA/SuperA/A4 paper + { MM2MM100( 305 ), MM2MM100( 487 ) }, // 58 - SuperB/SuperB/A3 paper + { IN2MM100( 8.5 ), IN2MM100( 12.69 ) }, // 59 - Letter plus paper + { MM2MM100( 210 ), MM2MM100( 330 ) }, // 60 - A4 plus paper + { MM2MM100( 148 ), MM2MM100( 210 ) }, // 61 - A5 transverse paper + { MM2MM100( 182 ), MM2MM100( 257 ) }, // 62 - JIS B5 transverse paper + { MM2MM100( 322 ), MM2MM100( 445 ) }, // 63 - A3 extra paper + { MM2MM100( 174 ), MM2MM100( 235 ) }, // 64 - A5 extra paper + { MM2MM100( 201 ), MM2MM100( 276 ) }, // 65 - ISO B5 extra paper + { MM2MM100( 420 ), MM2MM100( 594 ) }, // 66 - A2 paper + { MM2MM100( 297 ), MM2MM100( 420 ) }, // 67 - A3 transverse paper + { MM2MM100( 322 ), MM2MM100( 445 ) }, // 68 - A3 extra transverse paper + { MM2MM100( 200 ), MM2MM100( 148 ) }, // 69 - Japanese double postcard + { MM2MM100( 105 ), MM2MM100( 148 ), }, // 70 - A6 paper + { 0, 0 }, // 71 - Japanese Envelope Kaku #2 + { 0, 0 }, // 72 - Japanese Envelope Kaku #3 + { 0, 0 }, // 73 - Japanese Envelope Chou #3 + { 0, 0 }, // 74 - Japanese Envelope Chou #4 + { IN2MM100( 11 ), IN2MM100( 8.5 ) }, // 75 - Letter Rotated + { MM2MM100( 420 ), MM2MM100( 297 ) }, // 76 - A3 Rotated + { MM2MM100( 297 ), MM2MM100( 210 ) }, // 77 - A4 Rotated + { MM2MM100( 210 ), MM2MM100( 148 ) }, // 78 - A5 Rotated + { MM2MM100( 364 ), MM2MM100( 257 ) }, // 79 - B4 (JIS) Rotated + { MM2MM100( 257 ), MM2MM100( 182 ) }, // 80 - B5 (JIS) Rotated + { MM2MM100( 148 ), MM2MM100( 100 ) }, // 81 - Japanese Postcard Rotated + { MM2MM100( 148 ), MM2MM100( 200 ) }, // 82 - Double Japanese Postcard Rotated + { MM2MM100( 148 ), MM2MM100( 105 ) }, // 83 - A6 Rotated + { 0, 0 }, // 84 - Japanese Envelope Kaku #2 Rotated + { 0, 0 }, // 85 - Japanese Envelope Kaku #3 Rotated + { 0, 0 }, // 86 - Japanese Envelope Chou #3 Rotated + { 0, 0 }, // 87 - Japanese Envelope Chou #4 Rotated + { MM2MM100( 128 ), MM2MM100( 182 ) }, // 88 - B6 (JIS) + { MM2MM100( 182 ), MM2MM100( 128 ) }, // 89 - B6 (JIS) Rotated + { IN2MM100( 12 ), IN2MM100( 11 ) } // 90 - 12x11 +}; + +sal_Int32 PaperSizeConv::getMSPaperSizeIndex( const css::awt::Size& rSize ) +{ + // Need to find the best match for current size + sal_Int32 nDeltaWidth = 0; + sal_Int32 nDeltaHeight = 0; + + sal_Int32 nPaperSizeIndex = 0; // Undefined + const ApiPaperSize* pItem = spPaperSizeTable; + const ApiPaperSize* pEnd = spPaperSizeTable + SAL_N_ELEMENTS( spPaperSizeTable ); + for ( ; pItem != pEnd; ++pItem ) + { + sal_Int32 nCurDeltaHeight = std::abs( pItem->mnHeight - rSize.Height ); + sal_Int32 nCurDeltaWidth = std::abs( pItem->mnWidth - rSize.Width ); + if ( pItem == spPaperSizeTable ) // initialize delta with first item + { + nDeltaWidth = nCurDeltaWidth; + nDeltaHeight = nCurDeltaHeight; + } + else + { + if ( nCurDeltaWidth < nDeltaWidth && nCurDeltaHeight < nDeltaHeight ) + { + nDeltaWidth = nCurDeltaWidth; + nDeltaHeight = nCurDeltaHeight; + nPaperSizeIndex = (pItem - spPaperSizeTable); + } + } + } + sal_Int32 nTol = 10; // hmm not sure is this the best way + if ( nDeltaWidth <= nTol && nDeltaHeight <= nTol ) + return nPaperSizeIndex; + return 0; +} + +const ApiPaperSize& PaperSizeConv::getApiSizeForMSPaperSizeIndex( sal_Int32 nMSOPaperIndex ) +{ + if ( nMSOPaperIndex < 0 || nMSOPaperIndex > sal_Int32(SAL_N_ELEMENTS( spPaperSizeTable )) - 1 ) + return spPaperSizeTable[ 0 ]; + return spPaperSizeTable[ nMSOPaperIndex ]; +} + +std::u16string_view findQuotedText( std::u16string_view rCommand, + const char* cStartQuote, const sal_Unicode uEndQuote ) +{ + std::u16string_view sRet; + OUString sStartQuote( OUString::createFromAscii(cStartQuote) ); + size_t nStartIndex = rCommand.find( sStartQuote ); + if( nStartIndex != std::u16string_view::npos ) + { + sal_Int32 nStartLength = sStartQuote.getLength(); + size_t nEndIndex = rCommand.find( uEndQuote, nStartIndex + nStartLength); + if( nEndIndex != std::u16string_view::npos && nEndIndex > nStartIndex ) + { + sRet = rCommand.substr( nStartIndex + nStartLength, nEndIndex - nStartIndex - nStartLength); + } + } + return sRet; + +} + +WW8ReadFieldParams::WW8ReadFieldParams( OUString _aData ) + : aData(std::move( _aData )) + , nFnd( 0 ) + , nNext( 0 ) + , nSavPtr( 0 ) +{ + + /* + First look for an opening bracket or a space or a question mark or a backslash, so that the field (i.e. INCLUDEPICTURE or EINFUEGENGRAFIK or...) gets read over + */ + const sal_Int32 nLen = aData.getLength(); + + while ( nNextnFnd) + return OUString(); + else + { + return nSavPtr < nFnd ? aData.copy(nFnd) : aData.copy(nFnd, nSavPtr-nFnd); + } +} + + +bool WW8ReadFieldParams::GoToTokenParam() +{ + const sal_Int32 nOld = nNext; + if( -2 == SkipToNextToken() ) + return GetTokenSttPtr()>=0; + nNext = nOld; + return false; +} + +// ret: -2: NOT a '\' parameter but normal text +sal_Int32 WW8ReadFieldParams::SkipToNextToken() +{ + if ( nNext<0 || nNext>=aData.getLength() ) + return -1; + + nFnd = FindNextStringPiece(nNext); + if ( nFnd<0 ) + return -1; + + nSavPtr = nNext; + + if (nFnd+10 && (aData[nSavPtr-1]=='"' || aData[nSavPtr-1]==0x201d ) ) + { + --nSavPtr; + } + return -2; +} + +// FindNextPara searches the next backslash parameter or the next string +// until the next blank or "\" or closing quotation mark +// or the end of the string of pStr. +// +// Output ppNext (if ppNext != 0) search begin of next parameter resp. 0 +// +// Return value: 0 if end of string reached, +// otherwise beginning of the parameter resp. string +// +sal_Int32 WW8ReadFieldParams::FindNextStringPiece(const sal_Int32 nStart) +{ + const sal_Int32 nLen = aData.getLength(); + sal_Int32 n = nStart<0 ? nFnd : nStart; // start + sal_Int32 n2; // end + + nNext = -1; // if not found -> Default + + while ( n n2) + && (aData[n2] != '"') + && (aData[n2] != 0x201d) + && (aData[n2] != 147) + && (aData[n2] != 0x15) ) + n2++; // search for the end of the paragraph + } + else // no quotation mark + { + n2 = n; // search for the end from here on + while ( n2 OK + else + { + if( n2 > n ) + n2--; + break; // single backslash -> end + } + } + else + n2++; // no backslash -> OK + } + } + if( nLen > n2 ) + { + if (aData[n2]!=' ') ++n2; + nNext = n2; + } + return n; +} + + +// read parameters "1-3" or 1-3 with both values between 1 and nMax +bool WW8ReadFieldParams::GetTokenSttFromTo(sal_Int32* pFrom, sal_Int32* pTo, sal_Int32 nMax) +{ + sal_Int32 nStart = 0; + sal_Int32 nEnd = 0; + if ( GoToTokenParam() ) + { + + const OUString sParams( GetResult() ); + + sal_Int32 nIndex = 0; + const std::u16string_view sStart = o3tl::getToken(sParams, 0, '-', nIndex); + if (nIndex>=0) + { + nStart = o3tl::toInt32(sStart); + nEnd = o3tl::toInt32(sParams.subView(nIndex)); + } + } + if( pFrom ) *pFrom = nStart; + if( pTo ) *pTo = nEnd; + + return nStart && nEnd && (nMax >= nStart) && (nMax >= nEnd); +} + +static EquationResult Read_SubF_Combined(WW8ReadFieldParams& rReadParam) +{ + EquationResult aResult; + + OUString sCombinedCharacters; + WW8ReadFieldParams aOriFldParam = rReadParam; + const sal_Int32 cGetChar = rReadParam.SkipToNextToken(); + switch( cGetChar ) + { + case 'a': + case 'A': + if ( !rReadParam.GetResult().startsWithIgnoreAsciiCase("d") ) + { + break; + } + (void)rReadParam.SkipToNextToken(); + [[fallthrough]]; + case -2: + { + if ( rReadParam.GetResult().startsWithIgnoreAsciiCase("(") ) + { + for (int i=0;i<2;i++) + { + if ('s' == rReadParam.SkipToNextToken()) + { + const sal_Int32 cChar = rReadParam.SkipToNextToken(); + if (-2 != rReadParam.SkipToNextToken()) + break; + const OUString sF = rReadParam.GetResult(); + if ((('u' == cChar) && sF.startsWithIgnoreAsciiCase("p")) + || (('d' == cChar) && sF.startsWithIgnoreAsciiCase("o"))) + { + if (-2 == rReadParam.SkipToNextToken()) + { + OUString sPart = rReadParam.GetResult(); + sal_Int32 nBegin = sPart.indexOf('('); + + // Word disallows brackets in this field, which + // aids figuring out the case of an end of )) vs ) + sal_Int32 nEnd = sPart.indexOf(')'); + + if (nBegin != -1 && nEnd != -1) + { + sCombinedCharacters += + sPart.subView(nBegin+1,nEnd-nBegin-1); + } + } + } + } + } + if (!sCombinedCharacters.isEmpty()) + { + aResult.sType = "CombinedCharacters"; + aResult.sResult = sCombinedCharacters; + } + else + { + const OUString sPart = aOriFldParam.GetResult(); + sal_Int32 nBegin = sPart.indexOf('('); + sal_Int32 nEnd = sPart.indexOf(','); + if ( nEnd == -1 ) + { + nEnd = sPart.indexOf(')'); + } + if ( nBegin != -1 && nEnd != -1 ) + { + // skip certain leading characters + for (int i = nBegin;i < nEnd-1;i++) + { + const sal_Unicode cC = sPart[nBegin+1]; + if ( cC < 32 ) + { + nBegin++; + } + else + break; + } + sCombinedCharacters = sPart.copy( nBegin+1, nEnd-nBegin-1 ); + if ( !sCombinedCharacters.isEmpty() ) + { + aResult.sType = "Input"; + aResult.sResult = sCombinedCharacters; + } + } + } + } + break; + } + default: + break; + } + return aResult; +} + +EquationResult ParseCombinedChars(const OUString& rStr) +{ + EquationResult aResult; + WW8ReadFieldParams aReadParam( rStr ); + const sal_Int32 cChar = aReadParam.SkipToNextToken(); + if ('o' == cChar || 'O' == cChar) + aResult = Read_SubF_Combined(aReadParam); + return aResult; +} + +OString GetOOXMLPresetGeometry( std::u16string_view rShapeType ) +{ + typedef std::unordered_map CustomShapeTypeTranslationHashMap; + static const CustomShapeTypeTranslationHashMap aCustomShapeTypeTranslationHashMap{ + // { "non-primitive", mso_sptMin }, + { u"frame", "frame" }, + { u"rectangle", "rect" }, + { u"round-rectangle", "roundRect" }, + { u"ellipse", "ellipse" }, + { u"diamond", "diamond" }, + { u"isosceles-triangle", "triangle" }, + { u"right-triangle", "rtTriangle" }, + { u"parallelogram", "parallelogram" }, + { u"trapezoid", "trapezoid" }, + { u"hexagon", "hexagon" }, + { u"octagon", "octagon" }, + { u"cross", "plus" }, + { u"star5", "star5" }, + { u"right-arrow", "rightArrow" }, + // { u"mso-spt14", mso_sptThickArrow }, + { u"pentagon-right", "homePlate" }, + { u"cube", "cube" }, + // { u"mso-spt17", mso_sptBalloon }, + // { u"mso-spt18", mso_sptSeal }, + { u"mso-spt19", "arc" }, + { u"mso-spt20", "line" }, + { u"mso-spt21", "plaque" }, + { u"can", "can" }, + { u"ring", "donut" }, + { u"mso-spt24", "textPlain" }, + { u"mso-spt25", "textStop" }, + { u"mso-spt26", "textTriangle" }, + { u"mso-spt27", "textCanDown" }, + { u"mso-spt28", "textWave1" }, + { u"mso-spt29", "textArchUpPour" }, + { u"mso-spt30", "textCanDown" }, + { u"mso-spt31", "textArchUp" }, + { u"mso-spt32", "straightConnector1" }, + { u"mso-spt33", "bentConnector2" }, + { u"mso-spt34", "bentConnector3" }, + { u"mso-spt35", "bentConnector4" }, + { u"mso-spt36", "bentConnector5" }, + { u"mso-spt37", "curvedConnector2" }, + { u"mso-spt38", "curvedConnector3" }, + { u"mso-spt39", "curvedConnector4" }, + { u"mso-spt40", "curvedConnector5" }, + { u"mso-spt41", "callout1" }, + { u"mso-spt42", "callout2" }, + { u"mso-spt43", "callout3" }, + { u"mso-spt44", "accentCallout1" }, + { u"mso-spt45", "accentCallout2" }, + { u"mso-spt46", "accentCallout3" }, + { u"line-callout-1", "borderCallout1" }, + { u"line-callout-2", "borderCallout2" }, + { u"line-callout-3", "borderCallout3" }, + { u"mso-spt49", "borderCallout3" }, + { u"mso-spt50", "accentBorderCallout1" }, + { u"mso-spt51", "accentBorderCallout2" }, + { u"mso-spt52", "accentBorderCallout3" }, + { u"mso-spt53", "ribbon" }, + { u"mso-spt54", "ribbon2" }, + { u"chevron", "chevron" }, + { u"pentagon", "pentagon" }, + { u"forbidden", "noSmoking" }, + { u"star8", "star8" }, + { u"mso-spt59", "star16" }, + { u"mso-spt60", "star32" }, + { u"rectangular-callout", "wedgeRectCallout" }, + { u"round-rectangular-callout", "wedgeRoundRectCallout" }, + { u"round-callout", "wedgeEllipseCallout" }, + { u"mso-spt64", "wave" }, + { u"paper", "foldedCorner" }, + { u"left-arrow", "leftArrow" }, + { u"down-arrow", "downArrow" }, + { u"up-arrow", "upArrow" }, + { u"left-right-arrow", "leftRightArrow" }, + { u"up-down-arrow", "upDownArrow" }, + { u"mso-spt71", "irregularSeal1" }, + { u"bang", "irregularSeal2" }, + { u"lightning", "lightningBolt" }, + { u"heart", "heart" }, + { u"quad-arrow", "quadArrow" }, + { u"left-arrow-callout", "leftArrowCallout" }, + { u"right-arrow-callout", "rightArrowCallout" }, + { u"up-arrow-callout", "upArrowCallout" }, + { u"down-arrow-callout", "downArrowCallout" }, + { u"left-right-arrow-callout", "leftRightArrowCallout" }, + { u"up-down-arrow-callout", "upDownArrowCallout" }, + { u"quad-arrow-callout", "quadArrowCallout" }, + { u"quad-bevel", "bevel" }, + { u"left-bracket", "leftBracket" }, + { u"right-bracket", "rightBracket" }, + { u"left-brace", "leftBrace" }, + { u"right-brace", "rightBrace" }, + { u"mso-spt89", "leftUpArrow" }, + { u"mso-spt90", "bentUpArrow" }, + { u"mso-spt91", "bentArrow" }, + { u"star24", "star24" }, + { u"striped-right-arrow", "stripedRightArrow" }, + { u"notched-right-arrow", "notchedRightArrow" }, + { u"block-arc", "blockArc" }, + { u"smiley", "smileyFace" }, + { u"vertical-scroll", "verticalScroll" }, + { u"horizontal-scroll", "horizontalScroll" }, + { u"circular-arrow", "circularArrow" }, + { u"mso-spt100", "pie" }, // looks like MSO_SPT is wrong here + { u"mso-spt101", "uturnArrow" }, + { u"mso-spt102", "curvedRightArrow" }, + { u"mso-spt103", "curvedLeftArrow" }, + { u"mso-spt104", "curvedUpArrow" }, + { u"mso-spt105", "curvedDownArrow" }, + { u"cloud-callout", "cloudCallout" }, + { u"mso-spt107", "ellipseRibbon" }, + { u"mso-spt108", "ellipseRibbon2" }, + { u"flowchart-process", "flowChartProcess" }, + { u"flowchart-decision", "flowChartDecision" }, + { u"flowchart-data", "flowChartInputOutput" }, + { u"flowchart-predefined-process", "flowChartPredefinedProcess" }, + { u"flowchart-internal-storage", "flowChartInternalStorage" }, + { u"flowchart-document", "flowChartDocument" }, + { u"flowchart-multidocument", "flowChartMultidocument" }, + { u"flowchart-terminator", "flowChartTerminator" }, + { u"flowchart-preparation", "flowChartPreparation" }, + { u"flowchart-manual-input", "flowChartManualInput" }, + { u"flowchart-manual-operation", "flowChartManualOperation" }, + { u"flowchart-connector", "flowChartConnector" }, + { u"flowchart-card", "flowChartPunchedCard" }, + { u"flowchart-punched-tape", "flowChartPunchedTape" }, + { u"flowchart-summing-junction", "flowChartSummingJunction" }, + { u"flowchart-or", "flowChartOr" }, + { u"flowchart-collate", "flowChartCollate" }, + { u"flowchart-sort", "flowChartSort" }, + { u"flowchart-extract", "flowChartExtract" }, + { u"flowchart-merge", "flowChartMerge" }, + { u"mso-spt129", "flowChartOfflineStorage" }, + { u"flowchart-stored-data", "flowChartOnlineStorage" }, + { u"flowchart-sequential-access", "flowChartMagneticTape" }, + { u"flowchart-magnetic-disk", "flowChartMagneticDisk" }, + { u"flowchart-direct-access-storage", "flowChartMagneticDrum" }, + { u"flowchart-display", "flowChartDisplay" }, + { u"flowchart-delay", "flowChartDelay" }, + // { u"fontwork-plain-text", "textPlainText" }, + // { u"fontwork-stop", "textStop" }, + // { u"fontwork-triangle-up", "textTriangle" }, + // { u"fontwork-triangle-down", "textTriangleInverted" }, + // { u"fontwork-chevron-up", "textChevron" }, + // { u"fontwork-chevron-down", "textChevronInverted" }, + // { u"mso-spt142", "textRingInside" }, + // { u"mso-spt143", "textRingOutside" }, + // { u"fontwork-arch-up-curve", "textArchUpCurve" }, + // { u"fontwork-arch-down-curve", "textArchDownCurve" }, + // { u"fontwork-circle-curve", "textCircleCurve" }, + // { u"fontwork-open-circle-curve", "textButtonCurve" }, + // { u"fontwork-arch-up-pour", "textArchUpPour" }, + // { u"fontwork-arch-down-pour", "textArchDownPour" }, + // { u"fontwork-circle-pour", "textCirclePour" }, + // { u"fontwork-open-circle-pour", "textButtonPour" }, + // { u"fontwork-curve-up", "textCurveUp" }, + // { u"fontwork-curve-down", "textCurveDown" }, + // { u"fontwork-fade-up-and-right", "textCascadeUp" }, + // { u"fontwork-fade-up-and-left", "textCascadeDown" }, + // { u"fontwork-wave", "textWave1" }, + // { u"mso-spt157", "textWave2" }, + // { u"mso-spt158", "textWave3" }, + // { u"mso-spt159", "textWave4" }, + // { u"fontwork-inflate", "textInflate" }, + // { u"mso-spt161", "textDeflate" }, + // { u"mso-spt162", "textInflateBottom" }, + // { u"mso-spt163", "textDeflateBottom" }, + // { u"mso-spt164", "textInflateTop" }, + // { u"mso-spt165", "textDeflateTop" }, + // { u"mso-spt166", "textDeflateInflate" }, + // { u"mso-spt167", "textDeflateInflateDeflate" }, + // { u"fontwork-fade-right", "textFadeRight" }, + // { u"fontwork-fade-left", "textFadeLeft" }, + // { u"fontwork-fade-up", "textFadeUp" }, + // { u"fontwork-fade-down", "textFadeDown" }, + // { u"fontwork-slant-up", "textSlantUp" }, + // { u"fontwork-slant-down", "textSlantDown" }, + // { u"mso-spt174", "textCanUp" }, + // { u"mso-spt175", "textCanDown" }, + { u"flowchart-alternate-process", "flowChartAlternateProcess" }, + { u"flowchart-off-page-connector", "flowChartOffpageConnector" }, + { u"mso-spt178", "callout1" }, + { u"mso-spt179", "accentCallout1" }, + { u"mso-spt180", "borderCallout1" }, + { u"mso-spt182", "leftRightUpArrow" }, + { u"sun", "sun" }, + { u"moon", "moon" }, + { u"bracket-pair", "bracketPair" }, + { u"brace-pair", "bracePair" }, + { u"star4", "star4" }, + { u"mso-spt188", "doubleWave" }, + { u"mso-spt189", "actionButtonBlank" }, + { u"mso-spt190", "actionButtonHome" }, + { u"mso-spt191", "actionButtonHelp" }, + { u"mso-spt192", "actionButtonInformation" }, + { u"mso-spt193", "actionButtonForwardNext" }, + { u"mso-spt194", "actionButtonBackPrevious" }, + { u"mso-spt195", "actionButtonEnd" }, + { u"mso-spt196", "actionButtonBeginning" }, + { u"mso-spt197", "actionButtonReturn" }, + { u"mso-spt198", "actionButtonDocument" }, + { u"mso-spt199", "actionButtonSound" }, + { u"mso-spt200", "actionButtonMovie" }, + // { u"mso-spt201", "hostControl" }, + { u"mso-spt202", "rect" }, + { u"ooxml-actionButtonSound", "actionButtonSound" }, + { u"ooxml-borderCallout1", "borderCallout1" }, + { u"ooxml-plaqueTabs", "plaqueTabs" }, + { u"ooxml-curvedLeftArrow", "curvedLeftArrow" }, + { u"ooxml-octagon", "octagon" }, + { u"ooxml-leftRightRibbon", "leftRightRibbon" }, + { u"ooxml-actionButtonInformation", "actionButtonInformation" }, + { u"ooxml-bentConnector5", "bentConnector5" }, + { u"ooxml-circularArrow", "circularArrow" }, + { u"ooxml-downArrowCallout", "downArrowCallout" }, + { u"ooxml-mathMinus", "mathMinus" }, + { u"ooxml-gear9", "gear9" }, + { u"ooxml-round1Rect", "round1Rect" }, + { u"ooxml-sun", "sun" }, + { u"ooxml-plaque", "plaque" }, + { u"ooxml-chevron", "chevron" }, + { u"ooxml-flowChartPreparation", "flowChartPreparation" }, + { u"ooxml-diagStripe", "diagStripe" }, + { u"ooxml-pentagon", "pentagon" }, + { u"ooxml-funnel", "funnel" }, + { u"ooxml-chartStar", "chartStar" }, + { u"ooxml-accentBorderCallout1", "accentBorderCallout1" }, + { u"ooxml-notchedRightArrow", "notchedRightArrow" }, + { u"ooxml-rightBracket", "rightBracket" }, + { u"ooxml-flowChartOffpageConnector", "flowChartOffpageConnector" }, + { u"ooxml-leftRightArrow", "leftRightArrow" }, + { u"ooxml-decagon", "decagon" }, + { u"ooxml-actionButtonHelp", "actionButtonHelp" }, + { u"ooxml-star24", "star24" }, + { u"ooxml-mathDivide", "mathDivide" }, + { u"ooxml-curvedConnector4", "curvedConnector4" }, + { u"ooxml-flowChartOr", "flowChartOr" }, + { u"ooxml-borderCallout3", "borderCallout3" }, + { u"ooxml-upDownArrowCallout", "upDownArrowCallout" }, + { u"ooxml-flowChartDecision", "flowChartDecision" }, + { u"ooxml-leftRightArrowCallout", "leftRightArrowCallout" }, + { u"ooxml-flowChartManualOperation", "flowChartManualOperation" }, + { u"ooxml-snipRoundRect", "snipRoundRect" }, + { u"ooxml-mathPlus", "mathPlus" }, + { u"ooxml-actionButtonForwardNext", "actionButtonForwardNext" }, + { u"ooxml-can", "can" }, + { u"ooxml-foldedCorner", "foldedCorner" }, + { u"ooxml-star32", "star32" }, + { u"ooxml-flowChartInternalStorage", "flowChartInternalStorage" }, + { u"ooxml-upDownArrow", "upDownArrow" }, + { u"ooxml-irregularSeal2", "irregularSeal2" }, + { u"ooxml-mathEqual", "mathEqual" }, + { u"ooxml-star12", "star12" }, + { u"ooxml-uturnArrow", "uturnArrow" }, + { u"ooxml-squareTabs", "squareTabs" }, + { u"ooxml-leftRightUpArrow", "leftRightUpArrow" }, + { u"ooxml-homePlate", "homePlate" }, + { u"ooxml-dodecagon", "dodecagon" }, + { u"ooxml-leftArrowCallout", "leftArrowCallout" }, + { u"ooxml-chord", "chord" }, + { u"ooxml-quadArrowCallout", "quadArrowCallout" }, + { u"ooxml-actionButtonBeginning", "actionButtonBeginning" }, + { u"ooxml-ellipse", "ellipse" }, + { u"ooxml-actionButtonEnd", "actionButtonEnd" }, + { u"ooxml-arc", "arc" }, + { u"ooxml-star16", "star16" }, + { u"ooxml-parallelogram", "parallelogram" }, + { u"ooxml-bevel", "bevel" }, + { u"ooxml-roundRect", "roundRect" }, + { u"ooxml-accentCallout1", "accentCallout1" }, + { u"ooxml-flowChartSort", "flowChartSort" }, + { u"ooxml-star8", "star8" }, + { u"ooxml-flowChartAlternateProcess", "flowChartAlternateProcess" }, + { u"ooxml-moon", "moon" }, + { u"ooxml-star6", "star6" }, + { u"ooxml-round2SameRect", "round2SameRect" }, + { u"ooxml-nonIsoscelesTrapezoid", "nonIsoscelesTrapezoid" }, + { u"ooxml-diamond", "diamond" }, + { u"ooxml-ellipseRibbon", "ellipseRibbon" }, + { u"ooxml-callout2", "callout2" }, + { u"ooxml-pie", "pie" }, + { u"ooxml-star4", "star4" }, + { u"ooxml-flowChartPredefinedProcess", "flowChartPredefinedProcess" }, + { u"ooxml-flowChartPunchedTape", "flowChartPunchedTape" }, + { u"ooxml-curvedConnector2", "curvedConnector2" }, + { u"ooxml-bentConnector3", "bentConnector3" }, + { u"ooxml-cornerTabs", "cornerTabs" }, + { u"ooxml-hexagon", "hexagon" }, + { u"ooxml-flowChartConnector", "flowChartConnector" }, + { u"ooxml-flowChartMagneticDisk", "flowChartMagneticDisk" }, + { u"ooxml-heart", "heart" }, + { u"ooxml-ribbon2", "ribbon2" }, + { u"ooxml-bracePair", "bracePair" }, + { u"ooxml-flowChartExtract", "flowChartExtract" }, + { u"ooxml-actionButtonHome", "actionButtonHome" }, + { u"ooxml-accentBorderCallout3", "accentBorderCallout3" }, + { u"ooxml-flowChartOfflineStorage", "flowChartOfflineStorage" }, + { u"ooxml-irregularSeal1", "irregularSeal1" }, + { u"ooxml-quadArrow", "quadArrow" }, + { u"ooxml-leftBrace", "leftBrace" }, + { u"ooxml-leftBracket", "leftBracket" }, + { u"ooxml-blockArc", "blockArc" }, + { u"ooxml-curvedConnector3", "curvedConnector3" }, + { u"ooxml-wedgeRoundRectCallout", "wedgeRoundRectCallout" }, + { u"ooxml-actionButtonMovie", "actionButtonMovie" }, + { u"ooxml-flowChartOnlineStorage", "flowChartOnlineStorage" }, + { u"ooxml-gear6", "gear6" }, + { u"ooxml-halfFrame", "halfFrame" }, + { u"ooxml-snip2SameRect", "snip2SameRect" }, + { u"ooxml-triangle", "triangle" }, + { u"ooxml-teardrop", "teardrop" }, + { u"ooxml-flowChartDocument", "flowChartDocument" }, + { u"ooxml-rightArrowCallout", "rightArrowCallout" }, + { u"ooxml-rightBrace", "rightBrace" }, + { u"ooxml-chartPlus", "chartPlus" }, + { u"ooxml-flowChartManualInput", "flowChartManualInput" }, + { u"ooxml-flowChartMerge", "flowChartMerge" }, + { u"ooxml-line", "line" }, + { u"ooxml-downArrow", "downArrow" }, + { u"ooxml-upArrow", "upArrow" }, + { u"ooxml-curvedDownArrow", "curvedDownArrow" }, + { u"ooxml-actionButtonReturn", "actionButtonReturn" }, + { u"ooxml-flowChartInputOutput", "flowChartInputOutput" }, + { u"ooxml-bracketPair", "bracketPair" }, + { u"ooxml-smileyFace", "smileyFace" }, + { u"ooxml-actionButtonBlank", "actionButtonBlank" }, + { u"ooxml-wave", "wave" }, + { u"ooxml-swooshArrow", "swooshArrow" }, + { u"ooxml-flowChartSummingJunction", "flowChartSummingJunction" }, + { u"ooxml-lightningBolt", "lightningBolt" }, + { u"ooxml-flowChartDisplay", "flowChartDisplay" }, + { u"ooxml-actionButtonBackPrevious", "actionButtonBackPrevious" }, + { u"ooxml-frame", "frame" }, + { u"ooxml-rtTriangle", "rtTriangle" }, + { u"ooxml-flowChartMagneticTape", "flowChartMagneticTape" }, + { u"ooxml-curvedRightArrow", "curvedRightArrow" }, + { u"ooxml-leftUpArrow", "leftUpArrow" }, + { u"ooxml-wedgeEllipseCallout", "wedgeEllipseCallout" }, + { u"ooxml-doubleWave", "doubleWave" }, + { u"ooxml-bentArrow", "bentArrow" }, + { u"ooxml-star10", "star10" }, + { u"ooxml-leftArrow", "leftArrow" }, + { u"ooxml-curvedUpArrow", "curvedUpArrow" }, + { u"ooxml-snip1Rect", "snip1Rect" }, + { u"ooxml-ellipseRibbon2", "ellipseRibbon2" }, + { u"ooxml-plus", "plus" }, + { u"ooxml-accentCallout3", "accentCallout3" }, + { u"ooxml-leftCircularArrow", "leftCircularArrow" }, + { u"ooxml-rightArrow", "rightArrow" }, + { u"ooxml-flowChartPunchedCard", "flowChartPunchedCard" }, + { u"ooxml-snip2DiagRect", "snip2DiagRect" }, + { u"ooxml-verticalScroll", "verticalScroll" }, + { u"ooxml-star7", "star7" }, + { u"ooxml-chartX", "chartX" }, + { u"ooxml-cloud", "cloud" }, + { u"ooxml-cube", "cube" }, + { u"ooxml-round2DiagRect", "round2DiagRect" }, + { u"ooxml-flowChartMultidocument", "flowChartMultidocument" }, + { u"ooxml-actionButtonDocument", "actionButtonDocument" }, + { u"ooxml-flowChartTerminator", "flowChartTerminator" }, + { u"ooxml-flowChartDelay", "flowChartDelay" }, + { u"ooxml-curvedConnector5", "curvedConnector5" }, + { u"ooxml-horizontalScroll", "horizontalScroll" }, + { u"ooxml-bentConnector4", "bentConnector4" }, + { u"ooxml-leftRightCircularArrow", "leftRightCircularArrow" }, + { u"ooxml-wedgeRectCallout", "wedgeRectCallout" }, + { u"ooxml-accentCallout2", "accentCallout2" }, + { u"ooxml-flowChartMagneticDrum", "flowChartMagneticDrum" }, + { u"ooxml-corner", "corner" }, + { u"ooxml-borderCallout2", "borderCallout2" }, + { u"ooxml-donut", "donut" }, + { u"ooxml-flowChartCollate", "flowChartCollate" }, + { u"ooxml-mathNotEqual", "mathNotEqual" }, + { u"ooxml-bentConnector2", "bentConnector2" }, + { u"ooxml-mathMultiply", "mathMultiply" }, + { u"ooxml-heptagon", "heptagon" }, + { u"ooxml-rect", "rect" }, + { u"ooxml-accentBorderCallout2", "accentBorderCallout2" }, + { u"ooxml-pieWedge", "pieWedge" }, + { u"ooxml-upArrowCallout", "upArrowCallout" }, + { u"ooxml-flowChartProcess", "flowChartProcess" }, + { u"ooxml-star5", "star5" }, + { u"ooxml-lineInv", "lineInv" }, + { u"ooxml-straightConnector1", "straightConnector1" }, + { u"ooxml-stripedRightArrow", "stripedRightArrow" }, + { u"ooxml-callout3", "callout3" }, + { u"ooxml-bentUpArrow", "bentUpArrow" }, + { u"ooxml-noSmoking", "noSmoking" }, + { u"ooxml-trapezoid", "trapezoid" }, + { u"ooxml-cloudCallout", "cloudCallout" }, + { u"ooxml-callout1", "callout1" }, + { u"ooxml-ribbon", "ribbon" }, + { u"ooxml-rect", "rect" }, + }; + auto i(aCustomShapeTypeTranslationHashMap.find(rShapeType)); + return i == aCustomShapeTypeTranslationHashMap.end() ? "rect" : i->second; +} + +MSO_SPT GETVMLShapeType(std::u16string_view aType) +{ + typedef std::unordered_map DMLToVMLTranslationHashMap; + static const DMLToVMLTranslationHashMap aDMLToVMLMap{ + {"notPrimitive", mso_sptNotPrimitive}, + {"rectangle", mso_sptRectangle}, + {"roundRectangle", mso_sptRoundRectangle}, + {"ellipse", mso_sptEllipse}, + {"diamond", mso_sptDiamond}, + {"triangle", mso_sptIsocelesTriangle}, + {"rtTriangle", mso_sptRightTriangle}, + {"parallelogram", mso_sptParallelogram}, + {"trapezoid", mso_sptTrapezoid}, + {"hexagon", mso_sptHexagon}, + {"octagon", mso_sptOctagon}, + {"plus", mso_sptPlus}, + {"star5", mso_sptStar}, + {"rightArrow", mso_sptArrow}, + {"thickArrow", mso_sptThickArrow}, + {"homePlate", mso_sptHomePlate}, + {"cube", mso_sptCube}, + {"wedgeRoundRectCallout", mso_sptBalloon}, + {"star16", mso_sptSeal}, + {"arc", mso_sptArc}, + {"line", mso_sptLine}, + {"plaque", mso_sptPlaque}, + {"can", mso_sptCan}, + {"donut", mso_sptDonut}, + {"textPlain", mso_sptTextSimple}, + {"textStop", mso_sptTextOctagon}, + {"textTriangle", mso_sptTextHexagon}, + {"textCanDown", mso_sptTextCurve}, + {"textWave1", mso_sptTextWave}, + {"textArchUpPour", mso_sptTextRing}, + {"textCanDown", mso_sptTextOnCurve}, + {"textArchUp", mso_sptTextOnRing}, + {"straightConnector1", mso_sptStraightConnector1}, + {"bentConnector2", mso_sptBentConnector2}, + {"bentConnector3", mso_sptBentConnector3}, + {"bentConnector4", mso_sptBentConnector4}, + {"bentConnector5", mso_sptBentConnector5}, + {"curvedConnector2", mso_sptCurvedConnector2}, + {"curvedConnector3", mso_sptCurvedConnector3}, + {"curvedConnector4", mso_sptCurvedConnector4}, + {"curvedConnector5", mso_sptCurvedConnector5}, + {"callout1", mso_sptCallout1}, + {"callout2", mso_sptCallout2}, + {"callout3", mso_sptCallout3}, + {"accentCallout1", mso_sptAccentCallout1}, + {"accentCallout2", mso_sptAccentCallout2}, + {"accentCallout3", mso_sptAccentCallout3}, + {"borderCallout1", mso_sptBorderCallout1}, + {"borderCallout2", mso_sptBorderCallout2}, + {"borderCallout3", mso_sptBorderCallout3}, + {"accentBorderCallout1", mso_sptAccentBorderCallout1}, + {"accentBorderCallout2", mso_sptAccentBorderCallout2}, + {"accentBorderCallout3", mso_sptAccentBorderCallout3}, + {"ribbon", mso_sptRibbon}, + {"ribbon2", mso_sptRibbon2}, + {"chevron", mso_sptChevron}, + {"pentagon", mso_sptPentagon}, + {"noSmoking", mso_sptNoSmoking}, + {"star8", mso_sptSeal8}, + {"star16", mso_sptSeal16}, + {"star32", mso_sptSeal32}, + {"wedgeRectCallout", mso_sptWedgeRectCallout}, + {"wedgeRoundRectCallout", mso_sptWedgeRRectCallout}, + {"wedgeEllipseCallout", mso_sptWedgeEllipseCallout}, + {"wave", mso_sptWave}, + {"foldedCorner", mso_sptFoldedCorner}, + {"leftArrow", mso_sptLeftArrow}, + {"downArrow", mso_sptDownArrow}, + {"upArrow", mso_sptUpArrow}, + {"leftRightArrow", mso_sptLeftRightArrow}, + {"upDownArrow", mso_sptUpDownArrow}, + {"irregularSeal1", mso_sptIrregularSeal1}, + {"irregularSeal2", mso_sptIrregularSeal2}, + {"lightningBolt", mso_sptLightningBolt}, + {"heart", mso_sptHeart}, + {"pictureFrame", mso_sptPictureFrame}, + {"quadArrow", mso_sptQuadArrow}, + {"leftArrowCallout", mso_sptLeftArrowCallout}, + {"rightArrowCallout", mso_sptRightArrowCallout}, + {"upArrowCallout", mso_sptUpArrowCallout}, + {"downArrowCallout", mso_sptDownArrowCallout}, + {"leftRightArrowCallout", mso_sptLeftRightArrowCallout}, + {"upDownArrowCallout", mso_sptUpDownArrowCallout}, + {"quadArrowCallout", mso_sptQuadArrowCallout}, + {"bevel", mso_sptBevel}, + {"leftBracket", mso_sptLeftBracket}, + {"rightBracket", mso_sptRightBracket}, + {"leftBrace", mso_sptLeftBrace}, + {"rightBrace", mso_sptRightBrace}, + {"leftUpArrow", mso_sptLeftUpArrow}, + {"bentUpArrow", mso_sptBentUpArrow}, + {"bentArrow", mso_sptBentArrow}, + {"star24", mso_sptSeal24}, + {"stripedRightArrow", mso_sptStripedRightArrow}, + {"notchedRightArrow", mso_sptNotchedRightArrow}, + {"blockArc", mso_sptBlockArc}, + {"smileyFace", mso_sptSmileyFace}, + {"verticalScroll", mso_sptVerticalScroll}, + {"horizontalScroll", mso_sptHorizontalScroll}, + {"circularArrow", mso_sptCircularArrow}, + {"notchedCircularArrow", mso_sptNotchedCircularArrow}, + {"uturnArrow", mso_sptUturnArrow}, + {"curvedRightArrow", mso_sptCurvedRightArrow}, + {"curvedLeftArrow", mso_sptCurvedLeftArrow}, + {"curvedUpArrow", mso_sptCurvedUpArrow}, + {"curvedDownArrow", mso_sptCurvedDownArrow}, + {"cloudCallout", mso_sptCloudCallout}, + {"ellipseRibbon", mso_sptEllipseRibbon}, + {"ellipseRibbon2", mso_sptEllipseRibbon2}, + {"flowChartProcess", mso_sptFlowChartProcess}, + {"flowChartDecision", mso_sptFlowChartDecision}, + {"flowChartInputOutput", mso_sptFlowChartInputOutput}, + {"flowChartPredefinedProcess", mso_sptFlowChartPredefinedProcess}, + {"flowChartInternalStorage", mso_sptFlowChartInternalStorage}, + {"flowChartDocument", mso_sptFlowChartDocument}, + {"flowChartMultidocument", mso_sptFlowChartMultidocument}, + {"flowChartTerminator", mso_sptFlowChartTerminator}, + {"flowChartPreparation", mso_sptFlowChartPreparation}, + {"flowChartManualInput", mso_sptFlowChartManualInput}, + {"flowChartManualOperation", mso_sptFlowChartManualOperation}, + {"flowChartConnector", mso_sptFlowChartConnector}, + {"flowChartPunchedCard", mso_sptFlowChartPunchedCard}, + {"flowChartPunchedTape", mso_sptFlowChartPunchedTape}, + {"flowChartSummingJunction", mso_sptFlowChartSummingJunction}, + {"flowChartOr", mso_sptFlowChartOr}, + {"flowChartCollate", mso_sptFlowChartCollate}, + {"flowChartSort", mso_sptFlowChartSort}, + {"flowChartExtract", mso_sptFlowChartExtract}, + {"flowChartMerge", mso_sptFlowChartMerge}, + {"flowChartOfflineStorage", mso_sptFlowChartOfflineStorage}, + {"flowChartOnlineStorage", mso_sptFlowChartOnlineStorage}, + {"flowChartMagneticTape", mso_sptFlowChartMagneticTape}, + {"flowChartMagneticDisk", mso_sptFlowChartMagneticDisk}, + {"flowChartMagneticDrum", mso_sptFlowChartMagneticDrum}, + {"flowChartDisplay", mso_sptFlowChartDisplay}, + {"flowChartDelay", mso_sptFlowChartDelay}, + {"textPlain", mso_sptTextPlainText}, + {"textStop", mso_sptTextStop}, + {"textTriangle", mso_sptTextTriangle}, + {"textTriangleInverted", mso_sptTextTriangleInverted}, + {"textChevron", mso_sptTextChevron}, + {"textChevronInverted", mso_sptTextChevronInverted}, + {"textRingInside", mso_sptTextRingInside}, + {"textRingOutside", mso_sptTextRingOutside}, + {"textArchUp", mso_sptTextArchUpCurve}, + {"textArchDown", mso_sptTextArchDownCurve}, + {"textCircle", mso_sptTextCircleCurve}, + {"textButton", mso_sptTextButtonCurve}, + {"textArchUpPour", mso_sptTextArchUpPour}, + {"textArchDownPour", mso_sptTextArchDownPour}, + {"textCirclePour", mso_sptTextCirclePour}, + {"textButtonPour", mso_sptTextButtonPour}, + {"textCurveUp", mso_sptTextCurveUp}, + {"textCurveDown", mso_sptTextCurveDown}, + {"textCascadeUp", mso_sptTextCascadeUp}, + {"textCascadeDown", mso_sptTextCascadeDown}, + {"textWave1", mso_sptTextWave1}, + {"textWave2", mso_sptTextWave2}, + {"textWave3", mso_sptTextWave3}, + {"textWave4", mso_sptTextWave4}, + {"textInflate", mso_sptTextInflate}, + {"textDeflate", mso_sptTextDeflate}, + {"textInflateBottom", mso_sptTextInflateBottom}, + {"textDeflateBottom", mso_sptTextDeflateBottom}, + {"textInflateTop", mso_sptTextInflateTop}, + {"textDeflateTop", mso_sptTextDeflateTop}, + {"textDeflateInflate", mso_sptTextDeflateInflate}, + {"textDeflateInflateDeflate", mso_sptTextDeflateInflateDeflate}, + {"textFadeRight", mso_sptTextFadeRight}, + {"textFadeLeft", mso_sptTextFadeLeft}, + {"textFadeUp", mso_sptTextFadeUp}, + {"textFadeDown", mso_sptTextFadeDown}, + {"textSlantUp", mso_sptTextSlantUp}, + {"textSlantDown", mso_sptTextSlantDown}, + {"textCanUp", mso_sptTextCanUp}, + {"textCanDown", mso_sptTextCanDown}, + {"flowChartAlternateProcess", mso_sptFlowChartAlternateProcess}, + {"flowChartOffpageConnector", mso_sptFlowChartOffpageConnector}, + {"callout1", mso_sptCallout90}, + {"accentCallout1", mso_sptAccentCallout90}, + {"borderCallout1", mso_sptBorderCallout90}, + {"accentBorderCallout1", mso_sptAccentBorderCallout90}, + {"leftRightUpArrow", mso_sptLeftRightUpArrow}, + {"sun", mso_sptSun}, + {"moon", mso_sptMoon}, + {"bracketPair", mso_sptBracketPair}, + {"bracePair", mso_sptBracePair}, + {"star4", mso_sptSeal4}, + {"doubleWave", mso_sptDoubleWave}, + {"actionButtonBlank", mso_sptActionButtonBlank}, + {"actionButtonHome", mso_sptActionButtonHome}, + {"actionButtonHelp", mso_sptActionButtonHelp}, + {"actionButtonInformation", mso_sptActionButtonInformation}, + {"actionButtonForwardNext", mso_sptActionButtonForwardNext}, + {"actionButtonBackPrevious", mso_sptActionButtonBackPrevious}, + {"actionButtonEnd", mso_sptActionButtonEnd}, + {"actionButtonBeginning", mso_sptActionButtonBeginning}, + {"actionButtonReturn", mso_sptActionButtonReturn}, + {"actionButtonDocument", mso_sptActionButtonDocument}, + {"actionButtonSound", mso_sptActionButtonSound}, + {"actionButtonMovie", mso_sptActionButtonMovie}, + {"hostControl", mso_sptHostControl}, + {"textBox", mso_sptTextBox}, + }; + + auto i(aDMLToVMLMap.find(GetOOXMLPresetGeometry(aType))); + return i == aDMLToVMLMap.end() ? mso_sptNil : i->second; +} + +bool HasTextBoxContent(sal_uInt32 nShapeType) +{ + switch (nShapeType) + { + case ESCHER_ShpInst_TextPlainText: + case ESCHER_ShpInst_TextSlantUp: + case ESCHER_ShpInst_TextDeflateInflateDeflate: + return false; + default: + return true; + } +} + +namespace +{ + +// Scheme means pattern of chromatic values. +// [2,2,1] -> red and green are approximately equal and blue is the dominant color (e.g. blue) +// [1,1,1] -> all chromatic values are approximately equal (e.g. white, gray, black) +void CalculateScheme(const BitmapColor& rBitmapColor, std::vector &vScheme, sal_uInt16 nVariance) +{ + vScheme.resize(3,1); + if( rBitmapColor.GetRed() < rBitmapColor.GetGreen() + nVariance ) + ++vScheme[0]; + if( rBitmapColor.GetRed() < rBitmapColor.GetBlue() + nVariance ) + ++vScheme[0]; + if( rBitmapColor.GetGreen() < rBitmapColor.GetRed() + nVariance ) + ++vScheme[1]; + if( rBitmapColor.GetGreen() < rBitmapColor.GetBlue() + nVariance ) + ++vScheme[1]; + if( rBitmapColor.GetBlue() < rBitmapColor.GetRed() + nVariance ) + ++vScheme[2]; + if( rBitmapColor.GetBlue() < rBitmapColor.GetGreen() + nVariance ) + ++vScheme[2]; +} + +bool HasSimilarScheme(const BitmapColor& rBitmapColor1, const BitmapColor& rBitmapColor2, sal_uInt16 nVariance) +{ + std::vector vScheme1, vScheme2; + CalculateScheme(rBitmapColor1, vScheme1, nVariance); + CalculateScheme(rBitmapColor2, vScheme2, nVariance); + for( int i = 0; i < 3; ++i ) + { + if( vScheme1[i] != vScheme2[i] ) + return false; + } + return true; +} + +// Find the best match in the color palette using scheme of the input color +sal_uInt16 GetBestIndex(const BitmapPalette& rPalette, const BitmapColor& rBitmapColor) +{ + sal_uInt16 nReturn = 0; + sal_uInt16 nLastErr = SAL_MAX_UINT16; + bool bFound = false; + + // Prefer those colors which have similar scheme as the input + // Allow bigger and bigger variance of the schemes until we find + // a color in the palette with similar scheme. + for( sal_uInt16 nVariance = 0; nVariance <= 255; ++nVariance ) + { + for( sal_uInt16 i = 0; i < rPalette.GetEntryCount(); ++i ) + { + if( HasSimilarScheme(rBitmapColor, rPalette[i], nVariance) ) + { + const sal_uInt16 nActErr = rBitmapColor.GetColorError( rPalette[i] ); + if( nActErr < nLastErr ) + { + nLastErr = nActErr; + nReturn = i; + bFound = true; + } + } + } + if( bFound ) + return nReturn; + } + return nReturn; +} +} + +sal_uInt8 TransColToIco( const Color& rCol ) +{ + sal_uInt8 nCol = 0; // ->Auto + switch( sal_uInt32(rCol) ) + { + case sal_uInt32(COL_BLACK): nCol = 1; break; + case sal_uInt32(COL_BLUE): nCol = 9; break; + case sal_uInt32(COL_GREEN): nCol = 11; break; + case sal_uInt32(COL_CYAN): nCol = 10; break; + case sal_uInt32(COL_RED): nCol = 13; break; + case sal_uInt32(COL_MAGENTA): nCol = 12; break; + case sal_uInt32(COL_BROWN): nCol = 14; break; + case sal_uInt32(COL_GRAY): nCol = 15; break; + case sal_uInt32(COL_LIGHTGRAY): nCol = 16; break; + case sal_uInt32(COL_LIGHTBLUE): nCol = 2; break; + case sal_uInt32(COL_LIGHTGREEN): nCol = 4; break; + case sal_uInt32(COL_LIGHTCYAN): nCol = 3; break; + case sal_uInt32(COL_LIGHTRED): nCol = 6; break; + case sal_uInt32(COL_LIGHTMAGENTA): nCol = 5; break; + case sal_uInt32(COL_YELLOW): nCol = 7; break; + case sal_uInt32(COL_WHITE): nCol = 8; break; + case sal_uInt32(COL_AUTO): nCol = 0; break; + + default: + static const BitmapPalette aBmpPal { + COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN, + COL_LIGHTMAGENTA,COL_LIGHTRED, COL_YELLOW, COL_WHITE, + COL_BLUE, COL_CYAN, COL_GREEN, COL_MAGENTA, + COL_RED, COL_BROWN, COL_GRAY, COL_LIGHTGRAY + }; + + nCol = static_cast< sal_uInt8 >(GetBestIndex(aBmpPal, rCol) + 1); + break; + } + return nCol; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/msfilter/viscache.hxx b/filter/source/msfilter/viscache.hxx new file mode 100644 index 000000000..5111969b3 --- /dev/null +++ b/filter/source/msfilter/viscache.hxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ +#pragma once + +#include +#include +#include + +class SvStream; + +class Impl_OlePres +{ + SotClipboardFormatId nFormat; + sal_uInt16 nAspect; + std::unique_ptr + pMtf; + + sal_uInt32 nAdvFlags; + Size aSize; // size in 100TH_MM +public: + explicit Impl_OlePres() + : nFormat( SotClipboardFormatId::GDIMETAFILE ) + , nAspect( ASPECT_CONTENT ) + , nAdvFlags( 0x2 ) // found in document + {} + void SetMtf( const GDIMetaFile & rMtf ) + { + pMtf.reset( new GDIMetaFile( rMtf ) ); + } + void SetAspect( sal_uInt16 nAsp ) { nAspect = nAsp; } + void SetAdviseFlags( sal_uLong nAdv ) { nAdvFlags = nAdv; } + void SetSize( const Size & rSize ) { aSize = rSize; } + void Write( SvStream & rStm ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/odfflatxml/OdfFlatXml.cxx b/filter/source/odfflatxml/OdfFlatXml.cxx new file mode 100644 index 000000000..4d6005431 --- /dev/null +++ b/filter/source/odfflatxml/OdfFlatXml.cxx @@ -0,0 +1,260 @@ +/* -*- 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/. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::cppu; +using namespace ::osl; +using namespace ::sax; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; + +namespace filter::odfflatxml { + namespace { + + /* + * OdfFlatXml export and imports ODF flat XML documents by plugging a pass-through + * filter implementation into XmlFilterAdaptor. + */ + class OdfFlatXml : public WeakImplHelper + { + private: + Reference< XComponentContext > m_xContext; + + public: + + explicit OdfFlatXml(const Reference &r) : + m_xContext(r) + { + } + + // XImportFilter + virtual sal_Bool SAL_CALL + importer(const Sequence< PropertyValue >& sourceData, + const Reference< XDocumentHandler >& docHandler, + const Sequence< OUString >& userData) override; + + // XImportFilter2 + virtual sal_Bool SAL_CALL + importer(const Sequence< PropertyValue >& sourceData, + const Reference< XFastParser >& fastParser, + const Sequence< OUString >& userData) override; + + // XExportFilter + virtual sal_Bool SAL_CALL + exporter( + const Sequence< PropertyValue >& sourceData, + const Sequence< OUString >& userData) override; + + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.comp.filter.OdfFlatXml"; } + + sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override + { return cppu::supportsService(this, ServiceName); } + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override + { + return css::uno::Sequence{ + "com.sun.star.document.ImportFilter", + "com.sun.star.document.ExportFilter"}; + } + + }; + + } +} + +using namespace ::filter::odfflatxml; + +sal_Bool +OdfFlatXml::importer( + const Sequence< PropertyValue >& sourceData, + const Reference< XDocumentHandler >& docHandler, + const Sequence< OUString >& /* userData */) +{ + // Read InputStream to read from and a URL used for the system id + // of the InputSource we create from the given sourceData sequence + Reference inputStream; + OUString paramName; + OUString url; + + sal_Int32 paramCount = sourceData.getLength(); + for (sal_Int32 paramIdx = 0; paramIdx < paramCount; paramIdx++) + { + paramName = sourceData[paramIdx].Name; + if ( paramName == "InputStream" ) + sourceData[paramIdx].Value >>= inputStream; + else if ( paramName == "URL" ) + sourceData[paramIdx].Value >>= url; + } + + OSL_ASSERT(inputStream.is()); + if (!inputStream.is()) + return false; + + InputSource inputSource; + inputSource.sSystemId = url; + inputSource.sPublicId = url; + inputSource.aInputStream = inputStream; + try + { + css::uno::Reference< css::io::XSeekable > xSeekable( inputStream, css::uno::UNO_QUERY ); + if ( xSeekable.is() ) + xSeekable->seek( 0 ); + + css::uno::Reference< css::xml::sax::XFastParser > xFastParser (docHandler, UNO_QUERY ); + if( xFastParser.is() ) + xFastParser->parseStream( inputSource ); + else + { + Reference saxParser = Parser::create(m_xContext); + saxParser->setDocumentHandler(docHandler); + saxParser->parseStream(inputSource); + } + } + catch (const Exception &) + { + TOOLS_WARN_EXCEPTION("filter.odfflatxml", ""); + return false; + } + catch (const std::exception &exc) + { + SAL_WARN("filter.odfflatxml", exc.what()); + return false; + } + return true; +} + +sal_Bool +OdfFlatXml::importer( + const Sequence< PropertyValue >& sourceData, + const Reference< XFastParser >& xFastParser, + const Sequence< OUString >& /* userData */) +{ + // Read InputStream to read from and a URL used for the system id + // of the InputSource we create from the given sourceData sequence + Reference inputStream; + OUString paramName; + OUString url; + + sal_Int32 paramCount = sourceData.getLength(); + for (sal_Int32 paramIdx = 0; paramIdx < paramCount; paramIdx++) + { + paramName = sourceData[paramIdx].Name; + if ( paramName == "InputStream" ) + sourceData[paramIdx].Value >>= inputStream; + else if ( paramName == "URL" ) + sourceData[paramIdx].Value >>= url; + } + + OSL_ASSERT(inputStream.is()); + if (!inputStream.is()) + return false; + + InputSource inputSource; + inputSource.sSystemId = url; + inputSource.sPublicId = url; + inputSource.aInputStream = inputStream; + try + { + css::uno::Reference< css::io::XSeekable > xSeekable( inputStream, css::uno::UNO_QUERY ); + if ( xSeekable.is() ) + xSeekable->seek( 0 ); + + xFastParser->parseStream( inputSource ); + } + catch (const Exception &) + { + TOOLS_WARN_EXCEPTION("filter.odfflatxml", ""); + return false; + } + catch (const std::exception &exc) + { + SAL_WARN("filter.odfflatxml", exc.what()); + return false; + } + return true; +} + +sal_Bool +OdfFlatXml::exporter(const Sequence< PropertyValue >& sourceData, + const Sequence< OUString >& /*msUserData*/) +{ + OUString paramName; + Reference outputStream; + + // Read output stream and target URL from the parameters given in sourceData. + sal_Int32 paramCount = sourceData.getLength(); + for (sal_Int32 paramIdx = 0; paramIdx < paramCount; paramIdx++) + { + paramName = sourceData[paramIdx].Name; + if ( paramName == "OutputStream" ) + sourceData[paramIdx].Value >>= outputStream; + } + + if (!getDelegate().is()) + { + Reference< XDocumentHandler > saxWriter = Writer::create(m_xContext); + setDelegate(saxWriter); + } + // get data source interface ... + Reference dataSource(getDelegate(), UNO_QUERY); + OSL_ASSERT(dataSource.is()); + if (!dataSource.is()) + return false; + OSL_ASSERT(outputStream.is()); + if (!outputStream.is()) + return false; + dataSource->setOutputStream(outputStream); + + return true; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_OdfFlatXml_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new OdfFlatXml(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/odfflatxml/odfflatxml.component b/filter/source/odfflatxml/odfflatxml.component new file mode 100644 index 000000000..5f8bcfa9d --- /dev/null +++ b/filter/source/odfflatxml/odfflatxml.component @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx new file mode 100644 index 000000000..bd8db8369 --- /dev/null +++ b/filter/source/pdf/impdialog.cxx @@ -0,0 +1,1638 @@ +/* -*- 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 "impdialog.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static OUString PDFFilterResId(TranslateId aId) +{ + return Translate::get(aId, Translate::Create("flt")); +} + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +/** Tabbed PDF dialog implementation + Please note: the default used here are the same as per specification, + They should be the same in PDFFilter::implExport and in PDFExport::PDFExport + */ +ImpPDFTabDialog::ImpPDFTabDialog(weld::Window* pParent, const Sequence< PropertyValue >& rFilterData, + const Reference< XComponent >& rxDoc) + : SfxTabDialogController(pParent, "filter/ui/pdfoptionsdialog.ui", "PdfOptionsDialog"), + mrDoc(rxDoc), + mpParent(pParent), + maConfigItem( u"Office.Common/Filter/PDF/Export/", &rFilterData ), + maConfigI18N( u"Office.Common/I18N/CTL/" ), + mbIsPresentation( false ), + mbIsSpreadsheet( false ), + mbIsWriter( false ), + + mbSelectionPresent( false ), + mbUseCTLFont( false ), + mbUseLosslessCompression( true ), + mnQuality( 90 ), + mbReduceImageResolution( false ), + mnMaxImageResolution( 300 ), + mbUseTaggedPDF( false ), + mbUseTaggedPDFUserSelection( false ), + mbExportNotes( true ), + mbViewPDF( false ), + mbUseReferenceXObject( false ), + mbExportNotesPages( false ), + mbExportOnlyNotesPages( false ), + mbUseTransitionEffects( false ), + mbIsSkipEmptyPages( true ), + mbIsExportPlaceholders( false ), + mbAddStream( false ), + mnFormsType( 0 ), + mbExportFormFields( true ), + mbAllowDuplicateFieldNames( false ), + mbExportBookmarks( true ), + mbExportHiddenSlides ( false ), + mbSinglePageSheets ( false ), + mnOpenBookmarkLevels( -1 ), + + mbHideViewerToolbar( false ), + mbHideViewerMenubar( false ), + mbHideViewerWindowControls( false ), + mbResizeWinToInit( false ), + mbCenterWindow( false ), + mbOpenInFullScreenMode( false ), + mbDisplayPDFDocumentTitle( false ), + mnMagnification( 0 ), + mnInitialView( 0 ), + mnZoom( 0 ), + mnInitialPage( 1 ), + mnPageLayout( 0 ), + mbFirstPageLeft( false ), + + mbEncrypt( false ), + mbRestrictPermissions( false ), + mnPrint( 0 ), + mnChangesAllowed( 0 ), + mbCanCopyOrExtract( false ), + mbCanExtractForAccessibility( true ), + + mbIsRangeChecked( false ), + msPageRange( ' ' ), + + mbSelectionIsChecked( false ), + mbExportRelativeFsysLinks( false ), + mnViewPDFMode( 0 ), + mbConvertOOoTargets( false ), + mbExportBmkToPDFDestination( false ), + + mbSignPDF( false ) +{ + // check for selection + try + { + Reference< frame::XController > xController( Reference< frame::XModel >( rxDoc, UNO_QUERY_THROW )->getCurrentController() ); + if( xController.is() ) + { + Reference< view::XSelectionSupplier > xView( xController, UNO_QUERY ); + if( xView.is() ) + maSelection = xView->getSelection(); + } + } + catch(const RuntimeException &) + { + } + mbSelectionPresent = maSelection.hasValue(); + if ( mbSelectionPresent ) + { + Reference< drawing::XShapes > xShapes; + if ( !( maSelection >>= xShapes ) ) // XShapes is always a selection + { + // even if nothing is selected in writer the selection is not empty + Reference< container::XIndexAccess > xIndexAccess; + if ( maSelection >>= xIndexAccess ) + { + sal_Int32 nLen = xIndexAccess->getCount(); + if ( !nLen ) + mbSelectionPresent = false; + else if ( nLen == 1 ) + { + Reference< text::XTextRange > xTextRange( xIndexAccess->getByIndex( 0 ), UNO_QUERY ); + if ( xTextRange.is() && ( xTextRange->getString().isEmpty() ) ) + mbSelectionPresent = false; + } + } + } + } + + // check if source document is a presentation or a spreadsheet or a textdocument + try + { + Reference< XServiceInfo > xInfo( rxDoc, UNO_QUERY ); + if ( xInfo.is() ) + { + if ( xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) ) + mbIsPresentation = true; + if ( xInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) + mbIsSpreadsheet = true; + if ( xInfo->supportsService( "com.sun.star.text.GenericTextDocument" ) ) + mbIsWriter = true; + } + } + catch(const RuntimeException &) + { + } + + // get the CTL (Complex Text Layout) from general options, returns sal_True if we have a CTL font on our hands. + mbUseCTLFont = maConfigI18N.ReadBool( "CTLFont", false ); + + mbUseLosslessCompression = maConfigItem.ReadBool( "UseLosslessCompression", false ); + mnQuality = maConfigItem.ReadInt32( "Quality", 90 ); + mbReduceImageResolution = maConfigItem.ReadBool( "ReduceImageResolution", false ); + mnMaxImageResolution = maConfigItem.ReadInt32( "MaxImageResolution", 300 ); + + // this is always the user selection, independent from the PDF/A forced selection + mbUseTaggedPDF = maConfigItem.ReadBool( "UseTaggedPDF", false ); + mbUseTaggedPDFUserSelection = mbUseTaggedPDF; + + mnPDFTypeSelection = maConfigItem.ReadInt32( "SelectPdfVersion", 0 ); + mbPDFUACompliance = maConfigItem.ReadBool("PDFUACompliance", false); + + if ( mbIsPresentation ) + { + mbExportNotesPages = maConfigItem.ReadBool( "ExportNotesPages", false ); + mbExportOnlyNotesPages = maConfigItem.ReadBool( "ExportOnlyNotesPages", false ); + } + mbExportNotes = maConfigItem.ReadBool( "ExportNotes", false ); + mbViewPDF = maConfigItem.ReadBool( "ViewPDFAfterExport", false ); + + mbExportBookmarks = maConfigItem.ReadBool( "ExportBookmarks", true ); + if ( mbIsPresentation ) + mbExportHiddenSlides = maConfigItem.ReadBool( "ExportHiddenSlides", false ); + if ( mbIsSpreadsheet ) + mbSinglePageSheets = maConfigItem.ReadBool( "SinglePageSheets", false ); + mnOpenBookmarkLevels = maConfigItem.ReadInt32( "OpenBookmarkLevels", -1 ); + mbUseTransitionEffects = maConfigItem.ReadBool( "UseTransitionEffects", true ); + mbIsSkipEmptyPages = maConfigItem.ReadBool( "IsSkipEmptyPages", false ); + mbIsExportPlaceholders = maConfigItem.ReadBool( "ExportPlaceholders", false ); + mbAddStream = maConfigItem.ReadBool( "IsAddStream", false ); + + mbExportFormFields = maConfigItem.ReadBool( "ExportFormFields", true ); + mnFormsType = maConfigItem.ReadInt32( "FormsType", 0 ); + if ( ( mnFormsType < 0 ) || ( mnFormsType > 3 ) ) + mnFormsType = 0; + mbAllowDuplicateFieldNames = maConfigItem.ReadBool( "AllowDuplicateFieldNames", false ); + + // prepare values for the Viewer tab page + mbHideViewerToolbar = maConfigItem.ReadBool( "HideViewerToolbar", false ); + mbHideViewerMenubar = maConfigItem.ReadBool( "HideViewerMenubar", false ); + mbHideViewerWindowControls = maConfigItem.ReadBool( "HideViewerWindowControls", false ); + mbResizeWinToInit = maConfigItem.ReadBool( "ResizeWindowToInitialPage", false ); + mbCenterWindow = maConfigItem.ReadBool( "CenterWindow", false ); + mbOpenInFullScreenMode = maConfigItem.ReadBool( "OpenInFullScreenMode", false ); + mbDisplayPDFDocumentTitle = maConfigItem.ReadBool( "DisplayPDFDocumentTitle", true ); + + mnInitialView = maConfigItem.ReadInt32( "InitialView", 0 ); + mnMagnification = maConfigItem.ReadInt32( "Magnification", 0 ); + mnZoom = maConfigItem.ReadInt32( "Zoom", 100 ); + mnPageLayout = maConfigItem.ReadInt32( "PageLayout", 0 ); + mbFirstPageLeft = maConfigItem.ReadBool( "FirstPageOnLeft", false ); + mnInitialPage = maConfigItem.ReadInt32( "InitialPage", 1 ); + if( mnInitialPage < 1 ) + mnInitialPage = 1; + + // prepare values for the security tab page + mnPrint = maConfigItem.ReadInt32( "Printing", 2 ); + mnChangesAllowed = maConfigItem.ReadInt32( "Changes", 4 ); + mbCanCopyOrExtract = maConfigItem.ReadBool( "EnableCopyingOfContent", true ); + mbCanExtractForAccessibility = maConfigItem.ReadBool( "EnableTextAccessForAccessibilityTools", true ); + + // prepare values for relative links + mbExportRelativeFsysLinks = maConfigItem.ReadBool( "ExportLinksRelativeFsys", false ); + + mnViewPDFMode = maConfigItem.ReadInt32( "PDFViewSelection", 0 ); + + mbConvertOOoTargets = maConfigItem.ReadBool( "ConvertOOoTargetToPDFTarget", false ); + mbExportBmkToPDFDestination = maConfigItem.ReadBool( "ExportBookmarksToPDFDestination", false ); + + // prepare values for digital signatures + mbSignPDF = maConfigItem.ReadBool( "SignPDF", false ); + + // queue the tab pages for later creation (created when first shown) + AddTabPage("general", ImpPDFTabGeneralPage::Create, nullptr ); + AddTabPage("digitalsignatures", ImpPDFTabSigningPage::Create, nullptr); + AddTabPage("security", ImpPDFTabSecurityPage::Create, nullptr); + AddTabPage("links", ImpPDFTabLinksPage::Create, nullptr); + AddTabPage("userinterface", ImpPDFTabViewerPage::Create, nullptr); + AddTabPage("initialview", ImpPDFTabOpnFtrPage::Create, nullptr); + + SetCurPageId("general"); + + // get the string property value (from sfx2/source/dialog/mailmodel.cxx) to overwrite the text for the Ok button + OUString sOkButtonText = maConfigItem.ReadString( "_OkButtonString", OUString() ); + + // change text on the Ok button: get the relevant string from resources, update it on the button + // according to the exported pdf file destination: send as e-mail or write to file? + if (!sOkButtonText.isEmpty()) + GetOKButton().set_label(sOkButtonText); + + GetCancelButton().connect_clicked(LINK(this, ImpPDFTabDialog, CancelHdl)); + GetOKButton().connect_clicked(LINK(this, ImpPDFTabDialog, OkHdl)); + + // remove the reset button, not needed in this tabbed dialog + RemoveResetButton(); +} + +ImpPDFTabSecurityPage* ImpPDFTabDialog::getSecurityPage() const +{ + SfxTabPage* pSecurityPage = GetTabPage("security"); + if (pSecurityPage) + { + return static_cast(pSecurityPage); + } + return nullptr; +} + + +ImpPDFTabLinksPage* ImpPDFTabDialog::getLinksPage() const +{ + SfxTabPage* pLinksPage = GetTabPage("links"); + if (pLinksPage) + { + return static_cast(pLinksPage); + } + return nullptr; +} + + +ImpPDFTabGeneralPage* ImpPDFTabDialog::getGeneralPage() const +{ + SfxTabPage* pGeneralPage = GetTabPage("general"); + if (pGeneralPage) + { + return static_cast(pGeneralPage); + } + return nullptr; +} + +IMPL_LINK_NOARG(ImpPDFTabDialog, CancelHdl, weld::Button&, void) +{ + m_xDialog->response(RET_CANCEL); +} + +IMPL_LINK_NOARG(ImpPDFTabDialog, OkHdl, weld::Button&, void) +{ + if (getGeneralPage()->IsPdfUaSelected()) + { + SfxObjectShell* pShell = SfxObjectShell::GetShellFromComponent(mrDoc); + if (pShell) + { + sfx::AccessibilityIssueCollection aCollection = pShell->runAccessibilityCheck(); + if (!aCollection.getIssues().empty()) + { + mpAccessibilityCheckDialog = std::make_shared(mpParent, aCollection); + weld::DialogController::runAsync(mpAccessibilityCheckDialog, [this](sal_Int32 retValue){ + m_xDialog->response(retValue); + }); + } + else + { + m_xDialog->response(RET_OK); + } + } + else + { + m_xDialog->response(RET_OK); + } + } + else + { + m_xDialog->response(RET_OK); + } +} + +ImpPDFTabDialog::~ImpPDFTabDialog() +{ + maConfigItem.WriteModifiedConfig(); + maConfigI18N.WriteModifiedConfig(); + if (mpAccessibilityCheckDialog) + { + mpAccessibilityCheckDialog->response(RET_CANCEL); + } +} + +void ImpPDFTabDialog::PageCreated(const OString& rId, SfxTabPage& rPage) +{ + if (rId == "general") + static_cast(rPage).SetFilterConfigItem(this); + else if (rId == "userinterface") + { + static_cast(rPage).SetFilterConfigItem(this); + } + else if (rId == "initialview") + { + static_cast(rPage).SetFilterConfigItem(this); + } + else if (rId == "links") + { + static_cast(rPage).SetFilterConfigItem(this); + } + else if (rId == "security") + { + static_cast(rPage).SetFilterConfigItem(this); + } + else if (rId == "digitalsignatures") + { + static_cast(rPage).SetFilterConfigItem(this); + } +} + + +Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData() +{ + // updating the FilterData sequence and storing FilterData to configuration + if (ImpPDFTabGeneralPage* pPage = static_cast(GetTabPage("general"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabViewerPage* pPage = static_cast(GetTabPage("userinterface"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabOpnFtrPage* pPage = static_cast(GetTabPage("initialview"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabLinksPage* pPage = static_cast(GetTabPage("links"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabSecurityPage* pPage = static_cast( GetTabPage("security"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabSigningPage* pPage = static_cast(GetTabPage("digitalsignatures"))) + pPage->GetFilterConfigItem(this); + + // prepare the items to be returned + maConfigItem.WriteBool( "UseLosslessCompression", mbUseLosslessCompression ); + maConfigItem.WriteInt32("Quality", mnQuality ); + maConfigItem.WriteBool( "ReduceImageResolution", mbReduceImageResolution ); + maConfigItem.WriteInt32("MaxImageResolution", mnMaxImageResolution ); + + // always write the user selection, never the overridden value + const bool bIsPDFUA = mbPDFUACompliance; + const bool bIsPDFA = (1 == mnPDFTypeSelection) || (2 == mnPDFTypeSelection) || (3 == mnPDFTypeSelection); + const bool bUserSelectionTags = bIsPDFA || bIsPDFUA; + maConfigItem.WriteBool("UseTaggedPDF", bUserSelectionTags ? mbUseTaggedPDFUserSelection : mbUseTaggedPDF); + maConfigItem.WriteInt32("SelectPdfVersion", mnPDFTypeSelection ); + maConfigItem.WriteBool("PDFUACompliance", mbPDFUACompliance); + + if ( mbIsPresentation ) + { + maConfigItem.WriteBool( "ExportNotesPages", mbExportNotesPages ); + maConfigItem.WriteBool( "ExportOnlyNotesPages", mbExportOnlyNotesPages ); + } + maConfigItem.WriteBool( "ExportNotes", mbExportNotes ); + maConfigItem.WriteBool( "ViewPDFAfterExport", mbViewPDF ); + + maConfigItem.WriteBool( "ExportBookmarks", mbExportBookmarks ); + if ( mbIsPresentation ) + maConfigItem.WriteBool( "ExportHiddenSlides", mbExportHiddenSlides ); + if ( mbIsSpreadsheet ) + maConfigItem.WriteBool( "SinglePageSheets", mbSinglePageSheets ); + maConfigItem.WriteBool( "UseTransitionEffects", mbUseTransitionEffects ); + maConfigItem.WriteBool( "IsSkipEmptyPages", mbIsSkipEmptyPages ); + maConfigItem.WriteBool( "ExportPlaceholders", mbIsExportPlaceholders ); + maConfigItem.WriteBool( "IsAddStream", mbAddStream ); + + /* + * FIXME: the entries are only implicitly defined by the resource file. Should there + * ever be an additional form submit format this could get invalid. + */ + maConfigItem.WriteInt32( "FormsType", mnFormsType ); + maConfigItem.WriteBool( "ExportFormFields", mbExportFormFields ); + maConfigItem.WriteBool( "AllowDuplicateFieldNames", mbAllowDuplicateFieldNames ); + + maConfigItem.WriteBool( "HideViewerToolbar", mbHideViewerToolbar ); + maConfigItem.WriteBool( "HideViewerMenubar", mbHideViewerMenubar ); + maConfigItem.WriteBool( "HideViewerWindowControls", mbHideViewerWindowControls ); + maConfigItem.WriteBool( "ResizeWindowToInitialPage", mbResizeWinToInit ); + maConfigItem.WriteBool( "CenterWindow", mbCenterWindow ); + maConfigItem.WriteBool( "OpenInFullScreenMode", mbOpenInFullScreenMode ); + maConfigItem.WriteBool( "DisplayPDFDocumentTitle", mbDisplayPDFDocumentTitle ); + maConfigItem.WriteInt32( "InitialView", mnInitialView ); + maConfigItem.WriteInt32( "Magnification", mnMagnification); + maConfigItem.WriteInt32( "Zoom", mnZoom ); + maConfigItem.WriteInt32( "InitialPage", mnInitialPage ); + maConfigItem.WriteInt32( "PageLayout", mnPageLayout ); + maConfigItem.WriteBool( "FirstPageOnLeft", mbFirstPageLeft ); + maConfigItem.WriteInt32( "OpenBookmarkLevels", mnOpenBookmarkLevels ); + + maConfigItem.WriteBool( "ExportLinksRelativeFsys", mbExportRelativeFsysLinks ); + maConfigItem.WriteInt32("PDFViewSelection", mnViewPDFMode ); + maConfigItem.WriteBool( "ConvertOOoTargetToPDFTarget", mbConvertOOoTargets ); + maConfigItem.WriteBool( "ExportBookmarksToPDFDestination", mbExportBmkToPDFDestination ); + + maConfigItem.WriteBool( "SignPDF", mbSignPDF ); + + maConfigItem.WriteInt32( "Printing", mnPrint ); + maConfigItem.WriteInt32( "Changes", mnChangesAllowed ); + maConfigItem.WriteBool( "EnableCopyingOfContent", mbCanCopyOrExtract ); + maConfigItem.WriteBool( "EnableTextAccessForAccessibilityTools", mbCanExtractForAccessibility ); + + std::vector aRet + { + comphelper::makePropertyValue("Watermark", maWatermarkText), + comphelper::makePropertyValue("EncryptFile", mbEncrypt), + comphelper::makePropertyValue("PreparedPasswords", mxPreparedPasswords), + comphelper::makePropertyValue("RestrictPermissions", mbRestrictPermissions), + comphelper::makePropertyValue("PreparedPermissionPassword", maPreparedOwnerPassword) + }; + if( mbIsRangeChecked ) + aRet.push_back(comphelper::makePropertyValue("PageRange", msPageRange)); + else if( mbSelectionIsChecked ) + aRet.push_back(comphelper::makePropertyValue("Selection", maSelection)); + + aRet.push_back(comphelper::makePropertyValue("SignatureLocation", msSignLocation)); + aRet.push_back(comphelper::makePropertyValue("SignatureReason", msSignReason)); + aRet.push_back(comphelper::makePropertyValue("SignatureContactInfo", msSignContact)); + aRet.push_back(comphelper::makePropertyValue("SignaturePassword", msSignPassword)); + aRet.push_back(comphelper::makePropertyValue("SignatureCertificate", maSignCertificate)); + aRet.push_back(comphelper::makePropertyValue("SignatureTSA", msSignTSA)); + aRet.push_back(comphelper::makePropertyValue("UseReferenceXObject", mbUseReferenceXObject)); + + return comphelper::concatSequences(maConfigItem.GetFilterData(), comphelper::containerToSequence(aRet)); +} + + +ImpPDFTabGeneralPage::ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfgeneralpage.ui", "PdfGeneralPage", &rCoreSet) + , mbUseTaggedPDFUserSelection(false) + , mbIsPresentation(false) + , mbIsSpreadsheet(false) + , mbIsWriter(false) + , mpParent(nullptr) + , mxRbAll(m_xBuilder->weld_radio_button("all")) + , mxRbRange(m_xBuilder->weld_radio_button("range")) + , mxRbSelection(m_xBuilder->weld_radio_button("selection")) + , mxEdPages(m_xBuilder->weld_entry("pages")) + , mxSelectedSheets(m_xBuilder->weld_label("selectedsheets")) + , mxRbLosslessCompression(m_xBuilder->weld_radio_button("losslesscompress")) + , mxRbJPEGCompression(m_xBuilder->weld_radio_button("jpegcompress")) + , mxQualityFrame(m_xBuilder->weld_widget("qualityframe")) + , mxNfQuality(m_xBuilder->weld_metric_spin_button("quality", FieldUnit::PERCENT)) + , mxCbReduceImageResolution(m_xBuilder->weld_check_button("reduceresolution")) + , mxCoReduceImageResolution(m_xBuilder->weld_combo_box("resolution")) + , mxCbPDFA(m_xBuilder->weld_check_button("pdfa")) + , mxCbPDFUA(m_xBuilder->weld_check_button("pdfua")) + , mxRbPDFAVersion(m_xBuilder->weld_combo_box("pdfaversion")) + , mxCbTaggedPDF(m_xBuilder->weld_check_button("tagged")) + , mxCbExportFormFields(m_xBuilder->weld_check_button("forms")) + , mxFormsFrame(m_xBuilder->weld_widget("formsframe")) + , mxLbFormsFormat(m_xBuilder->weld_combo_box("format")) + , mxCbAllowDuplicateFieldNames(m_xBuilder->weld_check_button("allowdups")) + , mxCbExportBookmarks(m_xBuilder->weld_check_button("bookmarks")) + , mxCbExportHiddenSlides(m_xBuilder->weld_check_button("hiddenpages")) + , mxCbSinglePageSheets(m_xBuilder->weld_check_button("singlepagesheets")) + , mxCbExportNotes(m_xBuilder->weld_check_button("comments")) + , mxCbViewPDF(m_xBuilder->weld_check_button("viewpdf")) + , mxCbUseReferenceXObject(m_xBuilder->weld_check_button("usereferencexobject")) + , mxCbExportNotesPages(m_xBuilder->weld_check_button("notes")) + , mxCbExportOnlyNotesPages(m_xBuilder->weld_check_button("onlynotes")) + , mxCbExportEmptyPages(m_xBuilder->weld_check_button("emptypages")) + , mxCbExportPlaceholders(m_xBuilder->weld_check_button("exportplaceholders")) + , mxCbAddStream(m_xBuilder->weld_check_button("embed")) + , mxCbWatermark(m_xBuilder->weld_check_button("watermark")) + , mxFtWatermark(m_xBuilder->weld_label("watermarklabel")) + , mxEdWatermark(m_xBuilder->weld_entry("watermarkentry")) + , mxSlidesFt(m_xBuilder->weld_label("slides")) + , mxSheetsFt(m_xBuilder->weld_label("selectedsheets")) +{ +} + +ImpPDFTabGeneralPage::~ImpPDFTabGeneralPage() +{ +} + +void ImpPDFTabGeneralPage::SetFilterConfigItem(ImpPDFTabDialog* pParent) +{ + mpParent = pParent; + + // init this class data + mxRbRange->connect_toggled( LINK( this, ImpPDFTabGeneralPage, TogglePagesHdl ) ); + + mxRbAll->set_active(true); + mxRbAll->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleAllHdl ) ); + TogglePagesHdl(); + + const bool bSelectionPresent = pParent->mbSelectionPresent; + mxRbSelection->set_sensitive( bSelectionPresent ); + if ( bSelectionPresent ) + mxRbSelection->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleSelectionHdl ) ); + mbIsPresentation = pParent->mbIsPresentation; + mbIsWriter = pParent->mbIsWriter; + mbIsSpreadsheet = pParent->mbIsSpreadsheet; + + mxCbExportEmptyPages->set_sensitive( mbIsWriter ); + mxCbExportPlaceholders->set_sensitive( mbIsWriter ); + + mxRbLosslessCompression->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleCompressionHdl ) ); + const bool bUseLosslessCompression = pParent->mbUseLosslessCompression; + if ( bUseLosslessCompression ) + mxRbLosslessCompression->set_active(true); + else + mxRbJPEGCompression->set_active(true); + + mxNfQuality->set_value( pParent->mnQuality, FieldUnit::PERCENT ); + mxQualityFrame->set_sensitive(!bUseLosslessCompression); + + mxCbReduceImageResolution->connect_toggled(LINK(this, ImpPDFTabGeneralPage, ToggleReduceImageResolutionHdl)); + const bool bReduceImageResolution = pParent->mbReduceImageResolution; + mxCbReduceImageResolution->set_active( bReduceImageResolution ); + OUString aStrRes = OUString::number( pParent->mnMaxImageResolution ) + " DPI"; + mxCoReduceImageResolution->set_entry_text(aStrRes); + mxCoReduceImageResolution->set_sensitive( bReduceImageResolution ); + mxCbWatermark->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleWatermarkHdl ) ); + mxFtWatermark->set_sensitive(false ); + mxEdWatermark->set_sensitive( false ); + mxCbPDFA->connect_toggled(LINK(this, ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle)); + + const bool bIsPDFA = (pParent->mnPDFTypeSelection>=1) && (pParent->mnPDFTypeSelection <= 3); + mxCbPDFA->set_active(bIsPDFA); + switch( pParent->mnPDFTypeSelection ) + { + case 1: // PDF/A-1 + mxRbPDFAVersion->set_active_id("1"); + break; + case 2: // PDF/A-2 + mxRbPDFAVersion->set_active_id("2"); + break; + case 3: // PDF/A-3 + default: // PDF 1.x + mxRbPDFAVersion->set_active_id("3"); + break; + } + + const bool bIsPDFUA = pParent->mbPDFUACompliance; + mxCbPDFUA->set_active(bIsPDFUA); + mxCbPDFUA->connect_toggled(LINK(this, ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle)); + + // the TogglePDFVersionOrUniversalAccessibilityHandle handler will read or write the *UserSelection based + // on the mxCbPDFA (= bIsPDFA) state, so we have to prepare the correct input state. + if (bIsPDFA || bIsPDFUA) + mxCbTaggedPDF->set_active(pParent->mbUseTaggedPDFUserSelection); + else + mbUseTaggedPDFUserSelection = pParent->mbUseTaggedPDFUserSelection; + TogglePDFVersionOrUniversalAccessibilityHandle(*mxCbPDFA); + + mxCbExportFormFields->set_active(pParent->mbExportFormFields); + mxCbExportFormFields->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleExportFormFieldsHdl ) ); + + mxLbFormsFormat->set_active(static_cast(pParent->mnFormsType)); + mxCbAllowDuplicateFieldNames->set_active( pParent->mbAllowDuplicateFieldNames ); + mxFormsFrame->set_sensitive(pParent->mbExportFormFields); + + mxCbExportBookmarks->set_active( pParent->mbExportBookmarks ); + + mxCbExportNotes->set_active( pParent->mbExportNotes ); + mxCbViewPDF->set_active( pParent->mbViewPDF); + + if ( mbIsPresentation ) + { + mxRbRange->set_label(mxSlidesFt->get_label()); + mxCbExportNotesPages->show(); + mxCbExportNotesPages->set_active(pParent->mbExportNotesPages); + mxCbExportNotesPages->connect_toggled( LINK(this, ImpPDFTabGeneralPage, ToggleExportNotesPagesHdl ) ); + mxCbExportOnlyNotesPages->show(); + mxCbExportOnlyNotesPages->set_active(pParent->mbExportOnlyNotesPages); + // tdf#116473 Initially enable Export only note pages option depending on the checked state of Export notes pages option + mxCbExportOnlyNotesPages->set_sensitive(mxCbExportNotesPages->get_active()); + mxCbExportHiddenSlides->show(); + mxCbExportHiddenSlides->set_active(pParent->mbExportHiddenSlides); + } + else + { + mxCbExportNotesPages->hide(); + mxCbExportNotesPages->set_active(false); + mxCbExportOnlyNotesPages->hide(); + mxCbExportOnlyNotesPages->set_active(false); + mxCbExportHiddenSlides->hide(); + mxCbExportHiddenSlides->set_active(false); + } + + if( mbIsSpreadsheet ) + { + mxRbSelection->set_label(mxSheetsFt->get_label()); + // tdf#105965 Make Selection/Selected sheets the default PDF export range setting for spreadsheets + mxRbSelection->set_active(true); + + mxCbSinglePageSheets->show(); + mxCbSinglePageSheets->set_active(pParent->mbSinglePageSheets); + } + else + { + mxCbSinglePageSheets->hide(); + mxCbSinglePageSheets->set_active(false); + } + + mxCbExportPlaceholders->set_visible(mbIsWriter); + if( mbIsWriter ) + { + // tdf#54908 Make selection active if there is a selection in Writer's version + mxRbSelection->set_active( bSelectionPresent ); + } + else + { + mxCbExportPlaceholders->set_active(false); + } + mxCbExportEmptyPages->set_active(!pParent->mbIsSkipEmptyPages); + mxCbExportPlaceholders->set_active(pParent->mbIsExportPlaceholders); + + mxCbAddStream->show(); + mxCbAddStream->set_active(pParent->mbAddStream); + + mxCbAddStream->connect_toggled(LINK(this, ImpPDFTabGeneralPage, ToggleAddStreamHdl)); + ToggleAddStreamHdl(*mxCbAddStream); // init addstream dependencies +} + +void ImpPDFTabGeneralPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + // updating the FilterData sequence and storing FilterData to configuration + pParent->mbUseLosslessCompression = mxRbLosslessCompression->get_active(); + pParent->mnQuality = static_cast(mxNfQuality->get_value(FieldUnit::PERCENT)); + pParent->mbReduceImageResolution = mxCbReduceImageResolution->get_active(); + pParent->mnMaxImageResolution = mxCoReduceImageResolution->get_active_text().toInt32(); + pParent->mbExportNotes = mxCbExportNotes->get_active(); + pParent->mbViewPDF = mxCbViewPDF->get_active(); + pParent->mbUseReferenceXObject = mxCbUseReferenceXObject->get_active(); + if ( mbIsPresentation ) + { + pParent->mbExportNotesPages = mxCbExportNotesPages->get_active(); + pParent->mbExportOnlyNotesPages = mxCbExportOnlyNotesPages->get_active(); + } + pParent->mbExportBookmarks = mxCbExportBookmarks->get_active(); + if ( mbIsPresentation ) + pParent->mbExportHiddenSlides = mxCbExportHiddenSlides->get_active(); + + if (mbIsSpreadsheet) + pParent->mbSinglePageSheets = mxCbSinglePageSheets->get_active(); + + pParent->mbIsSkipEmptyPages = !mxCbExportEmptyPages->get_active(); + pParent->mbIsExportPlaceholders = mxCbExportPlaceholders->get_active(); + pParent->mbAddStream = mxCbAddStream->get_visible() && mxCbAddStream->get_active(); + + pParent->mbIsRangeChecked = false; + if( mxRbRange->get_active() ) + { + pParent->mbIsRangeChecked = true; + pParent->msPageRange = mxEdPages->get_text(); //FIXME all right on other languages ? + } + else if( mxRbSelection->get_active() ) + { + pParent->mbSelectionIsChecked = mxRbSelection->get_active(); + } + + pParent->mnPDFTypeSelection = 0; + pParent->mbUseTaggedPDF = mxCbTaggedPDF->get_active(); + + const bool bIsPDFA = mxCbPDFA->get_active(); + const bool bIsPDFUA = mxCbPDFUA->get_active(); + + if (bIsPDFA) + { + pParent->mnPDFTypeSelection = 3; + OUString currentPDFAMode = mxRbPDFAVersion->get_active_id(); + if( currentPDFAMode == "1" ) + pParent->mnPDFTypeSelection = 1; + else if(currentPDFAMode == "2") + pParent->mnPDFTypeSelection = 2; + } + + pParent->mbPDFUACompliance = bIsPDFUA; + + if (!bIsPDFA && !bIsPDFUA) + mbUseTaggedPDFUserSelection = pParent->mbUseTaggedPDF; + + pParent->mbUseTaggedPDFUserSelection = mbUseTaggedPDFUserSelection; + pParent->mbExportFormFields = mxCbExportFormFields->get_active(); + + if( mxCbWatermark->get_active() ) + pParent->maWatermarkText = mxEdWatermark->get_text(); + + /* + * FIXME: the entries are only implicitly defined by the resource file. Should there + * ever be an additional form submit format this could get invalid. + */ + pParent->mnFormsType = mxLbFormsFormat->get_active(); + pParent->mbAllowDuplicateFieldNames = mxCbAllowDuplicateFieldNames->get_active(); +} + +std::unique_ptr ImpPDFTabGeneralPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique(pPage, pController, *rAttrSet); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleAllHdl, weld::Toggleable&, void) +{ + EnableExportNotesPages(); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, TogglePagesHdl, weld::Toggleable&, void) +{ + TogglePagesHdl(); + EnableExportNotesPages(); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleSelectionHdl, weld::Toggleable&, void) +{ + EnableExportNotesPages(); +} + +void ImpPDFTabGeneralPage::TogglePagesHdl() +{ + mxEdPages->set_sensitive( mxRbRange->get_active() ); + if (mxRbRange->get_active()) + mxEdPages->grab_focus(); +} + +void ImpPDFTabGeneralPage::EnableExportNotesPages() +{ + if ( mbIsPresentation ) + { + mxCbExportNotesPages->set_sensitive( !mxRbSelection->get_active() ); + mxCbExportOnlyNotesPages->set_sensitive( !mxRbSelection->get_active() && mxCbExportNotesPages->get_active() ); + } +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleExportFormFieldsHdl, weld::Toggleable&, void) +{ + mxFormsFrame->set_sensitive(mxCbExportFormFields->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleExportNotesPagesHdl, weld::Toggleable&, void) +{ + mxCbExportOnlyNotesPages->set_sensitive(mxCbExportNotesPages->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleCompressionHdl, weld::Toggleable&, void) +{ + mxQualityFrame->set_sensitive(mxRbJPEGCompression->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleReduceImageResolutionHdl, weld::Toggleable&, void) +{ + mxCoReduceImageResolution->set_sensitive(mxCbReduceImageResolution->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleWatermarkHdl, weld::Toggleable&, void) +{ + mxEdWatermark->set_sensitive(mxCbWatermark->get_active()); + mxFtWatermark->set_sensitive(mxCbWatermark->get_active()); + if (mxCbWatermark->get_active()) + mxEdWatermark->grab_focus(); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleAddStreamHdl, weld::Toggleable&, void) +{ + if (!mxCbAddStream->get_visible()) + return; + + if( mxCbAddStream->get_active() ) + { + mxRbAll->set_active(true); + mxRbRange->set_sensitive( false ); + mxRbSelection->set_sensitive( false ); + mxEdPages->set_sensitive( false ); + mxRbAll->set_sensitive( false ); + } + else + { + mxRbAll->set_sensitive(true); + mxRbRange->set_sensitive(true); + mxRbSelection->set_sensitive(true); + } +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle, weld::Toggleable&, void) +{ + const bool bIsPDFA = mxCbPDFA->get_active(); + const bool bIsPDFUA = mxCbPDFUA->get_active(); + + // set the security page status (and its controls as well) + ImpPDFTabSecurityPage* pSecPage = mpParent ? mpParent->getSecurityPage() : nullptr; + if (pSecPage) + pSecPage->ImplPDFASecurityControl(!bIsPDFA); + + mxCbTaggedPDF->set_sensitive(!bIsPDFA && !bIsPDFUA); + mxRbPDFAVersion->set_sensitive(bIsPDFA); + + if (bIsPDFA || bIsPDFUA) + { + // store the users selection of subordinate controls and set required PDF/A values + mbUseTaggedPDFUserSelection = mxCbTaggedPDF->get_active(); + mxCbTaggedPDF->set_active(true); + + // if a password was set, inform the user that this will not be used + if (pSecPage && pSecPage->hasPassword()) + { + std::unique_ptr xBox(Application::CreateMessageDialog(m_xContainer.get(), + VclMessageType::Warning, VclButtonsType::Ok, + PDFFilterResId(STR_WARN_PASSWORD_PDFA))); + xBox->run(); + } + } + else + { + // restore the users values of subordinate controls + mxCbTaggedPDF->set_active(mbUseTaggedPDFUserSelection); + } + + // PDF/A doesn't allow launch action, so enable/disable the selection on the Link page + ImpPDFTabLinksPage* pLinksPage = mpParent ? mpParent->getLinksPage() : nullptr; + if (pLinksPage) + pLinksPage->ImplPDFALinkControl(!bIsPDFA); +} + +/// The option features tab page +ImpPDFTabOpnFtrPage::ImpPDFTabOpnFtrPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfviewpage.ui", "PdfViewPage", &rCoreSet) + , mbUseCTLFont(false) + , mxRbOpnPageOnly(m_xBuilder->weld_radio_button("pageonly")) + , mxRbOpnOutline(m_xBuilder->weld_radio_button("outline")) + , mxRbOpnThumbs(m_xBuilder->weld_radio_button("thumbs")) + , mxNumInitialPage(m_xBuilder->weld_spin_button("page")) + , mxRbMagnDefault(m_xBuilder->weld_radio_button("fitdefault")) + , mxRbMagnFitWin(m_xBuilder->weld_radio_button("fitwin")) + , mxRbMagnFitWidth(m_xBuilder->weld_radio_button("fitwidth")) + , mxRbMagnFitVisible(m_xBuilder->weld_radio_button("fitvis")) + , mxRbMagnZoom(m_xBuilder->weld_radio_button("fitzoom")) + , mxNumZoom(m_xBuilder->weld_spin_button("zoom")) + , mxRbPgLyDefault(m_xBuilder->weld_radio_button("defaultlayout")) + , mxRbPgLySinglePage(m_xBuilder->weld_radio_button("singlelayout")) + , mxRbPgLyContinue(m_xBuilder->weld_radio_button("contlayout")) + , mxRbPgLyContinueFacing(m_xBuilder->weld_radio_button("contfacinglayout")) + , mxCbPgLyFirstOnLeft(m_xBuilder->weld_check_button("firstonleft")) +{ + mxRbMagnDefault->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnFitWin->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnFitWidth->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnFitVisible->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnZoom->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); +} + +ImpPDFTabOpnFtrPage::~ImpPDFTabOpnFtrPage() +{ +} + +std::unique_ptr ImpPDFTabOpnFtrPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique(pPage, pController, *rAttrSet); +} + +void ImpPDFTabOpnFtrPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mnInitialView = 0; + if( mxRbOpnOutline->get_active() ) + pParent->mnInitialView = 1; + else if( mxRbOpnThumbs->get_active() ) + pParent->mnInitialView = 2; + + pParent->mnMagnification = 0; + if( mxRbMagnFitWin->get_active() ) + pParent->mnMagnification = 1; + else if( mxRbMagnFitWidth->get_active() ) + pParent->mnMagnification = 2; + else if( mxRbMagnFitVisible->get_active() ) + pParent->mnMagnification = 3; + else if( mxRbMagnZoom->get_active() ) + { + pParent->mnMagnification = 4; + pParent->mnZoom = mxNumZoom->get_value(); + } + + pParent->mnInitialPage = mxNumInitialPage->get_value(); + + pParent->mnPageLayout = 0; + if( mxRbPgLySinglePage->get_active() ) + pParent->mnPageLayout = 1; + else if( mxRbPgLyContinue->get_active() ) + pParent->mnPageLayout = 2; + else if( mxRbPgLyContinueFacing->get_active() ) + pParent->mnPageLayout = 3; + + pParent->mbFirstPageLeft = mbUseCTLFont && mxCbPgLyFirstOnLeft->get_active(); +} + +void ImpPDFTabOpnFtrPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + mbUseCTLFont = pParent->mbUseCTLFont; + switch( pParent->mnPageLayout ) + { + default: + case 0: + mxRbPgLyDefault->set_active(true); + break; + case 1: + mxRbPgLySinglePage->set_active(true); + break; + case 2: + mxRbPgLyContinue->set_active(true); + break; + case 3: + mxRbPgLyContinueFacing->set_active(true); + break; + } + + switch( pParent->mnInitialView ) + { + default: + case 0: + mxRbOpnPageOnly->set_active(true); + break; + case 1: + mxRbOpnOutline->set_active(true); + break; + case 2: + mxRbOpnThumbs->set_active(true); + break; + } + + switch( pParent->mnMagnification ) + { + default: + case 0: + mxRbMagnDefault->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 1: + mxRbMagnFitWin->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 2: + mxRbMagnFitWidth->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 3: + mxRbMagnFitVisible->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 4: + mxRbMagnZoom->set_active(true); + mxNumZoom->set_sensitive(true); + break; + } + + mxNumZoom->set_value(pParent->mnZoom); + mxNumInitialPage->set_value(pParent->mnInitialPage); + + if (!mbUseCTLFont) + mxCbPgLyFirstOnLeft->hide(); + else + { + mxRbPgLyContinueFacing->connect_toggled(LINK(this, ImpPDFTabOpnFtrPage, ToggleRbPgLyContinueFacingHdl)); + mxCbPgLyFirstOnLeft->set_active(pParent->mbFirstPageLeft); + ToggleRbPgLyContinueFacingHdl(); + } +} + +IMPL_LINK_NOARG(ImpPDFTabOpnFtrPage, ToggleRbPgLyContinueFacingHdl, weld::Toggleable&, void) +{ + ToggleRbPgLyContinueFacingHdl(); +} + +void ImpPDFTabOpnFtrPage::ToggleRbPgLyContinueFacingHdl() +{ + mxCbPgLyFirstOnLeft->set_sensitive(mxRbPgLyContinueFacing->get_active()); +} + +IMPL_LINK_NOARG( ImpPDFTabOpnFtrPage, ToggleRbMagnHdl, weld::Toggleable&, void ) +{ + mxNumZoom->set_sensitive(mxRbMagnZoom->get_active()); +} + +/// The Viewer preferences tab page +ImpPDFTabViewerPage::ImpPDFTabViewerPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet ) + : SfxTabPage(pPage, pController, "filter/ui/pdfuserinterfacepage.ui", "PdfUserInterfacePage", &rCoreSet) + , mbIsPresentation(false) + , m_xCbResWinInit(m_xBuilder->weld_check_button("resize")) + , m_xCbCenterWindow(m_xBuilder->weld_check_button("center")) + , m_xCbOpenFullScreen(m_xBuilder->weld_check_button("open")) + , m_xCbDispDocTitle(m_xBuilder->weld_check_button("display")) + , m_xCbHideViewerMenubar(m_xBuilder->weld_check_button("menubar")) + , m_xCbHideViewerToolbar(m_xBuilder->weld_check_button("toolbar")) + , m_xCbHideViewerWindowControls(m_xBuilder->weld_check_button("window")) + , m_xCbTransitionEffects(m_xBuilder->weld_check_button("effects")) + , m_xRbAllBookmarkLevels(m_xBuilder->weld_radio_button("allbookmarks")) + , m_xRbVisibleBookmarkLevels(m_xBuilder->weld_radio_button("visiblebookmark")) + , m_xNumBookmarkLevels(m_xBuilder->weld_spin_button("visiblelevel")) +{ + m_xRbAllBookmarkLevels->connect_toggled(LINK(this, ImpPDFTabViewerPage, ToggleRbBookmarksHdl)); + m_xRbVisibleBookmarkLevels->connect_toggled(LINK(this, ImpPDFTabViewerPage, ToggleRbBookmarksHdl)); +} + +ImpPDFTabViewerPage::~ImpPDFTabViewerPage() +{ +} + +IMPL_LINK_NOARG( ImpPDFTabViewerPage, ToggleRbBookmarksHdl, weld::Toggleable&, void ) +{ + m_xNumBookmarkLevels->set_sensitive(m_xRbVisibleBookmarkLevels->get_active()); +} + +std::unique_ptr ImpPDFTabViewerPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique(pPage, pController, *rAttrSet); +} + +void ImpPDFTabViewerPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mbHideViewerMenubar = m_xCbHideViewerMenubar->get_active(); + pParent->mbHideViewerToolbar = m_xCbHideViewerToolbar->get_active(); + pParent->mbHideViewerWindowControls = m_xCbHideViewerWindowControls->get_active(); + pParent->mbResizeWinToInit = m_xCbResWinInit->get_active(); + pParent->mbOpenInFullScreenMode = m_xCbOpenFullScreen->get_active(); + pParent->mbCenterWindow = m_xCbCenterWindow->get_active(); + pParent->mbDisplayPDFDocumentTitle = m_xCbDispDocTitle->get_active(); + pParent->mbUseTransitionEffects = m_xCbTransitionEffects->get_active(); + pParent->mnOpenBookmarkLevels = m_xRbAllBookmarkLevels->get_active() ? + -1 : static_cast(m_xNumBookmarkLevels->get_value()); +} + +void ImpPDFTabViewerPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + m_xCbHideViewerMenubar->set_active( pParent->mbHideViewerMenubar ); + m_xCbHideViewerToolbar->set_active( pParent->mbHideViewerToolbar ); + m_xCbHideViewerWindowControls->set_active( pParent->mbHideViewerWindowControls ); + + m_xCbResWinInit->set_active( pParent->mbResizeWinToInit ); + m_xCbOpenFullScreen->set_active( pParent->mbOpenInFullScreenMode ); + m_xCbCenterWindow->set_active( pParent->mbCenterWindow ); + m_xCbDispDocTitle->set_active( pParent->mbDisplayPDFDocumentTitle ); + mbIsPresentation = pParent->mbIsPresentation; + m_xCbTransitionEffects->set_active( pParent->mbUseTransitionEffects ); + m_xCbTransitionEffects->set_sensitive( mbIsPresentation ); + if( pParent->mnOpenBookmarkLevels < 0 ) + { + m_xRbAllBookmarkLevels->set_active(true); + m_xNumBookmarkLevels->set_sensitive( false ); + } + else + { + m_xRbVisibleBookmarkLevels->set_active(true); + m_xNumBookmarkLevels->set_sensitive(true); + m_xNumBookmarkLevels->set_value(pParent->mnOpenBookmarkLevels); + } +} + +/// The Security preferences tab page +ImpPDFTabSecurityPage::ImpPDFTabSecurityPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& i_rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfsecuritypage.ui", "PdfSecurityPage", &i_rCoreSet) + , msUserPwdTitle( PDFFilterResId( STR_PDF_EXPORT_UDPWD ) ) + , mbHaveOwnerPassword( false ) + , mbHaveUserPassword( false ) + , msOwnerPwdTitle( PDFFilterResId( STR_PDF_EXPORT_ODPWD ) ) + , mxPbSetPwd(m_xBuilder->weld_button("setpassword")) + , mxUserPwdSet(m_xBuilder->weld_widget("userpwdset")) + , mxUserPwdUnset(m_xBuilder->weld_widget("userpwdunset")) + , mxUserPwdPdfa(m_xBuilder->weld_widget("userpwdpdfa")) + , mxOwnerPwdSet(m_xBuilder->weld_widget("ownerpwdset")) + , mxOwnerPwdUnset(m_xBuilder->weld_widget("ownerpwdunset")) + , mxOwnerPwdPdfa(m_xBuilder->weld_widget("ownerpwdpdfa")) + , mxPrintPermissions(m_xBuilder->weld_widget("printing")) + , mxRbPrintNone(m_xBuilder->weld_radio_button("printnone")) + , mxRbPrintLowRes(m_xBuilder->weld_radio_button("printlow")) + , mxRbPrintHighRes(m_xBuilder->weld_radio_button("printhigh")) + , mxChangesAllowed(m_xBuilder->weld_widget("changes")) + , mxRbChangesNone(m_xBuilder->weld_radio_button("changenone")) + , mxRbChangesInsDel(m_xBuilder->weld_radio_button("changeinsdel")) + , mxRbChangesFillForm(m_xBuilder->weld_radio_button("changeform")) + , mxRbChangesComment(m_xBuilder->weld_radio_button("changecomment")) + , mxRbChangesAnyNoCopy(m_xBuilder->weld_radio_button("changeany")) + , mxContent(m_xBuilder->weld_widget("content")) + , mxCbEnableCopy(m_xBuilder->weld_check_button("enablecopy")) + , mxCbEnableAccessibility(m_xBuilder->weld_check_button("enablea11y")) + , mxPasswordTitle(m_xBuilder->weld_label("setpasswordstitle")) +{ + msStrSetPwd = mxPasswordTitle->get_label(); + mxPbSetPwd->connect_clicked(LINK(this, ImpPDFTabSecurityPage, ClickmaPbSetPwdHdl)); +} + +ImpPDFTabSecurityPage::~ImpPDFTabSecurityPage() +{ +} + +std::unique_ptr ImpPDFTabSecurityPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique(pPage, pController, *rAttrSet); +} + +void ImpPDFTabSecurityPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + // please note that in PDF/A-1a mode even if this are copied back, + // the security settings are forced disabled in PDFExport::Export + pParent->mbEncrypt = mbHaveUserPassword; + pParent->mxPreparedPasswords = mxPreparedPasswords; + + pParent->mbRestrictPermissions = mbHaveOwnerPassword; + pParent->maPreparedOwnerPassword = maPreparedOwnerPassword; + + // verify print status + pParent->mnPrint = 0; + if (mxRbPrintLowRes->get_active()) + pParent->mnPrint = 1; + else if (mxRbPrintHighRes->get_active()) + pParent->mnPrint = 2; + + // verify changes permitted + pParent->mnChangesAllowed = 0; + + if( mxRbChangesInsDel->get_active() ) + pParent->mnChangesAllowed = 1; + else if( mxRbChangesFillForm->get_active() ) + pParent->mnChangesAllowed = 2; + else if( mxRbChangesComment->get_active() ) + pParent->mnChangesAllowed = 3; + else if( mxRbChangesAnyNoCopy->get_active() ) + pParent->mnChangesAllowed = 4; + + pParent->mbCanCopyOrExtract = mxCbEnableCopy->get_active(); + pParent->mbCanExtractForAccessibility = mxCbEnableAccessibility->get_active(); +} + +void ImpPDFTabSecurityPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + switch( pParent->mnPrint ) + { + default: + case 0: + mxRbPrintNone->set_active(true); + break; + case 1: + mxRbPrintLowRes->set_active(true); + break; + case 2: + mxRbPrintHighRes->set_active(true); + break; + } + + switch( pParent->mnChangesAllowed ) + { + default: + case 0: + mxRbChangesNone->set_active(true); + break; + case 1: + mxRbChangesInsDel->set_active(true); + break; + case 2: + mxRbChangesFillForm->set_active(true); + break; + case 3: + mxRbChangesComment->set_active(true); + break; + case 4: + mxRbChangesAnyNoCopy->set_active(true); + break; + } + + mxCbEnableCopy->set_active(pParent->mbCanCopyOrExtract); + mxCbEnableAccessibility->set_active(pParent->mbCanExtractForAccessibility); + + // set the status of this windows, according to the PDFA selection + enablePermissionControls(); + + ImpPDFTabGeneralPage* pGeneralPage = pParent->getGeneralPage(); + + if (pGeneralPage) + ImplPDFASecurityControl(!pGeneralPage->IsPdfaSelected()); +} + +IMPL_LINK_NOARG(ImpPDFTabSecurityPage, ClickmaPbSetPwdHdl, weld::Button&, void) +{ + SfxPasswordDialog aPwdDialog(m_xContainer.get(), &msUserPwdTitle); + aPwdDialog.SetMinLen(0); + aPwdDialog.ShowMinLengthText(false); + aPwdDialog.ShowExtras( SfxShowExtras::CONFIRM | SfxShowExtras::PASSWORD2 | SfxShowExtras::CONFIRM2 ); + aPwdDialog.set_title(msStrSetPwd); + aPwdDialog.SetGroup2Text(msOwnerPwdTitle); + aPwdDialog.AllowAsciiOnly(); + if (aPwdDialog.run() == RET_OK) // OK issued get password and set it + { + OUString aUserPW(aPwdDialog.GetPassword()); + OUString aOwnerPW(aPwdDialog.GetPassword2()); + + mbHaveUserPassword = !aUserPW.isEmpty(); + mbHaveOwnerPassword = !aOwnerPW.isEmpty(); + + mxPreparedPasswords = vcl::PDFWriter::InitEncryption( aOwnerPW, aUserPW ); + if (!mxPreparedPasswords.is()) { + OUString msg; + ErrorHandler::GetErrorString(ERRCODE_IO_NOTSUPPORTED, msg); //TODO: handle failure + std::unique_ptr( + Application::CreateMessageDialog( + GetFrameWeld(), VclMessageType::Error, VclButtonsType::Ok, msg)) + ->run(); + return; + } + + if( mbHaveOwnerPassword ) + { + maPreparedOwnerPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aOwnerPW ); + } + else + maPreparedOwnerPassword = Sequence< NamedValue >(); + } + enablePermissionControls(); +} + +void ImpPDFTabSecurityPage::enablePermissionControls() +{ + bool bIsPDFASel = false; + ImpPDFTabDialog* pParent = static_cast(GetDialogController()); + ImpPDFTabGeneralPage* pGeneralPage = pParent ? pParent->getGeneralPage() : nullptr; + if (pGeneralPage) + { + bIsPDFASel = pGeneralPage->IsPdfaSelected(); + } + if (bIsPDFASel) + { + mxUserPwdPdfa->show(); + mxUserPwdSet->hide(); + mxUserPwdUnset->hide(); + } + else + { + if (mbHaveUserPassword && m_xContainer->get_sensitive()) + { + mxUserPwdSet->show(); + mxUserPwdUnset->hide(); + mxUserPwdPdfa->hide(); + } + else + { + mxUserPwdUnset->show(); + mxUserPwdSet->hide(); + mxUserPwdPdfa->hide(); + } + } + + bool bLocalEnable = mbHaveOwnerPassword && m_xContainer->get_sensitive(); + if (bIsPDFASel) + { + mxOwnerPwdPdfa->show(); + mxOwnerPwdSet->hide(); + mxOwnerPwdUnset->hide(); + } + else + { + if (bLocalEnable) + { + mxOwnerPwdSet->show(); + mxOwnerPwdUnset->hide(); + mxOwnerPwdPdfa->hide(); + } + else + { + mxOwnerPwdUnset->show(); + mxOwnerPwdSet->hide(); + mxOwnerPwdPdfa->hide(); + } + } + + mxPrintPermissions->set_sensitive(bLocalEnable); + mxChangesAllowed->set_sensitive(bLocalEnable); + mxContent->set_sensitive(bLocalEnable); +} + +// This tab page is under control of the PDF/A-1a checkbox: +// TODO: implement a method to do it. +void ImpPDFTabSecurityPage::ImplPDFASecurityControl( bool bEnableSecurity ) +{ + m_xContainer->set_sensitive(bEnableSecurity); + // after enable, check the status of control as if the dialog was initialized + enablePermissionControls(); +} + +/// The link preferences tab page (relative and other stuff) +ImpPDFTabLinksPage::ImpPDFTabLinksPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdflinkspage.ui", "PdfLinksPage", &rCoreSet) + , mbOpnLnksDefaultUserState(false) + , mbOpnLnksLaunchUserState(false) + , mbOpnLnksBrowserUserState(false) + , m_xCbExprtBmkrToNmDst(m_xBuilder->weld_check_button("export")) + , m_xCbOOoToPDFTargets(m_xBuilder->weld_check_button("convert")) + , m_xCbExportRelativeFsysLinks(m_xBuilder->weld_check_button("exporturl")) + , m_xRbOpnLnksDefault(m_xBuilder->weld_radio_button("default")) + , m_xRbOpnLnksLaunch(m_xBuilder->weld_radio_button("openpdf")) + , m_xRbOpnLnksBrowser(m_xBuilder->weld_radio_button("openinternet")) +{ +} + +ImpPDFTabLinksPage::~ImpPDFTabLinksPage() +{ +} + +std::unique_ptr ImpPDFTabLinksPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique(pPage, pController, *rAttrSet); +} + +void ImpPDFTabLinksPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mbExportRelativeFsysLinks = m_xCbExportRelativeFsysLinks->get_active(); + + bool bIsPDFASel = false; + ImpPDFTabGeneralPage* pGeneralPage = pParent->getGeneralPage(); + if (pGeneralPage) + bIsPDFASel = pGeneralPage->IsPdfaSelected(); + // if PDF/A-1 was not selected while exiting dialog... + if( !bIsPDFASel ) + { + // ...get the control states + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); + } + // the control states, or the saved is used + // to form the stored selection + pParent->mnViewPDFMode = 0; + if( mbOpnLnksBrowserUserState ) + pParent->mnViewPDFMode = 2; + else if( mbOpnLnksLaunchUserState ) + pParent->mnViewPDFMode = 1; + + pParent->mbConvertOOoTargets = m_xCbOOoToPDFTargets->get_active(); + pParent->mbExportBmkToPDFDestination = m_xCbExprtBmkrToNmDst->get_active(); +} + +void ImpPDFTabLinksPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + m_xCbOOoToPDFTargets->set_active(pParent->mbConvertOOoTargets); + m_xCbExprtBmkrToNmDst->set_active(pParent->mbExportBmkToPDFDestination); + + m_xRbOpnLnksDefault->connect_toggled(LINK(this, ImpPDFTabLinksPage, ClickRbOpnLnksDefaultHdl)); + m_xRbOpnLnksBrowser->connect_toggled(LINK(this, ImpPDFTabLinksPage, ClickRbOpnLnksBrowserHdl)); + + m_xCbExportRelativeFsysLinks->set_active(pParent->mbExportRelativeFsysLinks); + switch( pParent->mnViewPDFMode ) + { + default: + case 0: + m_xRbOpnLnksDefault->set_active(true); + mbOpnLnksDefaultUserState = true; + break; + case 1: + m_xRbOpnLnksLaunch->set_active(true); + mbOpnLnksLaunchUserState = true; + break; + case 2: + m_xRbOpnLnksBrowser->set_active(true); + mbOpnLnksBrowserUserState = true; + break; + } + + // now check the status of PDF/A selection + // and set the link action accordingly + // PDF/A-2 doesn't allow launch action on links + + ImpPDFTabGeneralPage* pGeneralPage = pParent->getGeneralPage(); + if (pGeneralPage) + ImplPDFALinkControl(!pGeneralPage->mxCbPDFA->get_active()); +} + + +/** Called from general tab, with PDFA/1 selection status. + Retrieves/store the status of Launch action selection. + */ +void ImpPDFTabLinksPage::ImplPDFALinkControl( bool bEnableLaunch ) +{ + // set the value and position of link type selection + if( bEnableLaunch ) + { + m_xRbOpnLnksLaunch->set_sensitive(true); + // restore user state with no PDF/A-1 selected + m_xRbOpnLnksDefault->set_active(mbOpnLnksDefaultUserState); + m_xRbOpnLnksLaunch->set_active(mbOpnLnksLaunchUserState); + m_xRbOpnLnksBrowser->set_active(mbOpnLnksBrowserUserState); + } + else + { + // save user state with no PDF/A-1 selected + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); + m_xRbOpnLnksLaunch->set_sensitive(false); + if (mbOpnLnksLaunchUserState) + m_xRbOpnLnksBrowser->set_active(true); + } +} + +/// Reset the memory of Launch action present when PDF/A-1 was requested +IMPL_LINK_NOARG(ImpPDFTabLinksPage, ClickRbOpnLnksDefaultHdl, weld::Toggleable&, void) +{ + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); +} + +/// Reset the memory of a launch action present when PDF/A-1 was requested +IMPL_LINK_NOARG(ImpPDFTabLinksPage, ClickRbOpnLnksBrowserHdl, weld::Toggleable&, void) +{ + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); +} + +ImplErrorDialog::ImplErrorDialog(weld::Window* pParent, const std::set& rErrors) + : MessageDialogController(pParent, "filter/ui/warnpdfdialog.ui", "WarnPDFDialog", "grid") + , m_xErrors(m_xBuilder->weld_tree_view("errors")) + , m_xExplanation(m_xBuilder->weld_label("message")) +{ + int nWidth = m_xErrors->get_approximate_digit_width() * 26; + int nHeight = m_xErrors->get_height_rows(9); + m_xErrors->set_size_request(nWidth, nHeight); + m_xExplanation->set_size_request(nWidth, nHeight); + + for (auto const& error : rErrors) + { + switch(error) + { + case vcl::PDFWriter::Warning_Transparency_Omitted_PDFA: + m_xErrors->append(PDFFilterResId(STR_WARN_TRANSP_PDFA), PDFFilterResId(STR_WARN_TRANSP_PDFA_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Warning_Transparency_Omitted_PDF13: + m_xErrors->append(PDFFilterResId(STR_WARN_TRANSP_VERSION), PDFFilterResId(STR_WARN_TRANSP_VERSION_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Warning_FormAction_Omitted_PDFA: + m_xErrors->append(PDFFilterResId(STR_WARN_FORMACTION_PDFA), PDFFilterResId(STR_WARN_FORMACTION_PDFA_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Warning_Transparency_Converted: + m_xErrors->append(PDFFilterResId(STR_WARN_TRANSP_CONVERTED), PDFFilterResId(STR_WARN_TRANSP_CONVERTED_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Error_Signature_Failed: + m_xErrors->append(PDFFilterResId(STR_ERR_PDF_EXPORT_ABORTED), PDFFilterResId(STR_ERR_SIGNATURE_FAILED), "dialog-error"); + break; + default: + break; + } + } + + if (m_xErrors->n_children() > 0) + { + m_xErrors->select(0); + m_xExplanation->set_label(m_xErrors->get_id(0)); + } + + m_xErrors->connect_changed(LINK(this, ImplErrorDialog, SelectHdl)); +} + +IMPL_LINK_NOARG(ImplErrorDialog, SelectHdl, weld::TreeView&, void) +{ + OUString aExplanation = m_xErrors->get_selected_id(); + m_xExplanation->set_label(aExplanation); +} + +/// The digital signatures tab page +ImpPDFTabSigningPage::ImpPDFTabSigningPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfsignpage.ui", "PdfSignPage", &rCoreSet) + , mxEdSignCert(m_xBuilder->weld_entry("cert")) + , mxPbSignCertSelect(m_xBuilder->weld_button("select")) + , mxPbSignCertClear(m_xBuilder->weld_button("clear")) + , mxEdSignPassword(m_xBuilder->weld_entry("password")) + , mxEdSignLocation(m_xBuilder->weld_entry("location")) + , mxEdSignContactInfo(m_xBuilder->weld_entry("contact")) + , mxEdSignReason(m_xBuilder->weld_entry("reason")) + , mxLBSignTSA(m_xBuilder->weld_combo_box("tsa")) +{ + mxPbSignCertSelect->set_sensitive(true); + mxPbSignCertSelect->connect_clicked(LINK(this, ImpPDFTabSigningPage, ClickmaPbSignCertSelect)); + mxPbSignCertClear->connect_clicked(LINK(this, ImpPDFTabSigningPage, ClickmaPbSignCertClear)); +} + +ImpPDFTabSigningPage::~ImpPDFTabSigningPage() +{ +} + +IMPL_LINK_NOARG(ImpPDFTabSigningPage, ClickmaPbSignCertSelect, weld::Button&, void) +{ + Reference< security::XDocumentDigitalSignatures > xSigner( + security::DocumentDigitalSignatures::createDefault( + comphelper::getProcessComponentContext())); + xSigner->setParentWindow(GetFrameWeld()->GetXWindow()); + + // The use may provide a description while choosing a certificate. + OUString aDescription; + maSignCertificate = xSigner->selectSigningCertificateWithType( + security::CertificateKind::CertificateKind_X509, aDescription); + + if (!maSignCertificate.is()) + return; + + mxEdSignCert->set_text(maSignCertificate->getSubjectName()); + mxPbSignCertClear->set_sensitive(true); + mxEdSignLocation->set_sensitive(true); + mxEdSignPassword->set_sensitive(true); + mxEdSignContactInfo->set_sensitive(true); + mxEdSignReason->set_sensitive(true); + mxEdSignReason->set_text(aDescription); + + try + { + std::optional> aTSAURLs(officecfg::Office::Common::Security::Scripting::TSAURLs::get()); + if (aTSAURLs) + { + const css::uno::Sequence& rTSAURLs = *aTSAURLs; + for (auto const& elem : rTSAURLs) + { + mxLBSignTSA->append_text(elem); + } + } + } + catch (const uno::Exception &) + { + TOOLS_INFO_EXCEPTION("filter.pdf", "TSAURLsDialog::TSAURLsDialog()"); + } + + // If more than only the "None" entry is there, enable the ListBox + if (mxLBSignTSA->get_count() > 1) + mxLBSignTSA->set_sensitive(true); +} + +IMPL_LINK_NOARG(ImpPDFTabSigningPage, ClickmaPbSignCertClear, weld::Button&, void) +{ + mxEdSignCert->set_text(""); + maSignCertificate.clear(); + mxPbSignCertClear->set_sensitive(false); + mxEdSignLocation->set_sensitive(false); + mxEdSignPassword->set_sensitive(false); + mxEdSignContactInfo->set_sensitive(false); + mxEdSignReason->set_sensitive(false); + mxLBSignTSA->set_sensitive(false); +} + +std::unique_ptr ImpPDFTabSigningPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique(pPage, pController, *rAttrSet); +} + +void ImpPDFTabSigningPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mbSignPDF = maSignCertificate.is(); + pParent->maSignCertificate = maSignCertificate; + pParent->msSignLocation = mxEdSignLocation->get_text(); + pParent->msSignPassword = mxEdSignPassword->get_text(); + pParent->msSignContact = mxEdSignContactInfo->get_text(); + pParent->msSignReason = mxEdSignReason->get_text(); + // Entry 0 is 'None' + if (mxLBSignTSA->get_active() >= 1) + pParent->msSignTSA = mxLBSignTSA->get_active_text(); +} + +void ImpPDFTabSigningPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + mxEdSignLocation->set_sensitive(false); + mxEdSignPassword->set_sensitive(false); + mxEdSignContactInfo->set_sensitive(false); + mxEdSignReason->set_sensitive(false); + mxLBSignTSA->set_sensitive(false); + mxPbSignCertClear->set_sensitive(false); + + if (pParent->mbSignPDF) + { + mxEdSignPassword->set_text(pParent->msSignPassword); + mxEdSignLocation->set_text(pParent->msSignLocation); + mxEdSignContactInfo->set_text(pParent->msSignContact); + mxEdSignReason->set_text(pParent->msSignReason); + maSignCertificate = pParent->maSignCertificate; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/impdialog.hxx b/filter/source/pdf/impdialog.hxx new file mode 100644 index 000000000..219d47e6d --- /dev/null +++ b/filter/source/pdf/impdialog.hxx @@ -0,0 +1,419 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include + +class ImpPDFTabGeneralPage; +class ImpPDFTabViewerPage; +class ImpPDFTabOpnFtrPage; +class ImpPDFTabLinksPage; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +class ImplErrorDialog : public weld::MessageDialogController +{ +private: + std::unique_ptr m_xErrors; + std::unique_ptr m_xExplanation; + + DECL_LINK(SelectHdl, weld::TreeView&, void); + +public: + explicit ImplErrorDialog(weld::Window* pParent, const std::set& rErrorCodes); +}; + + +class ImpPDFTabSecurityPage; +class ImpPDFTabLinksPage; + + +/// Class tabbed dialog +class ImpPDFTabDialog final : public SfxTabDialogController +{ + css::uno::Reference mrDoc; + weld::Window* mpParent; + + FilterConfigItem maConfigItem; + FilterConfigItem maConfigI18N; + + Any maSelection; + + DECL_LINK(CancelHdl, weld::Button&, void); + DECL_LINK(OkHdl, weld::Button&, void); + + // the following data are the configuration used throughout the dialog and pages + bool mbIsPresentation; + bool mbIsSpreadsheet; + bool mbIsWriter; + bool mbSelectionPresent; + bool mbUseCTLFont; + bool mbUseLosslessCompression; + sal_Int32 mnQuality; + bool mbReduceImageResolution; + sal_Int32 mnMaxImageResolution; + bool mbUseTaggedPDF; + bool mbUseTaggedPDFUserSelection; + sal_Int32 mnPDFTypeSelection; + bool mbPDFUACompliance; + bool mbExportNotes; + bool mbViewPDF; + bool mbUseReferenceXObject; + bool mbExportNotesPages; + bool mbExportOnlyNotesPages; + bool mbUseTransitionEffects; + bool mbIsSkipEmptyPages; + bool mbIsExportPlaceholders; + bool mbAddStream; + sal_Int32 mnFormsType; + bool mbExportFormFields; + bool mbAllowDuplicateFieldNames; + bool mbExportBookmarks; + bool mbExportHiddenSlides; + bool mbSinglePageSheets; + sal_Int32 mnOpenBookmarkLevels; + + bool mbHideViewerToolbar; + bool mbHideViewerMenubar; + bool mbHideViewerWindowControls; + bool mbResizeWinToInit; + bool mbCenterWindow; + bool mbOpenInFullScreenMode; + bool mbDisplayPDFDocumentTitle; + sal_Int32 mnMagnification; + sal_Int32 mnInitialView; + sal_Int32 mnZoom; + sal_Int32 mnInitialPage; + + sal_Int32 mnPageLayout; + bool mbFirstPageLeft; + + bool mbEncrypt; + + bool mbRestrictPermissions; + css::uno::Sequence< css::beans::NamedValue > maPreparedOwnerPassword; + sal_Int32 mnPrint; + sal_Int32 mnChangesAllowed; + bool mbCanCopyOrExtract; + bool mbCanExtractForAccessibility; + css::uno::Reference< css::beans::XMaterialHolder > mxPreparedPasswords; + + std::shared_ptr< svx::AccessibilityCheckDialog > mpAccessibilityCheckDialog; + + bool mbIsRangeChecked; + OUString msPageRange; + bool mbSelectionIsChecked; + + bool mbExportRelativeFsysLinks; + sal_Int32 mnViewPDFMode; + bool mbConvertOOoTargets; + bool mbExportBmkToPDFDestination; + + bool mbSignPDF; + OUString msSignPassword; + OUString msSignLocation; + OUString msSignContact; + OUString msSignReason; + css::uno::Reference< css::security::XCertificate > maSignCertificate; + OUString msSignTSA; + + OUString maWatermarkText; + +public: + + friend class ImpPDFTabGeneralPage; + friend class ImpPDFTabViewerPage; + friend class ImpPDFTabOpnFtrPage; + friend class ImpPDFTabSecurityPage; + friend class ImpPDFTabLinksPage; + friend class ImpPDFTabSigningPage; + + ImpPDFTabDialog(weld::Window* pParent, const Sequence< PropertyValue >& rFilterData, + const css::uno::Reference< XComponent >& rDoc); + virtual ~ImpPDFTabDialog() override; + + Sequence< PropertyValue > GetFilterData(); + + ImpPDFTabSecurityPage* getSecurityPage() const; + ImpPDFTabLinksPage* getLinksPage() const; + ImpPDFTabGeneralPage* getGeneralPage() const; + +private: + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; +}; + + +/// Class tab page general +class ImpPDFTabGeneralPage : public SfxTabPage +{ + friend class ImpPDFTabLinksPage; + + bool mbUseTaggedPDFUserSelection; + bool mbIsPresentation; + bool mbIsSpreadsheet; + bool mbIsWriter; + ImpPDFTabDialog* mpParent; + + std::unique_ptr mxRbAll; + std::unique_ptr mxRbRange; + std::unique_ptr mxRbSelection; + std::unique_ptr mxEdPages; + std::unique_ptr mxSelectedSheets; + std::unique_ptr mxRbLosslessCompression; + std::unique_ptr mxRbJPEGCompression; + std::unique_ptr mxQualityFrame; + std::unique_ptr mxNfQuality; + std::unique_ptr mxCbReduceImageResolution; + std::unique_ptr mxCoReduceImageResolution; + std::unique_ptr mxCbPDFA; + std::unique_ptr mxCbPDFUA; + std::unique_ptr mxRbPDFAVersion; + std::unique_ptr mxCbTaggedPDF; + std::unique_ptr mxCbExportFormFields; + std::unique_ptr mxFormsFrame; + std::unique_ptr mxLbFormsFormat; + std::unique_ptr mxCbAllowDuplicateFieldNames; + std::unique_ptr mxCbExportBookmarks; + std::unique_ptr mxCbExportHiddenSlides; + std::unique_ptr mxCbSinglePageSheets; + std::unique_ptr mxCbExportNotes; + std::unique_ptr mxCbViewPDF; + std::unique_ptr mxCbUseReferenceXObject; + std::unique_ptr mxCbExportNotesPages; + std::unique_ptr mxCbExportOnlyNotesPages; + std::unique_ptr mxCbExportEmptyPages; + std::unique_ptr mxCbExportPlaceholders; + std::unique_ptr mxCbAddStream; + std::unique_ptr mxCbWatermark; + std::unique_ptr mxFtWatermark; + std::unique_ptr mxEdWatermark; + std::unique_ptr mxSlidesFt; + std::unique_ptr mxSheetsFt; + + DECL_LINK(ToggleAllHdl, weld::Toggleable&, void); + DECL_LINK(TogglePagesHdl, weld::Toggleable&, void); + DECL_LINK(ToggleSelectionHdl, weld::Toggleable&, void); + DECL_LINK(ToggleCompressionHdl, weld::Toggleable&, void); + DECL_LINK(ToggleReduceImageResolutionHdl, weld::Toggleable&, void); + DECL_LINK(ToggleWatermarkHdl, weld::Toggleable&, void); + DECL_LINK(ToggleAddStreamHdl, weld::Toggleable&, void); + DECL_LINK(ToggleExportFormFieldsHdl, weld::Toggleable&, void); + DECL_LINK(ToggleExportNotesPagesHdl, weld::Toggleable&, void); + + void TogglePagesHdl(); + void EnableExportNotesPages(); + + DECL_LINK(TogglePDFVersionOrUniversalAccessibilityHandle, weld::Toggleable&, void); + +public: + + ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabGeneralPage() override; + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + void GetFilterConfigItem(ImpPDFTabDialog* paParent); + void SetFilterConfigItem(ImpPDFTabDialog* paParent); + bool IsPdfaSelected() const { return mxCbPDFA->get_active(); } + bool IsPdfUaSelected() const { return mxCbPDFUA->get_active(); } +}; + +/// Class tab page viewer +class ImpPDFTabOpnFtrPage : public SfxTabPage +{ + bool mbUseCTLFont; + + std::unique_ptr mxRbOpnPageOnly; + std::unique_ptr mxRbOpnOutline; + std::unique_ptr mxRbOpnThumbs; + std::unique_ptr mxNumInitialPage; + std::unique_ptr mxRbMagnDefault; + std::unique_ptr mxRbMagnFitWin; + std::unique_ptr mxRbMagnFitWidth; + std::unique_ptr mxRbMagnFitVisible; + std::unique_ptr mxRbMagnZoom; + std::unique_ptr mxNumZoom; + std::unique_ptr mxRbPgLyDefault; + std::unique_ptr mxRbPgLySinglePage; + std::unique_ptr mxRbPgLyContinue; + std::unique_ptr mxRbPgLyContinueFacing; + std::unique_ptr mxCbPgLyFirstOnLeft; + + DECL_LINK(ToggleRbPgLyContinueFacingHdl, weld::Toggleable&, void); + DECL_LINK(ToggleRbMagnHdl, weld::Toggleable&, void); + + void ToggleRbPgLyContinueFacingHdl(); + +public: + ImpPDFTabOpnFtrPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabOpnFtrPage() override; + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); +}; + +/// Class tab page viewer +class ImpPDFTabViewerPage : public SfxTabPage +{ + bool mbIsPresentation; + + std::unique_ptr m_xCbResWinInit; + std::unique_ptr m_xCbCenterWindow; + std::unique_ptr m_xCbOpenFullScreen; + std::unique_ptr m_xCbDispDocTitle; + std::unique_ptr m_xCbHideViewerMenubar; + std::unique_ptr m_xCbHideViewerToolbar; + std::unique_ptr m_xCbHideViewerWindowControls; + std::unique_ptr m_xCbTransitionEffects; + std::unique_ptr m_xRbAllBookmarkLevels; + std::unique_ptr m_xRbVisibleBookmarkLevels; + std::unique_ptrm_xNumBookmarkLevels; + + DECL_LINK(ToggleRbBookmarksHdl, weld::Toggleable&, void); + +public: + ImpPDFTabViewerPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabViewerPage() override; + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); +}; + +/// Class security tab page +class ImpPDFTabSecurityPage : public SfxTabPage +{ + OUString msStrSetPwd; + OUString msUserPwdTitle; + bool mbHaveOwnerPassword; + bool mbHaveUserPassword; + css::uno::Sequence< css::beans::NamedValue > maPreparedOwnerPassword; + OUString msOwnerPwdTitle; + + css::uno::Reference< css::beans::XMaterialHolder > mxPreparedPasswords; + + std::unique_ptr mxPbSetPwd; + std::unique_ptr mxUserPwdSet; + std::unique_ptr mxUserPwdUnset; + std::unique_ptr mxUserPwdPdfa; + std::unique_ptr mxOwnerPwdSet; + std::unique_ptr mxOwnerPwdUnset; + std::unique_ptr mxOwnerPwdPdfa; + std::unique_ptr mxPrintPermissions; + std::unique_ptr mxRbPrintNone; + std::unique_ptr mxRbPrintLowRes; + std::unique_ptr mxRbPrintHighRes; + std::unique_ptr mxChangesAllowed; + std::unique_ptr mxRbChangesNone; + std::unique_ptr mxRbChangesInsDel; + std::unique_ptr mxRbChangesFillForm; + std::unique_ptr mxRbChangesComment; + std::unique_ptr mxRbChangesAnyNoCopy; + std::unique_ptr mxContent; + std::unique_ptr mxCbEnableCopy; + std::unique_ptr mxCbEnableAccessibility; + std::unique_ptr mxPasswordTitle; + + DECL_LINK(ClickmaPbSetPwdHdl, weld::Button&, void); + + void enablePermissionControls(); + +public: + ImpPDFTabSecurityPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabSecurityPage() override; + + static std::unique_ptr Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); + void ImplPDFASecurityControl( bool bEnableSecurity ); + bool hasPassword() const { return mbHaveOwnerPassword || mbHaveUserPassword; } +}; + +/// Implements the relative link stuff +class ImpPDFTabLinksPage : public SfxTabPage +{ + bool mbOpnLnksDefaultUserState; + bool mbOpnLnksLaunchUserState; + bool mbOpnLnksBrowserUserState; + + std::unique_ptr m_xCbExprtBmkrToNmDst; + std::unique_ptr m_xCbOOoToPDFTargets; + std::unique_ptr m_xCbExportRelativeFsysLinks; + std::unique_ptr m_xRbOpnLnksDefault; + std::unique_ptr m_xRbOpnLnksLaunch; + std::unique_ptr m_xRbOpnLnksBrowser; + + DECL_LINK(ClickRbOpnLnksDefaultHdl, weld::Toggleable&, void); + DECL_LINK(ClickRbOpnLnksBrowserHdl, weld::Toggleable&, void); + +public: + ImpPDFTabLinksPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabLinksPage() override; + + static std::unique_ptr Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); + + void ImplPDFALinkControl( bool bEnableLaunch ); +}; + +//class to implement the digital signing +class ImpPDFTabSigningPage : public SfxTabPage +{ + css::uno::Reference< css::security::XCertificate > maSignCertificate; + + std::unique_ptr mxEdSignCert; + std::unique_ptr mxPbSignCertSelect; + std::unique_ptr mxPbSignCertClear; + std::unique_ptr mxEdSignPassword; + std::unique_ptr mxEdSignLocation; + std::unique_ptr mxEdSignContactInfo; + std::unique_ptr mxEdSignReason; + std::unique_ptr mxLBSignTSA; + + DECL_LINK(ClickmaPbSignCertSelect, weld::Button&, void); + DECL_LINK(ClickmaPbSignCertClear, weld::Button&, void); + +public: + ImpPDFTabSigningPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabSigningPage() override; + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfdecomposer.cxx b/filter/source/pdf/pdfdecomposer.cxx new file mode 100644 index 000000000..7a032bf36 --- /dev/null +++ b/filter/source/pdf/pdfdecomposer.cxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace css; + +namespace +{ +/// Class to convert the PDF data into a XPrimitive2D (containing only a bitmap). +class XPdfDecomposer + : public ::cppu::WeakAggImplHelper2 +{ +public: + explicit XPdfDecomposer(uno::Reference const& context); + XPdfDecomposer(const XPdfDecomposer&) = delete; + XPdfDecomposer& operator=(const XPdfDecomposer&) = delete; + + // XPdfDecomposer + uno::Sequence> SAL_CALL + getDecomposition(const uno::Reference& xDataContainer, + const uno::Sequence& xDecompositionParameters) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString&) override; + uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +XPdfDecomposer::XPdfDecomposer(uno::Reference const&) {} + +uno::Sequence> SAL_CALL +XPdfDecomposer::getDecomposition(const uno::Reference& xDataContainer, + const uno::Sequence& xParameters) +{ + sal_Int32 nPageIndex = -1; + + for (const beans::PropertyValue& rProperty : xParameters) + { + if (rProperty.Name == "PageIndex") + { + rProperty.Value >>= nPageIndex; + break; + } + } + + if (nPageIndex < 0) + nPageIndex = 0; + + BinaryDataContainer aDataContainer = vcl::convertUnoBinaryDataContainer(xDataContainer); + + std::vector aBitmaps; + int rv = vcl::RenderPDFBitmaps(aDataContainer.getData(), aDataContainer.getSize(), aBitmaps, + nPageIndex, 1); + if (rv == 0) + return {}; // happens if we do not have PDFium + + BitmapEx aReplacement(aBitmaps[0]); + + // short form for scale and translate transformation + const Size aBitmapSize(aReplacement.GetSizePixel()); + // ImpGraphic::getPrefMapMode() requires mm100 for bitmaps rendered from vector graphic data. + const Size aMM100( + Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, MapMode(MapUnit::Map100thMM))); + const basegfx::B2DHomMatrix aBitmapTransform(basegfx::utils::createScaleTranslateB2DHomMatrix( + aMM100.getWidth(), aMM100.getHeight(), 0, 0)); + + // create primitive + return drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::BitmapPrimitive2D( + VCLUnoHelper::CreateVCLXBitmap(aReplacement), aBitmapTransform) + } + .toSequence(); +} + +OUString SAL_CALL XPdfDecomposer::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFDecomposer"; +} + +sal_Bool SAL_CALL XPdfDecomposer::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence SAL_CALL XPdfDecomposer::getSupportedServiceNames() +{ + return { "com.sun.star.graphic.PdfTools" }; +} +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PdfDecomposer_get_implementation(css::uno::XComponentContext* context, + css::uno::Sequence const&) +{ + return cppu::acquire(new XPdfDecomposer(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/filter/source/pdf/pdfdialog.cxx b/filter/source/pdf/pdfdialog.cxx new file mode 100644 index 000000000..7c3e5dda1 --- /dev/null +++ b/filter/source/pdf/pdfdialog.cxx @@ -0,0 +1,139 @@ +/* -*- 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 "pdfdialog.hxx" +#include "impdialog.hxx" +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +PDFDialog::PDFDialog( const Reference< XComponentContext > &rxContext ) +: PDFDialog_Base( rxContext ) +{ +} + + +PDFDialog::~PDFDialog() +{ +} + + +Sequence< sal_Int8 > SAL_CALL PDFDialog::getImplementationId() +{ + return css::uno::Sequence(); +} + + +OUString SAL_CALL PDFDialog::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFDialog"; +} + + +Sequence< OUString > SAL_CALL PDFDialog::getSupportedServiceNames() +{ + return { "com.sun.star.document.PDFDialog" }; +} + +std::unique_ptr PDFDialog::createDialog(const css::uno::Reference& rParent) +{ + if( mxSrcDoc.is() ) + return std::make_unique(Application::GetFrameWeld(rParent), maFilterData, mxSrcDoc); + return nullptr; +} + +void PDFDialog::executedDialog( sal_Int16 nExecutionResult ) +{ + if (nExecutionResult && m_xDialog) + maFilterData = static_cast(m_xDialog.get())->GetFilterData(); + destroyDialog(); +} + +Reference< XPropertySetInfo > SAL_CALL PDFDialog::getPropertySetInfo() +{ + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& PDFDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* PDFDialog::createArrayHelper() const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + + +Sequence< PropertyValue > SAL_CALL PDFDialog::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 PDFDialog::setPropertyValues( const Sequence< PropertyValue >& rProps ) +{ + maMediaDescriptor = rProps; + + for( const PropertyValue& rProp : std::as_const(maMediaDescriptor) ) + { + if ( rProp.Name == "FilterData" ) + { + rProp.Value >>= maFilterData; + break; + } + } +} + + +void SAL_CALL PDFDialog::setSourceDocument( const Reference< XComponent >& xDoc ) +{ + mxSrcDoc = xDoc; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PDFDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new PDFDialog(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfdialog.hxx b/filter/source/pdf/pdfdialog.hxx new file mode 100644 index 000000000..fcfd1d097 --- /dev/null +++ b/filter/source/pdf/pdfdialog.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +typedef ::cppu::ImplInheritanceHelper < ::svt::OGenericUnoDialog, XPropertyAccess, XExporter > PDFDialog_Base; + +class PDFDialog final: + public PDFDialog_Base, + public ::comphelper::OPropertyArrayUsageHelper< PDFDialog > +{ +private: + Sequence< PropertyValue > maMediaDescriptor; + Sequence< PropertyValue > maFilterData; + Reference< XComponent > mxSrcDoc; + + // OGenericUnoDialog + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual OUString SAL_CALL getImplementationName() override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + virtual std::unique_ptr createDialog(const css::uno::Reference& rParent) override; + virtual void executedDialog( sal_Int16 nExecutionResult ) override; + virtual Reference< XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // XPropertyAccess + using OPropertySetHelper::getPropertyValues; + virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override; + using OPropertySetHelper::setPropertyValues; + virtual void SAL_CALL setPropertyValues( const Sequence< PropertyValue >& aProps ) override; + + // XExporter + virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override; + +public: + + explicit PDFDialog( const Reference< XComponentContext >& rxContext ); + virtual ~PDFDialog() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx new file mode 100644 index 000000000..7a233aad0 --- /dev/null +++ b/filter/source/pdf/pdfexport.cxx @@ -0,0 +1,1374 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pdfexport.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::io; +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::graphic; + + +PDFExport::PDFExport( const Reference< XComponent >& rxSrcDoc, + const Reference< task::XStatusIndicator >& rxStatusIndicator, + const Reference< task::XInteractionHandler >& rxIH, + const Reference< XComponentContext >& xContext ) : + mxSrcDoc ( rxSrcDoc ), + mxContext ( xContext ), + mxStatusIndicator ( rxStatusIndicator ), + mxIH ( rxIH ), + mbUseTaggedPDF ( false ), + mnPDFTypeSelection ( 0 ), + mbPDFUACompliance ( false), + mbExportNotes ( true ), + mbExportPlaceholders ( false ), + mbUseReferenceXObject ( false ), + mbExportNotesPages ( false ), + mbExportOnlyNotesPages ( false ), + mbUseTransitionEffects ( true ), + mbExportBookmarks ( true ), + mbExportHiddenSlides ( false ), + mbSinglePageSheets ( false ), + mnOpenBookmarkLevels ( -1 ), + mbUseLosslessCompression ( false ), + mbReduceImageResolution ( true ), + mbSkipEmptyPages ( true ), + mbAddStream ( false ), + mnMaxImageResolution ( 300 ), + mnQuality ( 80 ), + mnFormsFormat ( 0 ), + mbExportFormFields ( true ), + mbAllowDuplicateFieldNames ( false ), + mnProgressValue ( 0 ), + mbRemoveTransparencies ( false ), + + mbIsRedactMode ( false ), + maWatermarkColor ( COL_LIGHTGREEN ), + maWatermarkFontName ( "Helvetica" ), + + mbHideViewerToolbar ( false ), + mbHideViewerMenubar ( false ), + mbHideViewerWindowControls ( false ), + mbFitWindow ( false ), + mbCenterWindow ( false ), + mbOpenInFullScreenMode ( false ), + mbDisplayPDFDocumentTitle ( true ), + mnPDFDocumentMode ( 0 ), + mnPDFDocumentAction ( 0 ), + mnZoom ( 100 ), + mnInitialPage ( 1 ), + mnPDFPageLayout ( 0 ), + + mbEncrypt ( false ), + mbRestrictPermissions ( false ), + mnPrintAllowed ( 2 ), + mnChangesAllowed ( 4 ), + mbCanCopyOrExtract ( true ), + mbCanExtractForAccessibility( true ), + + // #i56629 + mbExportRelativeFsysLinks ( false ), + mnDefaultLinkAction ( 0 ), + mbConvertOOoTargetToPDFTarget( false ), + mbExportBmkToDest ( false ), + mbSignPDF ( false ) +{ +} + + +PDFExport::~PDFExport() +{ +} + + +bool PDFExport::ExportSelection( vcl::PDFWriter& rPDFWriter, + Reference< css::view::XRenderable > const & rRenderable, + const Any& rSelection, + const StringRangeEnumerator& rRangeEnum, + Sequence< PropertyValue >& rRenderOptions, + sal_Int32 nPageCount ) +{ + bool bRet = false; + try + { + Any* pFirstPage = nullptr; + Any* pLastPage = nullptr; + + bool bExportNotesPages = false; + + auto rRenderOptionsRange = asNonConstRange(rRenderOptions); + for( sal_Int32 nData = 0, nDataCount = rRenderOptions.getLength(); nData < nDataCount; ++nData ) + { + if ( rRenderOptions[ nData ].Name == "IsFirstPage" ) + pFirstPage = &rRenderOptionsRange[ nData ].Value; + else if ( rRenderOptions[ nData ].Name == "IsLastPage" ) + pLastPage = &rRenderOptionsRange[ nData ].Value; + else if ( rRenderOptions[ nData ].Name == "ExportNotesPages" ) + rRenderOptionsRange[ nData ].Value >>= bExportNotesPages; + } + + OutputDevice* pOut = rPDFWriter.GetReferenceDevice(); + + if( pOut ) + { + if ( nPageCount ) + { + vcl::PDFExtOutDevData& rPDFExtOutDevData = dynamic_cast(*pOut->GetExtOutDevData()); + rPDFExtOutDevData.SetIsExportNotesPages( bExportNotesPages ); + + sal_Int32 nCurrentPage(0); + StringRangeEnumerator::Iterator aIter = rRangeEnum.begin(); + StringRangeEnumerator::Iterator aEnd = rRangeEnum.end(); + while ( aIter != aEnd ) + { + const Sequence< PropertyValue > aRenderer( rRenderable->getRenderer( *aIter, rSelection, rRenderOptions ) ); + awt::Size aPageSize; + + for( const PropertyValue& rProp : aRenderer ) + { + if ( rProp.Name == "PageSize" ) + { + rProp.Value >>= aPageSize; + break; + } + } + + rPDFExtOutDevData.SetCurrentPageNumber( nCurrentPage ); + + GDIMetaFile aMtf; + const MapMode aMapMode( MapUnit::Map100thMM ); + const Size aMtfSize( aPageSize.Width, aPageSize.Height ); + + pOut->Push(); + pOut->EnableOutput( false ); + pOut->SetMapMode( aMapMode ); + + aMtf.SetPrefSize( aMtfSize ); + aMtf.SetPrefMapMode( aMapMode ); + aMtf.Record( pOut ); + + // #i35176# + // IsLastPage property. + const sal_Int32 nCurrentRenderer = *aIter; + ++aIter; + if ( pLastPage && aIter == aEnd ) + *pLastPage <<= true; + + rRenderable->render( nCurrentRenderer, rSelection, rRenderOptions ); + + aMtf.Stop(); + aMtf.WindStart(); + + bool bEmptyPage = false; + if( aMtf.GetActionSize() && + ( !mbSkipEmptyPages || aPageSize.Width || aPageSize.Height ) ) + { + // We convert the whole metafile into a bitmap to get rid of the + // text covered by redaction shapes + if (mbIsRedactMode) + { + try + { + Graphic aGraph(aMtf); + // use antialiasing to improve how graphic objects look + BitmapEx bmp = aGraph.GetBitmapEx(GraphicConversionParameters(Size(0, 0), false, true, false)); + Graphic bgraph(bmp); + aMtf = bgraph.GetGDIMetaFile(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("filter.pdf", "Something went wrong while converting metafile to bitmap"); + } + } + + ImplExportPage(rPDFWriter, rPDFExtOutDevData, aMtf); + bRet = true; + } + else + { + bEmptyPage = true; + } + + pOut->Pop(); + + if ( mxStatusIndicator.is() ) + mxStatusIndicator->setValue( mnProgressValue ); + if ( pFirstPage ) + *pFirstPage <<= false; + + ++mnProgressValue; + if (!bEmptyPage) + { + // Calculate the page number in the PDF output, which may be smaller than the page number in + // case of hidden slides or a partial export. + ++nCurrentPage; + } + } + } + else + { + bRet = true; // #i18334# nPageCount == 0, + rPDFWriter.NewPage( 10000, 10000 ); // creating dummy page + rPDFWriter.SetMapMode(MapMode(MapUnit::Map100thMM)); + } + } + } + catch(const RuntimeException &) + { + } + return bRet; +} + +namespace { + +class PDFExportStreamDoc : public vcl::PDFOutputStream +{ +private: + + Reference< XComponent > m_xSrcDoc; + Sequence< beans::NamedValue > m_aPreparedPassword; + +public: + + PDFExportStreamDoc( const Reference< XComponent >& xDoc, const Sequence& rPwd ) + : m_xSrcDoc( xDoc ), + m_aPreparedPassword( rPwd ) + {} + + virtual void write( const Reference< XOutputStream >& xStream ) override; +}; + +} + +void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream ) +{ + Reference< css::frame::XStorable > xStore( m_xSrcDoc, UNO_QUERY ); + if( !xStore.is() ) + return; + + Sequence< beans::PropertyValue > aArgs( 2 + (m_aPreparedPassword.hasElements() ? 1 : 0) ); + aArgs.getArray()[0].Name = "FilterName"; + aArgs.getArray()[1].Name = "OutputStream"; + aArgs.getArray()[1].Value <<= xStream; + if( m_aPreparedPassword.hasElements() ) + { + aArgs.getArray()[2].Name = "EncryptionData"; + aArgs.getArray()[2].Value <<= m_aPreparedPassword; + } + + try + { + xStore->storeToURL( "private:stream", aArgs ); + } + catch( const IOException& ) + { + } +} + + +static OUString getMimetypeForDocument( const Reference< XComponentContext >& xContext, + const Reference< XComponent >& xDoc ) noexcept +{ + OUString aDocMimetype; + try + { + // get document service name + Reference< css::frame::XStorable > xStore( xDoc, UNO_QUERY ); + Reference< frame::XModuleManager2 > xModuleManager = frame::ModuleManager::create(xContext); + if( xStore.is() ) + { + OUString aDocServiceName = xModuleManager->identify( Reference< XInterface >( xStore, uno::UNO_QUERY ) ); + if ( !aDocServiceName.isEmpty() ) + { + // get the actual filter name + Reference< lang::XMultiServiceFactory > xConfigProvider = + configuration::theDefaultProvider::get( xContext ); + beans::NamedValue aPathProp; + aPathProp.Name = "nodepath"; + aPathProp.Value <<= OUString( "/org.openoffice.Setup/Office/Factories/" ); + uno::Sequence< uno::Any > aArgs{ uno::Any(aPathProp) }; + + Reference< container::XNameAccess > xSOFConfig( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", aArgs ), + uno::UNO_QUERY ); + + Reference< container::XNameAccess > xApplConfig; + xSOFConfig->getByName( aDocServiceName ) >>= xApplConfig; + if ( xApplConfig.is() ) + { + OUString aFilterName; + xApplConfig->getByName( "ooSetupFactoryActualFilter" ) >>= aFilterName; + if( !aFilterName.isEmpty() ) + { + // find the related type name + OUString aTypeName; + Reference< container::XNameAccess > xFilterFactory( + xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext), + uno::UNO_QUERY ); + + Sequence< beans::PropertyValue > aFilterData; + xFilterFactory->getByName( aFilterName ) >>= aFilterData; + for ( const beans::PropertyValue& rProp : std::as_const(aFilterData) ) + if ( rProp.Name == "Type" ) + rProp.Value >>= aTypeName; + + if ( !aTypeName.isEmpty() ) + { + // find the mediatype + Reference< container::XNameAccess > xTypeDetection( + xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext), + UNO_QUERY ); + + Sequence< beans::PropertyValue > aTypeData; + xTypeDetection->getByName( aTypeName ) >>= aTypeData; + for ( const beans::PropertyValue& rProp : std::as_const(aTypeData) ) + if ( rProp.Name == "MediaType" ) + rProp.Value >>= aDocMimetype; + } + } + } + } + } + } + catch (...) + { + } + return aDocMimetype; +} + +uno::Reference +PDFExport::GetCertificateFromSubjectName(const std::u16string_view& rSubjectName) const +{ + uno::Reference xSEInitializer + = xml::crypto::SEInitializer::create(mxContext); + uno::Reference xSecurityContext + = xSEInitializer->createSecurityContext(OUString()); + uno::Reference xSecurityEnvironment + = xSecurityContext->getSecurityEnvironment(); + for (const auto& xCertificate : xSecurityEnvironment->getPersonalCertificates()) + { + if (xCertificate->getSubjectName() == rSubjectName) + { + return xCertificate; + } + } + + return {}; +} + +bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData ) +{ + INetURLObject aURL( rFile ); + bool bRet = false; + + std::set< vcl::PDFWriter::ErrorCode > aErrors; + + if( aURL.GetProtocol() != INetProtocol::File ) + { + OUString aTmp; + + if( osl::FileBase::getFileURLFromSystemPath( rFile, aTmp ) == osl::FileBase::E_None ) + aURL = INetURLObject(aTmp); + } + + if( aURL.GetProtocol() == INetProtocol::File ) + { + Reference< XRenderable > xRenderable( mxSrcDoc, UNO_QUERY ); + + if( xRenderable.is() ) + { + rtl::Reference xDevice(new VCLXDevice); + OUString aPageRange; + Any aSelection; + vcl::PDFWriter::PDFWriterContext aContext; + OUString aOpenPassword, aPermissionPassword; + Reference< beans::XMaterialHolder > xEnc; + Sequence< beans::NamedValue > aPreparedPermissionPassword; + + + // getting the string for the creator + OUString aCreator; + Reference< XServiceInfo > xInfo( mxSrcDoc, UNO_QUERY ); + if ( xInfo.is() ) + { + if ( xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) ) + aCreator += "Impress"; + else if ( xInfo->supportsService( "com.sun.star.drawing.DrawingDocument" ) ) + aCreator += "Draw"; + else if ( xInfo->supportsService( "com.sun.star.text.TextDocument" ) ) + aCreator += "Writer"; + else if ( xInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) + aCreator += "Calc"; + else if ( xInfo->supportsService( "com.sun.star.formula.FormulaProperties" ) ) + aCreator += "Math"; + } + + Reference< document::XDocumentPropertiesSupplier > xDocumentPropsSupplier( mxSrcDoc, UNO_QUERY ); + if ( xDocumentPropsSupplier.is() ) + { + Reference< document::XDocumentProperties > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties() ); + if ( xDocumentProps.is() ) + { + aContext.DocumentInfo.Title = xDocumentProps->getTitle(); + aContext.DocumentInfo.Author = xDocumentProps->getAuthor(); + aContext.DocumentInfo.Subject = xDocumentProps->getSubject(); + aContext.DocumentInfo.Keywords = ::comphelper::string::convertCommaSeparated(xDocumentProps->getKeywords()); + } + } + // getting the string for the producer + OUString aProducerOverride = officecfg::Office::Common::Save::Document::GeneratorOverride::get(); + if( !aProducerOverride.isEmpty()) + aContext.DocumentInfo.Producer = aProducerOverride; + else + aContext.DocumentInfo.Producer = + utl::ConfigManager::getProductName() + + " " + + utl::ConfigManager::getProductVersion(); + + aContext.DocumentInfo.Creator = aCreator; + + OUString aSignCertificateSubjectName; + for ( const beans::PropertyValue& rProp : rFilterData ) + { + if ( rProp.Name == "PageRange" ) + rProp.Value >>= aPageRange; + else if ( rProp.Name == "Selection" ) + aSelection = rProp.Value; + else if ( rProp.Name == "UseLosslessCompression" ) + rProp.Value >>= mbUseLosslessCompression; + else if ( rProp.Name == "Quality" ) + rProp.Value >>= mnQuality; + else if ( rProp.Name == "ReduceImageResolution" ) + rProp.Value >>= mbReduceImageResolution; + else if ( rProp.Name == "IsSkipEmptyPages" ) + rProp.Value >>= mbSkipEmptyPages; + else if ( rProp.Name == "MaxImageResolution" ) + rProp.Value >>= mnMaxImageResolution; + else if ( rProp.Name == "UseTaggedPDF" ) + rProp.Value >>= mbUseTaggedPDF; + else if ( rProp.Name == "SelectPdfVersion" ) + rProp.Value >>= mnPDFTypeSelection; + else if ( rProp.Name == "PDFUACompliance" ) + rProp.Value >>= mbPDFUACompliance; + else if ( rProp.Name == "ExportNotes" ) + rProp.Value >>= mbExportNotes; + else if ( rProp.Name == "ExportNotesPages" ) + rProp.Value >>= mbExportNotesPages; + else if ( rProp.Name == "ExportOnlyNotesPages" ) + rProp.Value >>= mbExportOnlyNotesPages; + else if ( rProp.Name == "UseTransitionEffects" ) + rProp.Value >>= mbUseTransitionEffects; + else if ( rProp.Name == "ExportFormFields" ) + rProp.Value >>= mbExportFormFields; + else if ( rProp.Name == "FormsType" ) + rProp.Value >>= mnFormsFormat; + else if ( rProp.Name == "AllowDuplicateFieldNames" ) + rProp.Value >>= mbAllowDuplicateFieldNames; + // viewer properties + else if ( rProp.Name == "HideViewerToolbar" ) + rProp.Value >>= mbHideViewerToolbar; + else if ( rProp.Name == "HideViewerMenubar" ) + rProp.Value >>= mbHideViewerMenubar; + else if ( rProp.Name == "HideViewerWindowControls" ) + rProp.Value >>= mbHideViewerWindowControls; + else if ( rProp.Name == "ResizeWindowToInitialPage" ) + rProp.Value >>= mbFitWindow; + else if ( rProp.Name == "CenterWindow" ) + rProp.Value >>= mbCenterWindow; + else if ( rProp.Name == "OpenInFullScreenMode" ) + rProp.Value >>= mbOpenInFullScreenMode; + else if ( rProp.Name == "DisplayPDFDocumentTitle" ) + rProp.Value >>= mbDisplayPDFDocumentTitle; + else if ( rProp.Name == "InitialView" ) + rProp.Value >>= mnPDFDocumentMode; + else if ( rProp.Name == "Magnification" ) + rProp.Value >>= mnPDFDocumentAction; + else if ( rProp.Name == "Zoom" ) + rProp.Value >>= mnZoom; + else if ( rProp.Name == "InitialPage" ) + rProp.Value >>= mnInitialPage; + else if ( rProp.Name == "PageLayout" ) + rProp.Value >>= mnPDFPageLayout; + else if ( rProp.Name == "FirstPageOnLeft" ) + rProp.Value >>= aContext.FirstPageLeft; + else if ( rProp.Name == "IsAddStream" ) + rProp.Value >>= mbAddStream; + else if ( rProp.Name == "Watermark" ) + rProp.Value >>= msWatermark; + else if ( rProp.Name == "WatermarkColor" ) + { + sal_Int32 nColor{}; + if (rProp.Value >>= nColor) + { + maWatermarkColor = Color(ColorTransparency, nColor); + } + } + else if (rProp.Name == "WatermarkFontHeight") + { + sal_Int32 nFontHeight{}; + if (rProp.Value >>= nFontHeight) + { + moWatermarkFontHeight = nFontHeight; + } + } + else if (rProp.Name == "WatermarkRotateAngle") + { + sal_Int32 nRotateAngle{}; + if (rProp.Value >>= nRotateAngle) + { + moWatermarkRotateAngle = Degree10(nRotateAngle); + } + } + else if (rProp.Name == "WatermarkFontName") + { + OUString aFontName{}; + if (rProp.Value >>= aFontName) + { + maWatermarkFontName = aFontName; + } + } + else if ( rProp.Name == "TiledWatermark" ) + rProp.Value >>= msTiledWatermark; + // now all the security related properties... + else if ( rProp.Name == "EncryptFile" ) + rProp.Value >>= mbEncrypt; + else if ( rProp.Name == "DocumentOpenPassword" ) + rProp.Value >>= aOpenPassword; + else if ( rProp.Name == "RestrictPermissions" ) + rProp.Value >>= mbRestrictPermissions; + else if ( rProp.Name == "PermissionPassword" ) + rProp.Value >>= aPermissionPassword; + else if ( rProp.Name == "PreparedPasswords" ) + rProp.Value >>= xEnc; + else if ( rProp.Name == "PreparedPermissionPassword" ) + rProp.Value >>= aPreparedPermissionPassword; + else if ( rProp.Name == "Printing" ) + rProp.Value >>= mnPrintAllowed; + else if ( rProp.Name == "Changes" ) + rProp.Value >>= mnChangesAllowed; + else if ( rProp.Name == "EnableCopyingOfContent" ) + rProp.Value >>= mbCanCopyOrExtract; + else if ( rProp.Name == "EnableTextAccessForAccessibilityTools" ) + rProp.Value >>= mbCanExtractForAccessibility; + // i56629 links extra (relative links and other related stuff) + else if ( rProp.Name == "ExportLinksRelativeFsys" ) + rProp.Value >>= mbExportRelativeFsysLinks; + else if ( rProp.Name == "PDFViewSelection" ) + rProp.Value >>= mnDefaultLinkAction; + else if ( rProp.Name == "ConvertOOoTargetToPDFTarget" ) + rProp.Value >>= mbConvertOOoTargetToPDFTarget; + else if ( rProp.Name == "ExportBookmarksToPDFDestination" ) + rProp.Value >>= mbExportBmkToDest; + else if ( rProp.Name == "ExportBookmarks" ) + rProp.Value >>= mbExportBookmarks; + else if ( rProp.Name == "ExportHiddenSlides" ) + rProp.Value >>= mbExportHiddenSlides; + else if ( rProp.Name == "SinglePageSheets" ) + rProp.Value >>= mbSinglePageSheets; + else if ( rProp.Name == "OpenBookmarkLevels" ) + rProp.Value >>= mnOpenBookmarkLevels; + else if ( rProp.Name == "SignPDF" ) + rProp.Value >>= mbSignPDF; + else if ( rProp.Name == "SignatureLocation" ) + rProp.Value >>= msSignLocation; + else if ( rProp.Name == "SignatureReason" ) + rProp.Value >>= msSignReason; + else if ( rProp.Name == "SignatureContactInfo" ) + rProp.Value >>= msSignContact; + else if ( rProp.Name == "SignaturePassword" ) + rProp.Value >>= msSignPassword; + else if ( rProp.Name == "SignatureCertificate" ) + rProp.Value >>= maSignCertificate; + else if (rProp.Name == "SignCertificateSubjectName") + rProp.Value >>= aSignCertificateSubjectName; + else if ( rProp.Name == "SignatureTSA" ) + rProp.Value >>= msSignTSA; + else if ( rProp.Name == "ExportPlaceholders" ) + rProp.Value >>= mbExportPlaceholders; + else if ( rProp.Name == "UseReferenceXObject" ) + rProp.Value >>= mbUseReferenceXObject; + // Redaction & bitmap related stuff + else if ( rProp.Name == "IsRedactMode" ) + rProp.Value >>= mbIsRedactMode; + } + + if (!maSignCertificate.is() && !aSignCertificateSubjectName.isEmpty()) + { + maSignCertificate = GetCertificateFromSubjectName(aSignCertificateSubjectName); + } + + aContext.URL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + + // set the correct version, depending on user request + switch( mnPDFTypeSelection ) + { + default: + case 0: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6; + break; + case 1: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_1; + mbUseTaggedPDF = true; // force the tagged PDF as well + mbRemoveTransparencies = true; // does not allow transparencies + mbEncrypt = false; // no encryption + xEnc.clear(); + break; + case 2: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_2; + mbUseTaggedPDF = true; // force the tagged PDF as well + mbRemoveTransparencies = false; // does allow transparencies + mbEncrypt = false; // no encryption + xEnc.clear(); + break; + case 3: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_3; + mbUseTaggedPDF = true; // force the tagged PDF as well + mbRemoveTransparencies = false; // does allow transparencies + mbEncrypt = false; // no encryption + xEnc.clear(); + break; + case 15: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_5; + break; + case 16: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6; + break; + } + + // PDF/UA support + aContext.UniversalAccessibilityCompliance = mbPDFUACompliance; + if (mbPDFUACompliance) + { + mbUseTaggedPDF = true; + } + + // copy in context the values default in the constructor or set by the FilterData sequence of properties + aContext.Tagged = mbUseTaggedPDF; + + // values used in viewer + aContext.HideViewerToolbar = mbHideViewerToolbar; + aContext.HideViewerMenubar = mbHideViewerMenubar; + aContext.HideViewerWindowControls = mbHideViewerWindowControls; + aContext.FitWindow = mbFitWindow; + aContext.CenterWindow = mbCenterWindow; + aContext.OpenInFullScreenMode = mbOpenInFullScreenMode; + aContext.DisplayPDFDocumentTitle = mbDisplayPDFDocumentTitle; + aContext.InitialPage = mnInitialPage-1; + aContext.OpenBookmarkLevels = mnOpenBookmarkLevels; + + switch( mnPDFDocumentMode ) + { + default: + case 0: + aContext.PDFDocumentMode = vcl::PDFWriter::ModeDefault; + break; + case 1: + aContext.PDFDocumentMode = vcl::PDFWriter::UseOutlines; + break; + case 2: + aContext.PDFDocumentMode = vcl::PDFWriter::UseThumbs; + break; + } + switch( mnPDFDocumentAction ) + { + default: + case 0: + aContext.PDFDocumentAction = vcl::PDFWriter::ActionDefault; + break; + case 1: + aContext.PDFDocumentAction = vcl::PDFWriter::FitInWindow; + break; + case 2: + aContext.PDFDocumentAction = vcl::PDFWriter::FitWidth; + break; + case 3: + aContext.PDFDocumentAction = vcl::PDFWriter::FitVisible; + break; + case 4: + aContext.PDFDocumentAction = vcl::PDFWriter::ActionZoom; + aContext.Zoom = mnZoom; + break; + } + + switch( mnPDFPageLayout ) + { + default: + case 0: + aContext.PageLayout = vcl::PDFWriter::DefaultLayout; + break; + case 1: + aContext.PageLayout = vcl::PDFWriter::SinglePage; + break; + case 2: + aContext.PageLayout = vcl::PDFWriter::Continuous; + break; + case 3: + aContext.PageLayout = vcl::PDFWriter::ContinuousFacing; + break; + } + + aContext.FirstPageLeft = false; + + // check if PDF/A, which does not allow encryption + if( aContext.Version != vcl::PDFWriter::PDFVersion::PDF_A_1 ) + { + // set check for permission change password + // if not enabled and no permission password, force permissions to default as if PDF where without encryption + if( mbRestrictPermissions && (xEnc.is() || !aPermissionPassword.isEmpty()) ) + { + mbEncrypt = true; // permission set as desired, done after + } + else + { + // force permission to default + mnPrintAllowed = 2 ; + mnChangesAllowed = 4 ; + mbCanCopyOrExtract = true; + mbCanExtractForAccessibility = true ; + } + + switch( mnPrintAllowed ) + { + case 0: // initialized when aContext is build, means no printing + break; + default: + case 2: + aContext.Encryption.CanPrintFull = true; + [[fallthrough]]; + case 1: + aContext.Encryption.CanPrintTheDocument = true; + break; + } + + switch( mnChangesAllowed ) + { + case 0: // already in struct PDFSecPermissions CTOR + break; + case 1: + aContext.Encryption.CanAssemble = true; + break; + case 2: + aContext.Encryption.CanFillInteractive = true; + break; + case 3: + aContext.Encryption.CanAddOrModify = true; + break; + default: + case 4: + aContext.Encryption.CanModifyTheContent = + aContext.Encryption.CanCopyOrExtract = + aContext.Encryption.CanAddOrModify = + aContext.Encryption.CanFillInteractive = true; + break; + } + + aContext.Encryption.CanCopyOrExtract = mbCanCopyOrExtract; + aContext.Encryption.CanExtractForAccessibility = mbCanExtractForAccessibility; + if( mbEncrypt && ! xEnc.is() ) + xEnc = vcl::PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword ); + if( mbEncrypt && !aPermissionPassword.isEmpty() && ! aPreparedPermissionPassword.hasElements() ) + aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword ); + } + // after this point we don't need the legacy clear passwords anymore + // however they are still inside the passed filter data sequence + // which is sadly out of our control + aPermissionPassword.clear(); + aOpenPassword.clear(); + + /* + * FIXME: the entries are only implicitly defined by the resource file. Should there + * ever be an additional form submit format this could get invalid. + */ + switch( mnFormsFormat ) + { + case 1: + aContext.SubmitFormat = vcl::PDFWriter::PDF; + break; + case 2: + aContext.SubmitFormat = vcl::PDFWriter::HTML; + break; + case 3: + aContext.SubmitFormat = vcl::PDFWriter::XML; + break; + default: + case 0: + aContext.SubmitFormat = vcl::PDFWriter::FDF; + break; + } + aContext.AllowDuplicateFieldNames = mbAllowDuplicateFieldNames; + + // get model + Reference< frame::XModel > xModel( mxSrcDoc, UNO_QUERY ); + { + // #i56629: Relative link stuff + // set the base URL of the file: then base URL + aContext.BaseURL = xModel->getURL(); + // relative link option is private to PDF Export filter and limited to local filesystem only + aContext.RelFsys = mbExportRelativeFsysLinks; + // determine the default acton for PDF links + switch( mnDefaultLinkAction ) + { + default: + // default: URI, without fragment conversion (the bookmark in PDF may not work) + case 0: + aContext.DefaultLinkAction = vcl::PDFWriter::URIAction; + break; + case 1: + // view PDF through the reader application + aContext.ForcePDFAction = true; + aContext.DefaultLinkAction = vcl::PDFWriter::LaunchAction; + break; + case 2: + // view PDF through an Internet browser + aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination; + break; + } + aContext.ConvertOOoTargetToPDFTarget = mbConvertOOoTargetToPDFTarget; + + // check for Link Launch action, not allowed on PDF/A-1 + // this code chunk checks when the filter is called from scripting + if( aContext.Version == vcl::PDFWriter::PDFVersion::PDF_A_1 && + aContext.DefaultLinkAction == vcl::PDFWriter::LaunchAction ) + { + // force the similar allowed URI action + aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination; + // and remove the remote goto action forced on PDF file + aContext.ForcePDFAction = false; + } + } + + aContext.SignPDF = mbSignPDF; + aContext.SignLocation = msSignLocation; + aContext.SignContact = msSignContact; + aContext.SignReason = msSignReason; + aContext.SignPassword = msSignPassword; + aContext.SignCertificate = maSignCertificate; + aContext.SignTSA = msSignTSA; + aContext.UseReferenceXObject = mbUseReferenceXObject; + + // all context data set, time to create the printing device + vcl::PDFWriter aPDFWriter( aContext, xEnc ); + OutputDevice* pOut = aPDFWriter.GetReferenceDevice(); + + DBG_ASSERT( pOut, "PDFExport::Export: no reference device" ); + xDevice->SetOutputDevice(pOut); + + if( mbAddStream ) + { + // export stream + // get mimetype + OUString aSrcMimetype = getMimetypeForDocument( mxContext, mxSrcDoc ); + aPDFWriter.AddStream( aSrcMimetype, + new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword ) + ); + } + + if ( pOut ) + { + DBG_ASSERT( pOut->GetExtOutDevData() == nullptr, "PDFExport: ExtOutDevData already set!!!" ); + vcl::PDFExtOutDevData aPDFExtOutDevData( *pOut ); + pOut->SetExtOutDevData( &aPDFExtOutDevData ); + aPDFExtOutDevData.SetIsExportNotes( mbExportNotes ); + aPDFExtOutDevData.SetIsExportTaggedPDF( mbUseTaggedPDF ); + aPDFExtOutDevData.SetIsExportTransitionEffects( mbUseTransitionEffects ); + aPDFExtOutDevData.SetIsExportFormFields( mbExportFormFields ); + aPDFExtOutDevData.SetIsExportBookmarks( mbExportBookmarks ); + aPDFExtOutDevData.SetIsExportHiddenSlides( mbExportHiddenSlides ); + aPDFExtOutDevData.SetIsSinglePageSheets( mbSinglePageSheets ); + aPDFExtOutDevData.SetIsLosslessCompression( mbUseLosslessCompression ); + aPDFExtOutDevData.SetCompressionQuality( mnQuality ); + aPDFExtOutDevData.SetIsReduceImageResolution( mbReduceImageResolution ); + aPDFExtOutDevData.SetIsExportNamedDestinations( mbExportBmkToDest ); + + Sequence< PropertyValue > aRenderOptions{ + comphelper::makePropertyValue("RenderDevice", uno::Reference(xDevice)), + comphelper::makePropertyValue("ExportNotesPages", false), + comphelper::makePropertyValue("IsFirstPage", true), + comphelper::makePropertyValue("IsLastPage", false), + comphelper::makePropertyValue("IsSkipEmptyPages", mbSkipEmptyPages), + comphelper::makePropertyValue("PageRange", aPageRange), + comphelper::makePropertyValue("ExportPlaceholders", mbExportPlaceholders), + comphelper::makePropertyValue("SinglePageSheets", mbSinglePageSheets) + }; + Any& rExportNotesValue = aRenderOptions.getArray()[ 1 ].Value; + + if( !aPageRange.isEmpty() || !aSelection.hasValue() ) + { + aSelection = Any(); + aSelection <<= mxSrcDoc; + } + bool bExportNotesPages = false; + bool bReChangeToNormalView = false; + static const OUStringLiteral sShowOnlineLayout( u"ShowOnlineLayout" ); + bool bReHideWhitespace = false; + static const OUStringLiteral sHideWhitespace(u"HideWhitespace"); + uno::Reference< beans::XPropertySet > xViewProperties; + + if ( aCreator == "Writer" ) + { + // #i92835: if Writer is in web layout mode this has to be switched to normal view and back to web view in the end + try + { + Reference< view::XViewSettingsSupplier > xVSettingsSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xViewProperties = xVSettingsSupplier->getViewSettings(); + xViewProperties->getPropertyValue( sShowOnlineLayout ) >>= bReChangeToNormalView; + if( bReChangeToNormalView ) + { + xViewProperties->setPropertyValue( sShowOnlineLayout, uno::Any( false ) ); + } + + // Also, disable hide-whitespace during export. + xViewProperties->getPropertyValue(sHideWhitespace) >>= bReHideWhitespace; + if (bReHideWhitespace) + { + xViewProperties->setPropertyValue(sHideWhitespace, uno::Any(false)); + } + } + catch( const uno::Exception& ) + { + } + + } + + const sal_Int32 nPageCount = xRenderable->getRendererCount( aSelection, aRenderOptions ); + + if ( mbExportNotesPages && aCreator == "Impress" ) + { + uno::Reference< drawing::XShapes > xShapes; // do not allow to export notes when exporting a selection + if ( ! ( aSelection >>= xShapes ) ) + bExportNotesPages = true; + } + const bool bExportPages = !bExportNotesPages || !mbExportOnlyNotesPages; + + if( aPageRange.isEmpty() || mbSinglePageSheets) + { + aPageRange = OUString::number( 1 ) + "-" + OUString::number(nPageCount ); + } + StringRangeEnumerator aRangeEnum( aPageRange, 0, nPageCount-1 ); + + if ( mxStatusIndicator.is() ) + { + std::locale loc(Translate::Create("flt")); + sal_Int32 nTotalPageCount = aRangeEnum.size(); + if ( bExportPages && bExportNotesPages ) + nTotalPageCount *= 2; + mxStatusIndicator->start(Translate::get(PDF_PROGRESS_BAR, loc), nTotalPageCount); + } + + bRet = nPageCount > 0; + + if ( bRet && bExportPages ) + bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount ); + + if ( bRet && bExportNotesPages ) + { + rExportNotesValue <<= true; + bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount ); + } + if ( mxStatusIndicator.is() ) + mxStatusIndicator->end(); + + // if during the export the doc locale was set copy it to PDF writer + const css::lang::Locale& rLoc( aPDFExtOutDevData.GetDocumentLocale() ); + if( !rLoc.Language.isEmpty() ) + aPDFWriter.SetDocumentLocale( rLoc ); + + if( bRet ) + { + aPDFExtOutDevData.PlayGlobalActions( aPDFWriter ); + bRet = aPDFWriter.Emit(); + aErrors = aPDFWriter.GetErrors(); + } + pOut->SetExtOutDevData( nullptr ); + if( bReChangeToNormalView ) + { + try + { + xViewProperties->setPropertyValue( sShowOnlineLayout, uno::Any( true ) ); + } + catch( const uno::Exception& ) + { + } + } + if( bReHideWhitespace ) + { + try + { + xViewProperties->setPropertyValue( sHideWhitespace, uno::Any( true ) ); + } + catch( const uno::Exception& ) + { + } + } + } + } + } + + // show eventual errors during export + showErrors( aErrors ); + + return bRet; +} + + +namespace +{ + +typedef cppu::WeakComponentImplHelper< task::XInteractionRequest > PDFErrorRequestBase; + +class PDFErrorRequest : private cppu::BaseMutex, + public PDFErrorRequestBase +{ + task::PDFExportException maExc; +public: + explicit PDFErrorRequest( task::PDFExportException aExc ); + + // XInteractionRequest + virtual uno::Any SAL_CALL getRequest() override; + virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() override; +}; + + +PDFErrorRequest::PDFErrorRequest( task::PDFExportException aExc ) : + PDFErrorRequestBase( m_aMutex ), + maExc(std::move( aExc )) +{ +} + + +uno::Any SAL_CALL PDFErrorRequest::getRequest() +{ + osl::MutexGuard const guard( m_aMutex ); + + uno::Any aRet; + aRet <<= maExc; + return aRet; +} + + +uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL PDFErrorRequest::getContinuations() +{ + return uno::Sequence< uno::Reference< task::XInteractionContinuation > >(); +} + +} // end anonymous namespace + + +void PDFExport::showErrors( const std::set< vcl::PDFWriter::ErrorCode >& rErrors ) +{ + if( ! rErrors.empty() && mxIH.is() ) + { + task::PDFExportException aExc; + aExc.ErrorCodes = comphelper::containerToSequence( rErrors ); + Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( std::move(aExc) ) ); + mxIH->handle( xReq ); + } +} + + +void PDFExport::ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& rPDFExtOutDevData, const GDIMetaFile& rMtf ) +{ + //Rectangle(Point, Size) creates a rectangle off by 1, use Rectangle(long, long, long, long) instead + basegfx::B2DPolygon aSize(tools::Polygon(tools::Rectangle(0, 0, rMtf.GetPrefSize().Width(), rMtf.GetPrefSize().Height())).getB2DPolygon()); + basegfx::B2DPolygon aSizePDF(OutputDevice::LogicToLogic(aSize, rMtf.GetPrefMapMode(), MapMode(MapUnit::MapPoint))); + basegfx::B2DRange aRangePDF(aSizePDF.getB2DRange()); + tools::Rectangle aPageRect( Point(), rMtf.GetPrefSize() ); + + rWriter.NewPage( aRangePDF.getWidth(), aRangePDF.getHeight() ); + rWriter.SetMapMode( rMtf.GetPrefMapMode() ); + + vcl::PDFWriter::PlayMetafileContext aCtx; + GDIMetaFile aMtf; + if( mbRemoveTransparencies ) + { + aCtx.m_bTransparenciesWereRemoved = rWriter.GetReferenceDevice()-> + RemoveTransparenciesFromMetaFile( rMtf, aMtf, mnMaxImageResolution, mnMaxImageResolution, + false, true, mbReduceImageResolution ); + // tdf#134736 if the metafile was replaced then rPDFExtOutDevData's PageSyncData mActions + // all still point to MetaAction indexes in the original metafile that are now invalid. + // Throw them all away in the absence of a way to reposition them to new positions of + // their replacements. + if (aCtx.m_bTransparenciesWereRemoved) + rPDFExtOutDevData.ResetSyncData(); + } + else + { + aMtf = rMtf; + } + aCtx.m_nMaxImageResolution = mbReduceImageResolution ? mnMaxImageResolution : 0; + aCtx.m_bOnlyLosslessCompression = mbUseLosslessCompression; + aCtx.m_nJPEGQuality = mnQuality; + + + rWriter.SetClipRegion( basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromRect( vcl::unotools::b2DRectangleFromRectangle(aPageRect) ) ) ); + + rWriter.PlayMetafile( aMtf, aCtx, &rPDFExtOutDevData ); + + rPDFExtOutDevData.ResetSyncData(); + + if (!msWatermark.isEmpty()) + { + ImplWriteWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) ); + } + else if (!msTiledWatermark.isEmpty()) + { + ImplWriteTiledWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) ); + } +} + + +void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ) +{ + vcl::Font aFont( maWatermarkFontName, Size( 0, moWatermarkFontHeight ? *moWatermarkFontHeight : 3*rPageSize.Height()/4 ) ); + aFont.SetItalic( ITALIC_NONE ); + aFont.SetWidthType( WIDTH_NORMAL ); + aFont.SetWeight( WEIGHT_NORMAL ); + aFont.SetAlignment( ALIGN_BOTTOM ); + tools::Long nTextWidth = rPageSize.Width(); + if( rPageSize.Width() < rPageSize.Height() ) + { + nTextWidth = rPageSize.Height(); + aFont.SetOrientation( 2700_deg10 ); + } + + if (moWatermarkRotateAngle) + { + aFont.SetOrientation(*moWatermarkRotateAngle); + if (rPageSize.Width() < rPageSize.Height()) + { + // Set text width based on the shorter side, so rotation can't push text outside the + // page boundaries. + nTextWidth = rPageSize.Width(); + } + } + + // adjust font height for text to fit + OutputDevice* pDev = rWriter.GetReferenceDevice(); + pDev->Push(); + pDev->SetFont( aFont ); + pDev->SetMapMode( MapMode( MapUnit::MapPoint ) ); + int w = 0; + if (moWatermarkFontHeight) + { + w = pDev->GetTextWidth(msWatermark); + } + else + { + while( ( w = pDev->GetTextWidth( msWatermark ) ) > nTextWidth ) + { + if (w == 0) + break; + tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w; + if( nNewHeight == aFont.GetFontHeight() ) + { + nNewHeight--; + if( nNewHeight <= 0 ) + break; + } + aFont.SetFontHeight( nNewHeight ); + pDev->SetFont( aFont ); + } + } + tools::Long nTextHeight = pDev->GetTextHeight(); + // leave some maneuvering room for rounding issues, also + // some fonts go a little outside ascent/descent + nTextHeight += nTextHeight/20; + pDev->Pop(); + + rWriter.Push(); + rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); + rWriter.SetFont( aFont ); + rWriter.SetTextColor(maWatermarkColor); + Point aTextPoint; + tools::Rectangle aTextRect; + if( rPageSize.Width() > rPageSize.Height() ) + { + aTextPoint = Point( (rPageSize.Width()-w)/2, + rPageSize.Height()-(rPageSize.Height()-nTextHeight)/2 ); + aTextRect = tools::Rectangle( Point( (rPageSize.Width()-w)/2, + (rPageSize.Height()-nTextHeight)/2 ), + Size( w, nTextHeight ) ); + } + else + { + aTextPoint = Point( (rPageSize.Width()-nTextHeight)/2, + (rPageSize.Height()-w)/2 ); + aTextRect = tools::Rectangle( aTextPoint, Size( nTextHeight, w ) ); + } + + if (moWatermarkRotateAngle) + { + // First set the text's starting point to the center of the page. + tools::Rectangle aPageRectangle(Point(0, 0), rPageSize); + aTextPoint = aPageRectangle.Center(); + // Then adjust it so that the text remains centered, based on the rotation angle. + basegfx::B2DPolygon aTextPolygon + = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(0, -nTextHeight, w, 0)); + basegfx::B2DHomMatrix aMatrix; + aMatrix.rotate(-1 * toRadians(*moWatermarkRotateAngle)); + aTextPolygon.transform(aMatrix); + basegfx::B2DPoint aPolygonCenter = aTextPolygon.getB2DRange().getCenter(); + aTextPoint.AdjustX(-aPolygonCenter.getX()); + aTextPoint.AdjustY(-aPolygonCenter.getY()); + + aTextRect = aPageRectangle; + } + + rWriter.SetClipRegion(); + rWriter.BeginTransparencyGroup(); + rWriter.DrawText( aTextPoint, msWatermark ); + rWriter.EndTransparencyGroup( aTextRect, 50 ); + rWriter.Pop(); +} + +void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ) +{ + OUString watermark = msTiledWatermark; + // Maximum number of characters in one line. + // it is set to 21 to make it look like tiled watermarks as online in secure view + const int lineLength = 21; + vcl::Font aFont( "Liberation Sans", Size( 0, 40 ) ); + aFont.SetItalic( ITALIC_NONE ); + aFont.SetWidthType( WIDTH_NORMAL ); + aFont.SetWeight( WEIGHT_NORMAL ); + aFont.SetAlignment( ALIGN_BOTTOM ); + aFont.SetFontHeight(40); + aFont.SetOrientation(450_deg10); + + OutputDevice* pDev = rWriter.GetReferenceDevice(); + pDev->SetFont(aFont); + pDev->Push(); + pDev->SetFont(aFont); + pDev->SetMapMode( MapMode( MapUnit::MapPoint ) ); + int w = 0; + int watermarkcount = ((rPageSize.Width()) / 200)+1; + tools::Long nTextWidth = rPageSize.Width() / (watermarkcount*1.5); + OUString oneLineText = watermark; + + if(watermark.getLength() > lineLength) + oneLineText = watermark.copy(0, lineLength); + + while((w = pDev->GetTextWidth(oneLineText)) > nTextWidth) + { + if(w==0) + break; + + tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w; + aFont.SetFontHeight(nNewHeight); + pDev->SetFont( aFont ); + } + // maximum number of watermark count for the width + if(watermarkcount > 8) + watermarkcount = 8; + + pDev->Pop(); + + rWriter.Push(); + rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); + rWriter.SetFont(aFont); + rWriter.SetTextColor( Color(19,20,22) ); + // center watermarks horizontally + Point aTextPoint( (rPageSize.Width()/2) - (((nTextWidth*watermarkcount)+(watermarkcount-1)*nTextWidth)/2), + pDev->GetTextHeight()); + + for( int i = 0; i < watermarkcount; i ++) + { + while(aTextPoint.getY()+pDev->GetTextHeight()*3 <= rPageSize.Height()) + { + tools::Rectangle aTextRect(aTextPoint, Size(nTextWidth*2,pDev->GetTextHeight()*4)); + + pDev->Push(); + rWriter.SetClipRegion(); + rWriter.BeginTransparencyGroup(); + rWriter.SetTextColor( Color(19,20,22) ); + rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom); + rWriter.EndTransparencyGroup( aTextRect, 50 ); + pDev->Pop(); + + pDev->Push(); + rWriter.SetClipRegion(); + rWriter.BeginTransparencyGroup(); + rWriter.SetTextColor( Color(236,235,233) ); + rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom); + rWriter.EndTransparencyGroup( aTextRect, 50 ); + pDev->Pop(); + + aTextPoint.Move(0, pDev->GetTextHeight()*3); + } + aTextPoint=Point( aTextPoint.getX(), pDev->GetTextHeight() ); + aTextPoint.Move( nTextWidth*1.5, 0 ); + } + + rWriter.Pop(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfexport.hxx b/filter/source/pdf/pdfexport.hxx new file mode 100644 index 000000000..dfd371c31 --- /dev/null +++ b/filter/source/pdf/pdfexport.hxx @@ -0,0 +1,145 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class GDIMetaFile; +class Size; + +namespace vcl { class PDFWriter; } + +class PDFExport +{ +private: + + css::uno::Reference< css::lang::XComponent > mxSrcDoc; + css::uno::Reference< css::uno::XComponentContext > mxContext; + css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator; + css::uno::Reference< css::task::XInteractionHandler > mxIH; + + bool mbUseTaggedPDF; + sal_Int32 mnPDFTypeSelection; + bool mbPDFUACompliance; + bool mbExportNotes; + bool mbExportPlaceholders; + bool mbUseReferenceXObject; + bool mbExportNotesPages; + bool mbExportOnlyNotesPages; + bool mbUseTransitionEffects; + bool mbExportBookmarks; + bool mbExportHiddenSlides; + bool mbSinglePageSheets; + sal_Int32 mnOpenBookmarkLevels; + + bool mbUseLosslessCompression; + bool mbReduceImageResolution; + bool mbSkipEmptyPages; + bool mbAddStream; + sal_Int32 mnMaxImageResolution; + sal_Int32 mnQuality; + sal_Int32 mnFormsFormat; + bool mbExportFormFields; + bool mbAllowDuplicateFieldNames; + sal_Int32 mnProgressValue; + bool mbRemoveTransparencies; + + bool mbIsRedactMode; + + OUString msWatermark; + Color maWatermarkColor; + std::optional moWatermarkFontHeight; + OUString maWatermarkFontName; + std::optional moWatermarkRotateAngle; + OUString msTiledWatermark; + + // these variable are here only to have a location in filter/pdf to set the default + // to be used by the macro (when the FilterData are set by the macro itself) + bool mbHideViewerToolbar; + bool mbHideViewerMenubar; + bool mbHideViewerWindowControls; + bool mbFitWindow; + bool mbCenterWindow; + bool mbOpenInFullScreenMode; + bool mbDisplayPDFDocumentTitle; + sal_Int32 mnPDFDocumentMode; + sal_Int32 mnPDFDocumentAction; + sal_Int32 mnZoom; + sal_Int32 mnInitialPage; + sal_Int32 mnPDFPageLayout; + + bool mbEncrypt; + bool mbRestrictPermissions; + sal_Int32 mnPrintAllowed; + sal_Int32 mnChangesAllowed; + bool mbCanCopyOrExtract; + bool mbCanExtractForAccessibility; + + // #i56629 + bool mbExportRelativeFsysLinks; + sal_Int32 mnDefaultLinkAction; + bool mbConvertOOoTargetToPDFTarget; + bool mbExportBmkToDest; + void ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& rPDFExtOutDevData, + const GDIMetaFile& rMtf ); + + bool mbSignPDF; + OUString msSignLocation; + OUString msSignContact; + OUString msSignReason; + OUString msSignPassword; + css::uno::Reference< css::security::XCertificate > maSignCertificate; + OUString msSignTSA; + + void ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ); + void ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ); + css::uno::Reference GetCertificateFromSubjectName(const std::u16string_view& rSubjectName) const; + + +public: + + PDFExport( const css::uno::Reference< css::lang::XComponent >& rxSrcDoc, + const css::uno::Reference< css::task::XStatusIndicator >& xStatusIndicator, + const css::uno::Reference< css::task::XInteractionHandler >& xIH, + const css::uno::Reference< css::uno::XComponentContext >& xFact ); + ~PDFExport(); + + bool ExportSelection( vcl::PDFWriter& rPDFWriter, + css::uno::Reference< css::view::XRenderable > const & rRenderable, + const css::uno::Any& rSelection, + const StringRangeEnumerator& rRangeEnum, + css::uno::Sequence< css::beans::PropertyValue >& rRenderOptions, + sal_Int32 nPageCount ); + + bool Export( const OUString& rFile, const css::uno::Sequence< css::beans::PropertyValue >& rFilterData ); + + void showErrors( const std::set& ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdffilter.component b/filter/source/pdf/pdffilter.component new file mode 100644 index 000000000..5f3dc7879 --- /dev/null +++ b/filter/source/pdf/pdffilter.component @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + diff --git a/filter/source/pdf/pdffilter.cxx b/filter/source/pdf/pdffilter.cxx new file mode 100644 index 000000000..746a1dd9b --- /dev/null +++ b/filter/source/pdf/pdffilter.cxx @@ -0,0 +1,295 @@ +/* -*- 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 "pdffilter.hxx" +#include "pdfexport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +using namespace ::com::sun::star::io; + +PDFFilter::PDFFilter( const Reference< XComponentContext > &rxContext ) : + mxContext( rxContext ) +{ +} + + +PDFFilter::~PDFFilter() +{ +} + + +bool PDFFilter::implExport( const Sequence< PropertyValue >& rDescriptor ) +{ + Reference< XOutputStream > xOStm; + Sequence< PropertyValue > aFilterData; + OUString aFilterOptions; + sal_Int32 nLength = rDescriptor.getLength(); + const PropertyValue* pValue = rDescriptor.getConstArray(); + bool bIsRedactMode = false; + bool bRet = false; + Reference< task::XStatusIndicator > xStatusIndicator; + Reference< task::XInteractionHandler > xIH; + + for (sal_Int32 i = 0; i < nLength; ++i) + { + if ( pValue[ i ].Name == "OutputStream" ) + pValue[ i ].Value >>= xOStm; + else if ( pValue[ i ].Name == "FilterData" ) + pValue[ i ].Value >>= aFilterData; + else if ( pValue[ i ].Name == "FilterOptions" ) + pValue[ i ].Value >>= aFilterOptions; + else if ( pValue[ i ].Name == "StatusIndicator" ) + pValue[ i ].Value >>= xStatusIndicator; + else if ( pValue[i].Name == "InteractionHandler" ) + pValue[i].Value >>= xIH; + } + + for (sal_Int32 i = 0 ; i < nLength; ++i) + { + if ( pValue[i].Name == "IsRedactMode") + pValue[i].Value >>= bIsRedactMode; + } + + if (!aFilterData.hasElements() && aFilterOptions.startsWith("{")) + { + try + { + // Allow setting filter data keys from the cmdline. + std::vector aData + = comphelper::JsonToPropertyValues(aFilterOptions.toUtf8()); + aFilterData = comphelper::containerToSequence(aData); + } + catch (const boost::property_tree::json_parser::json_parser_error& e) + { + // This wasn't a valid json; maybe came from import filter (tdf#150846) + SAL_WARN("filter.pdf", "error parsing FilterOptions: " << e.message()); + } + } + + /* we don't get FilterData if we are exporting directly + to pdf, but we have to use the last user settings (especially for the CompressMode) */ + if ( !aFilterData.hasElements() ) + { + FilterConfigItem aCfgItem( u"Office.Common/Filter/PDF/Export/" ); + aCfgItem.ReadBool( "UseLosslessCompression", false ); + aCfgItem.ReadInt32( "Quality", 90 ); + aCfgItem.ReadBool( "ReduceImageResolution", false ); + aCfgItem.ReadInt32( "MaxImageResolution", 300 ); + aCfgItem.ReadBool( "UseTaggedPDF", false ); + aCfgItem.ReadInt32( "SelectPdfVersion", 0 ); + aCfgItem.ReadBool("PDFUACompliance", false); + aCfgItem.ReadBool( "ExportNotes", false ); + aCfgItem.ReadBool( "ExportPlaceholders", false ); + aCfgItem.ReadBool( "ExportNotesPages", false ); + aCfgItem.ReadBool( "ExportOnlyNotesPages", false ); + aCfgItem.ReadBool( "UseTransitionEffects", true ); + aCfgItem.ReadBool( "IsSkipEmptyPages", false ); + aCfgItem.ReadBool( "ExportFormFields", true ); + aCfgItem.ReadInt32( "FormsType", 0 ); + aCfgItem.ReadBool( "HideViewerToolbar", false ); + aCfgItem.ReadBool( "HideViewerMenubar", false ); + aCfgItem.ReadBool( "HideViewerWindowControls", false ); + aCfgItem.ReadBool( "ResizeWindowToInitialPage", false ); + aCfgItem.ReadBool( "CenterWindow", false ); + aCfgItem.ReadBool( "OpenInFullScreenMode", false ); + aCfgItem.ReadBool( "DisplayPDFDocumentTitle", true ); + aCfgItem.ReadInt32( "InitialView", 0 ); + aCfgItem.ReadInt32( "Magnification", 0 ); + aCfgItem.ReadInt32( "Zoom", 100 ); + aCfgItem.ReadInt32( "PageLayout", 0 ); + aCfgItem.ReadBool( "FirstPageOnLeft", false ); + aCfgItem.ReadInt32( "InitialPage", 1 ); + aCfgItem.ReadBool( "IsAddStream", false ); + + // the encryption is not available when exporting directly, since the encryption is off by default and the selection + // (encrypt or not) is not persistent; it's available through macro though, + // provided the correct property values are set, see help + + // now, the relative link stuff + aCfgItem.ReadBool( "ExportLinksRelativeFsys", false ); + aCfgItem.ReadInt32("PDFViewSelection", 0 ); + aCfgItem.ReadBool( "ConvertOOoTargetToPDFTarget", false ); + aCfgItem.ReadBool( "ExportBookmarksToPDFDestination", false ); + + aCfgItem.ReadBool( "ExportBookmarks", true ); + aCfgItem.ReadBool( "ExportHiddenSlides", false ); + aCfgItem.ReadBool( "SinglePageSheets", false ); + aCfgItem.ReadInt32( "OpenBookmarkLevels", -1 ); + + aCfgItem.ReadBool( "IsRedactMode", false); + + aFilterData = aCfgItem.GetFilterData(); + } + + + if (bIsRedactMode) + { + bool bFound = false; + + for (PropertyValue& rProp : asNonConstRange(aFilterData)) + { + if (rProp.Name == "IsRedactMode") + { + rProp.Value <<= bIsRedactMode; + bFound = true; + break; + } + } + + if (!bFound) + { + sal_Int32 nNewSize = aFilterData.getLength() + 1; + aFilterData.realloc( nNewSize ); + auto pFilterData = aFilterData.getArray(); + pFilterData[nNewSize - 1].Name = "IsRedactMode"; + pFilterData[nNewSize - 1].Value <<= bIsRedactMode; + } + } + + if( mxSrcDoc.is() && xOStm.is() ) + { + PDFExport aExport( mxSrcDoc, xStatusIndicator, xIH, mxContext ); + ::utl::TempFile aTempFile; + + aTempFile.EnableKillingFile(); + bRet = aExport.Export( aTempFile.GetURL(), aFilterData ); + + if( bRet ) + { + std::unique_ptr pIStm(::utl::UcbStreamHelper::CreateStream( aTempFile.GetURL(), StreamMode::READ )); + + if( pIStm ) + { + SvOutputStream aOStm( xOStm ); + + aOStm.WriteStream( *pIStm ); + bRet = ( aOStm.Tell() && ( aOStm.GetError() == ERRCODE_NONE ) ); + } + } + } + + return bRet; +} + +namespace { + +class FocusWindowWaitCursor +{ +private: + + VclPtr m_pFocusWindow; + +public: + FocusWindowWaitCursor() : + m_pFocusWindow( Application::GetFocusWindow() ) + { + if( m_pFocusWindow ) + { + m_pFocusWindow->AddEventListener( LINK( this, FocusWindowWaitCursor, DestroyedLink ) ); + m_pFocusWindow->EnterWait(); + } + } + + ~FocusWindowWaitCursor() + { + if( m_pFocusWindow ) + { + m_pFocusWindow->LeaveWait(); + m_pFocusWindow->RemoveEventListener( LINK( this, FocusWindowWaitCursor, DestroyedLink ) ); + } + } + + DECL_LINK( DestroyedLink, VclWindowEvent&, void ); +}; + +} + +IMPL_LINK( FocusWindowWaitCursor, DestroyedLink, VclWindowEvent&, rEvent, void ) +{ + if( rEvent.GetId() == VclEventId::ObjectDying ) + m_pFocusWindow = nullptr; +} + + +sal_Bool SAL_CALL PDFFilter::filter( const Sequence< PropertyValue >& rDescriptor ) +{ + FocusWindowWaitCursor aCur; + + const bool bRet = implExport( rDescriptor ); + + return bRet; +} + + +void SAL_CALL PDFFilter::cancel( ) +{ +} + + +void SAL_CALL PDFFilter::setSourceDocument( const Reference< XComponent >& xDoc ) +{ + mxSrcDoc = xDoc; +} + + +void SAL_CALL PDFFilter::initialize( const css::uno::Sequence< css::uno::Any >& ) +{ +} + + +OUString SAL_CALL PDFFilter::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFFilter"; +} + + +sal_Bool SAL_CALL PDFFilter::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService( this, rServiceName ); +} + + +css::uno::Sequence< OUString > SAL_CALL PDFFilter::getSupportedServiceNames( ) +{ + return { "com.sun.star.document.PDFFilter" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PDFFilter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new PDFFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdffilter.hxx b/filter/source/pdf/pdffilter.hxx new file mode 100644 index 000000000..28869272c --- /dev/null +++ b/filter/source/pdf/pdffilter.hxx @@ -0,0 +1,70 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +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::document; + + +class PDFFilter : public cppu::WeakImplHelper < XFilter, XExporter, XInitialization, XServiceInfo > +{ +private: + + Reference< XComponentContext > mxContext; + Reference< XComponent > mxSrcDoc; + + bool implExport( const Sequence< PropertyValue >& rDescriptor ); + +protected: + + // XFilter + virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& rDescriptor ) override; + 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; + +public: + + explicit PDFFilter( const Reference< XComponentContext >& rxContext ); + virtual ~PDFFilter() override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfinteract.cxx b/filter/source/pdf/pdfinteract.cxx new file mode 100644 index 000000000..cf38cf4a0 --- /dev/null +++ b/filter/source/pdf/pdfinteract.cxx @@ -0,0 +1,97 @@ +/* -*- 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 "pdfinteract.hxx" +#include "impdialog.hxx" + +#include +#include +#include +#include +#include + +PDFInteractionHandler::PDFInteractionHandler() +{ +} + +PDFInteractionHandler::~PDFInteractionHandler() +{ +} + +void SAL_CALL PDFInteractionHandler::handle( const Reference< task::XInteractionRequest >& i_xRequest ) +{ + handleInteractionRequest( i_xRequest ); +} + +void SAL_CALL PDFInteractionHandler::initialize(const css::uno::Sequence& rArguments) +{ + comphelper::NamedValueCollection aProperties(rArguments); + if (aProperties.has("Parent")) + aProperties.get("Parent") >>= m_xParent; +} + +sal_Bool SAL_CALL PDFInteractionHandler::handleInteractionRequest( const Reference< task::XInteractionRequest >& i_xRequest ) +{ + bool bHandled = false; + + Any aRequest( i_xRequest->getRequest() ); + task::PDFExportException aExc; + if( aRequest >>= aExc ) + { + std::set< vcl::PDFWriter::ErrorCode > aCodes; + sal_Int32 nCodes = aExc.ErrorCodes.getLength(); + for( sal_Int32 i = 0; i < nCodes; i++ ) + aCodes.insert( static_cast(aExc.ErrorCodes.getConstArray()[i]) ); + + ImplErrorDialog aDlg(Application::GetFrameWeld(m_xParent), aCodes); + aDlg.run(); + bHandled = true; + } + return bHandled; +} + + + +OUString SAL_CALL PDFInteractionHandler::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFExportInteractionHandler"; +} + + +sal_Bool SAL_CALL PDFInteractionHandler::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService( this, rServiceName ); +} + + +css::uno::Sequence< OUString > SAL_CALL PDFInteractionHandler::getSupportedServiceNames( ) +{ + return { "com.sun.star.filter.pdfexport.PDFExportInteractionHandler" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PDFExportInteractionHandler_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new PDFInteractionHandler()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfinteract.hxx b/filter/source/pdf/pdfinteract.hxx new file mode 100644 index 000000000..0af5c260b --- /dev/null +++ b/filter/source/pdf/pdfinteract.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + + +class PDFInteractionHandler : public cppu::WeakImplHelper +{ +private: + css::uno::Reference m_xParent; +protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& rArguments) override; + + // XInteractionHandler + virtual void SAL_CALL handle( const Reference< task::XInteractionRequest >& ) override; + + // XInteractionHandler2 + virtual sal_Bool SAL_CALL handleInteractionRequest( const Reference< task::XInteractionRequest >& ) override; + +public: + + PDFInteractionHandler(); + virtual ~PDFInteractionHandler() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/storagefilterdetect/filterdetect.cxx b/filter/source/storagefilterdetect/filterdetect.cxx new file mode 100644 index 000000000..05eb74769 --- /dev/null +++ b/filter/source/storagefilterdetect/filterdetect.cxx @@ -0,0 +1,192 @@ +/* -*- 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 "filterdetect.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using utl::MediaDescriptor; + +namespace { + +OUString getInternalFromMediaType(std::u16string_view aMediaType) +{ + // OpenDocument types + if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII ) return "writer8"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII ) return "writer8_template"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII ) return "writerweb8_writer_template"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII ) return "writerglobal8"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII ) return "writerglobal8_template"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII ) return "draw8"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII ) return "draw8_template"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII ) return "impress8"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII ) return "impress8_template"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII ) return "calc8"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII ) return "calc8_template"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII ) return "chart8"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII ) return "math8"; + else if ( aMediaType == MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII ) return "StarBaseReportChart"; + + // OOo legacy types + else if ( aMediaType == MIMETYPE_VND_SUN_XML_WRITER_ASCII ) return "writer_StarOffice_XML_Writer"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_WRITER_TEMPLATE_ASCII ) return "writer_StarOffice_XML_Writer_Template"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_WRITER_WEB_ASCII ) return "writer_web_StarOffice_XML_Writer_Web_Template"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII ) return "writer_globaldocument_StarOffice_XML_Writer_GlobalDocument"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_DRAW_ASCII ) return "draw_StarOffice_XML_Draw"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_DRAW_TEMPLATE_ASCII ) return "draw_StarOffice_XML_Draw_Template"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_IMPRESS_ASCII ) return "impress_StarOffice_XML_Impress"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_IMPRESS_TEMPLATE_ASCII ) return "impress_StarOffice_XML_Impress_Template"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_CALC_ASCII ) return "calc_StarOffice_XML_Calc"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_CALC_TEMPLATE_ASCII ) return "calc_StarOffice_XML_Calc_Template"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_CHART_ASCII ) return "chart_StarOffice_XML_Chart"; + else if ( aMediaType == MIMETYPE_VND_SUN_XML_MATH_ASCII ) return "math_StarOffice_XML_Math"; + + // Unknown type + return OUString(); +} + +} + +StorageFilterDetect::StorageFilterDetect(uno::Reference xCxt) : + mxCxt(std::move(xCxt)) {} + +StorageFilterDetect::~StorageFilterDetect() {} + +OUString SAL_CALL StorageFilterDetect::detect(uno::Sequence& rDescriptor) +{ + MediaDescriptor aMediaDesc( rDescriptor ); + OUString aTypeName; + + try + { + uno::Reference< io::XInputStream > xInStream( aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM], uno::UNO_QUERY ); + if ( !xInStream.is() ) + return OUString(); + + uno::Reference< embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream( xInStream, mxCxt ); + if ( !xStorage.is() ) + return OUString(); + + uno::Reference< beans::XPropertySet > xStorageProperties( xStorage, uno::UNO_QUERY ); + if ( !xStorageProperties.is() ) + return OUString(); + + OUString aMediaType; + xStorageProperties->getPropertyValue( "MediaType" ) >>= aMediaType; + aTypeName = getInternalFromMediaType( aMediaType ); + } + + catch( const lang::WrappedTargetException& aWrap ) + { + packages::zip::ZipIOException aZipException; + // We don't do any type detection on broken packages (f.e. because it might be impossible), + // so for repairing we'll use the requested type, which was detected by the flat detection. + OUString aRequestedTypeName = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_TYPENAME, OUString() ); + if ( ( aWrap.TargetException >>= aZipException ) && !aRequestedTypeName.isEmpty() ) + { + // The package is a broken one. + uno::Reference< task::XInteractionHandler > xInteraction = + aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_INTERACTIONHANDLER, uno::Reference< task::XInteractionHandler >() ); + + if ( xInteraction.is() ) + { + INetURLObject aParser( aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_URL, OUString() ) ); + OUString aDocumentTitle = aParser.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ); + bool bRepairPackage = aMediaDesc.getUnpackedValueOrDefault( "RepairPackage", false ); + // fdo#46310 Don't try to repair if the user rejected it once. + bool bRepairAllowed = aMediaDesc.getUnpackedValueOrDefault( "RepairAllowed", true ); + + if ( !bRepairPackage && bRepairAllowed ) + { + // Ask the user whether he wants to try to repair. + RequestPackageReparation aRequest( aDocumentTitle ); + xInteraction->handle( aRequest.GetRequest() ); + + if ( aRequest.isApproved() ) + { + aTypeName = aRequestedTypeName; + aMediaDesc[MediaDescriptor::PROP_DOCUMENTTITLE] <<= aDocumentTitle; + aMediaDesc[MediaDescriptor::PROP_ASTEMPLATE] <<= true; + aMediaDesc["RepairPackage"] <<= true; + } + else + { + // Repair either not allowed or not successful. + NotifyBrokenPackage aNotifyRequest( aDocumentTitle ); + xInteraction->handle( aNotifyRequest.GetRequest() ); + aMediaDesc["RepairAllowed"] <<= false; + } + + // Write the changes back. + aMediaDesc >> rDescriptor; + } + } + } + } + catch( uno::RuntimeException& ) + { + throw; + } + catch( uno::Exception& ) + {} + + return aTypeName; +} + +// XInitialization +void SAL_CALL StorageFilterDetect::initialize(const uno::Sequence& /*aArguments*/) {} + +// XServiceInfo +OUString SAL_CALL StorageFilterDetect::getImplementationName() +{ + return "com.sun.star.comp.filters.StorageFilterDetect"; +} + +sal_Bool SAL_CALL StorageFilterDetect::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence SAL_CALL StorageFilterDetect::getSupportedServiceNames() +{ + return { "com.sun.star.document.ExtendedTypeDetection", "com.sun.star.comp.filters.StorageFilterDetect" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_StorageFilterDetect_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new StorageFilterDetect(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/storagefilterdetect/filterdetect.hxx b/filter/source/storagefilterdetect/filterdetect.hxx new file mode 100644 index 000000000..052e2c2ff --- /dev/null +++ b/filter/source/storagefilterdetect/filterdetect.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include + +#include + +class StorageFilterDetect : public cppu::WeakImplHelper< + css::document::XExtendedFilterDetection, + css::lang::XInitialization, + css::lang::XServiceInfo> +{ + css::uno::Reference mxCxt; + +public: + + explicit StorageFilterDetect (css::uno::Reference xCxt); + virtual ~StorageFilterDetect() override; + + // XExtendedFilterDetection + virtual OUString SAL_CALL detect(css::uno::Sequence& rDescriptor) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& aArguments) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/storagefilterdetect/storagefd.component b/filter/source/storagefilterdetect/storagefd.component new file mode 100644 index 000000000..4a2ea0bf4 --- /dev/null +++ b/filter/source/storagefilterdetect/storagefd.component @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/filter/source/svg/.eslintrc.js b/filter/source/svg/.eslintrc.js new file mode 100644 index 000000000..8daf37eab --- /dev/null +++ b/filter/source/svg/.eslintrc.js @@ -0,0 +1,250 @@ +module.exports = { + "env": { + "browser": true, + "es6": true + }, + "extends": "eslint:recommended", + "rules": { + "accessor-pairs": "error", + "array-bracket-spacing": "off", + "array-callback-return": "error", + "arrow-body-style": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "block-scoped-var": "off", + "block-spacing": [ + "error", + "always" + ], + "brace-style": "off", + "callback-return": "error", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "error", + "comma-dangle": "error", + "comma-spacing": "off", + "comma-style": [ + "error", + "last" + ], + "complexity": "off", + "computed-property-spacing": "off", + "consistent-return": "off", + "consistent-this": "off", + "curly": "off", + "default-case": "off", + "dot-location": [ + "error", + "property" + ], + "dot-notation": "off", + "eol-last": "error", + "eqeqeq": "off", + "func-call-spacing": "error", + "func-name-matching": "error", + "func-names": [ + "error", + "never" + ], + "func-style": "off", + "generator-star-spacing": "error", + "global-require": "error", + "guard-for-in": "off", + "handle-callback-err": "error", + "id-denylist": "error", + "id-length": "off", + "id-match": "error", + "indent": "off", + "init-declarations": "off", + "jsx-quotes": "error", + "key-spacing": "off", + "keyword-spacing": "off", + "line-comment-position": "off", + "linebreak-style": [ + "error", + "unix" + ], + "lines-around-comment": "off", + "lines-around-directive": "off", + "max-depth": "off", + "max-len": "off", + "max-lines": "off", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-ternary": "off", + "new-parens": "error", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": "off", + "no-alert": "off", + "no-array-constructor": "error", + "no-await-in-loop": "error", + "no-bitwise": "off", + "no-caller": "error", + "no-catch-shadow": "error", + "no-compare-neg-zero": "error", + "no-confusing-arrow": "error", + "no-continue": "off", + "no-div-regex": "error", + "no-duplicate-imports": "error", + "no-else-return": "off", + "no-empty-function": "off", + "no-eq-null": "off", + "no-eval": "off", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-label": "error", + "no-extra-parens": "off", + "no-floating-decimal": "error", + "no-implicit-globals": "off", + "no-implied-eval": "off", + "no-inline-comments": "off", + "no-inner-declarations": [ + "error", + "functions" + ], + "no-invalid-this": "error", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-lonely-if": "off", + "no-loop-func": "error", + "no-magic-numbers": "off", + "no-mixed-operators": "off", + "no-mixed-requires": "error", + "no-multi-assign": "off", + "no-multi-spaces": "off", + "no-multi-str": "error", + "no-multiple-empty-lines": "off", + "no-native-reassign": "error", + "no-negated-condition": "off", + "no-negated-in-lhs": "error", + "no-nested-ternary": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-object": "error", + "no-new-require": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "error", + "no-process-exit": "error", + "no-proto": "error", + "no-prototype-builtins": "off", + "no-restricted-globals": "error", + "no-restricted-imports": "error", + "no-restricted-modules": "error", + "no-restricted-properties": "error", + "no-restricted-syntax": "error", + "no-return-assign": [ + "error", + "except-parens" + ], + "no-return-await": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow": "off", + "no-shadow-restricted-names": "error", + "no-spaced-func": "error", + "no-sync": "error", + "no-tabs": "off", + "no-template-curly-in-string": "error", + "no-ternary": "off", + "no-throw-literal": "off", + "no-trailing-spaces": "off", + "no-undef-init": "off", + "no-undefined": "off", + "no-underscore-dangle": "off", + "no-unmodified-loop-condition": "off", + "no-unneeded-ternary": "off", + "no-unused-expressions": "error", + "no-use-before-define": "off", + "no-useless-call": "error", + "no-useless-computed-key": "error", + "no-useless-concat": "off", + "no-useless-constructor": "error", + "no-useless-escape": "error", + "no-useless-rename": "error", + "no-useless-return": "off", + "no-var": "off", + "no-void": "error", + "no-warning-comments": "off", + "no-whitespace-before-property": "error", + "no-with": "error", + "nonblock-statement-body-position": [ + "error", + "any" + ], + "object-curly-newline": "off", + "object-curly-spacing": "off", + "object-property-newline": [ + "error", + { + "allowMultiplePropertiesPerLine": true + } + ], + "object-shorthand": "off", + "one-var": "off", + "one-var-declaration-per-line": "off", + "operator-assignment": "off", + "operator-linebreak": "off", + "padded-blocks": "off", + "prefer-arrow-callback": "off", + "prefer-const": "off", + "prefer-destructuring": [ + "error", + { + "array": false, + "object": false + } + ], + "prefer-numeric-literals": "error", + "prefer-promise-reject-errors": "error", + "prefer-reflect": "off", + "prefer-rest-params": "off", + "prefer-spread": "error", + "prefer-template": "off", + "quote-props": "off", + "quotes": [ + "error", + "single" + ], + "radix": [ + "error", + "as-needed" + ], + "require-await": "error", + "require-jsdoc": "off", + "rest-spread-spacing": "error", + "semi": "off", + "semi-spacing": "off", + "sort-imports": "error", + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "off", + "space-before-function-paren": "off", + "space-in-parens": "off", + "space-infix-ops": "off", + "space-unary-ops": "off", + "spaced-comment": "off", + "strict": "off", + "symbol-description": "error", + "template-curly-spacing": "error", + "template-tag-spacing": "error", + "unicode-bom": [ + "error", + "never" + ], + "valid-jsdoc": "off", + "vars-on-top": "off", + "wrap-iife": "error", + "wrap-regex": "off", + "yield-star-spacing": "error" + } +}; \ No newline at end of file diff --git a/filter/source/svg/gentoken.py b/filter/source/svg/gentoken.py new file mode 100644 index 000000000..c78d066d7 --- /dev/null +++ b/filter/source/svg/gentoken.py @@ -0,0 +1,60 @@ +# 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/. +# + +import sys + +tokenfile_name = sys.argv[1] +hxx_name = sys.argv[2] +gperf_name = sys.argv[3] + +gperf_header = r"""%language=C++ +%global-table +%null-strings +%struct-type +struct xmltoken +{ + const char *name; sal_Int32 nToken; +} +%% +""" + +tokens = {} + +with open(tokenfile_name) as tokenfile: + for line in tokenfile: + line = line.strip() + if line: + arr = line.split() + if len(arr) < 2: + t = "XML_" + arr[0] + t = t.replace('-', '_').replace('.', '_').replace(':', '_') + t = t.replace('+', 'PLUS') + arr.append(t) + tokens[arr[0]] = arr[1].upper() + +hxx = open(hxx_name, 'w') +gperf = open(gperf_name, 'w') + +gperf.write(gperf_header) + +hxx.write("#ifndef INCLUDED_AUTOGEN_TOKEN_HXX\n") +hxx.write("#define INCLUDED_AUTOGEN_TOKEN_HXX\n\n") +hxx.write("#include \n\n" ) + +i = 0; +for token in sorted(tokens.keys()): + i += 1; + hxx.write("const sal_Int32 {} = {};\n".format(tokens[token], i)) + gperf.write("{},{}\n".format(token, tokens[token])) + +gperf.write("%%\n") +hxx.write("const sal_Int32 XML_TOKEN_COUNT = {};\n".format(i)) +hxx.write("const sal_Int32 XML_TOKEN_INVALID = -1;\n\n") +hxx.write("#endif\n") + +hxx.close() +gperf.close() diff --git a/filter/source/svg/js2hxx.py b/filter/source/svg/js2hxx.py new file mode 100755 index 000000000..38bcab12b --- /dev/null +++ b/filter/source/svg/js2hxx.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# 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/. +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# Major Contributor(s): +# Copyright (C) 2011 Marco Cecchetti +# +# All Rights Reserved. +# +# For minor contributions see the git repository. + +import os, sys + +MAX_LINES = 150 +VARIABLE_NAME = 'aSVGScript' + +def get_var_decl(n): + return 'static const char %s%d[] =' % ( VARIABLE_NAME, n ) + +script_name = os.path.basename( sys.argv[0] ) +infile_name = sys.argv[1] +outfile_name = sys.argv[2] + + +# collect input JavaScript file lines +if( not os.path.isfile( infile_name ) ): + print ( '%s: error: file "%s" not found' % ( script_name, infile_name ) ) + sys.exit( -1 ) + +infile = open( infile_name, 'r' ) +in_lines = [line.rstrip() for line in infile.readlines()] +infile.close() + + +valid_lines=[] +is_multiline_comment = False +lineNumber = 0 +emptyLineCount = 0 +for line in in_lines: + lineNumber += 1 + index = line.find('"') + if( index != -1 ): + print ( '%s: warning: processed file contains \'"\' at %d:%d' % ( script_name, lineNumber, index ) ) + + sline = line.strip() + + # strip comment lines except multilines comments that begins with one '/' and exactly 5 '*' + if( is_multiline_comment and sline.endswith( '*/' ) ): + is_multiline_comment = False + continue + + if( is_multiline_comment ): + continue + + if( sline.startswith( '//' ) ): + continue + + if( sline.startswith( '/*' ) and sline.endswith( '*/' ) ): + continue + + if( ( sline.startswith( '/*' ) and not sline.startswith( '/*****' ) ) + or sline.startswith( '/******' ) ): + is_multiline_comment = True + continue + + # disable any debug printer + dline = line.replace( 'NAVDBG.on', 'NAVDBG.off' ) + dline = dline.replace( 'ANIMDBG.on', 'ANIMDBG.off' ) + dline = dline.replace( 'DebugPrinter.on', 'DebugPrinter.off' ) + + escaped_line = '%s' % dline + escaped_line = escaped_line.rstrip().lstrip() + + # no more than 2 consecutive empty lines + if( escaped_line == '' ): + emptyLineCount += 1 + else: + emptyLineCount = 0 + + if( emptyLineCount > 2 ): + continue + + # append to some escape sequence another '\' + escaped_line = escaped_line.replace( '\\', '\\\\' ) + escaped_line = escaped_line.replace( '\n', '\\n') + escaped_line = escaped_line.replace( '\t', '\\t' ) + + valid_lines.append( escaped_line ) + + +# compute the number of needed fragments that is of C constant strings +total_valid_lines = len (valid_lines) + 2 +total_fragments = total_valid_lines / MAX_LINES +if( ( total_valid_lines % MAX_LINES ) != 0 ): + total_fragments += 1 + + + +out_lines = [] +out_lines.append( '' ) +out_lines.append( '#define N_SVGSCRIPT_FRAGMENTS %d' % total_fragments ) +out_lines.append( '' ) +out_lines.append( get_var_decl( 0 ) ) +out_lines.append( '"";' ) +out_lines.append( '' ) + +out_lines.append('static const char * g_SVGScripts[N_SVGSCRIPT_FRAGMENTS] = {') +for j in range(0, fragment+1): + out_lines.append(" %s%d," % (VARIABLE_NAME, j)) +out_lines.append('};') + +outfile = open( outfile_name, 'w' ) +if( not os.path.isfile( outfile_name ) ): + print ( '%s: error: I cannot create file "%s"' % ( script_name, outfile_name ) ) + sys.exit( -1 ) + + +# C++ header +header_info = '/* !! This file is auto-generated, do not edit !! */' + +outfile.write( header_info +'\n\n' ) + +for line in out_lines: + outfile.write( line + '\n' ) + +outfile.close() diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js new file mode 100644 index 000000000..6473963f8 --- /dev/null +++ b/filter/source/svg/presentation_engine.js @@ -0,0 +1,19575 @@ +/* -*- Mode: JS; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * - Presentation Engine - * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * / + +/** + * WARNING: any comment that should not be striped out by the script + * generating the C++ header file must start with a '/' and exactly 5 '*' + * not striped examples: '/*****', '/***** *' + * striped examples: '/** ***' (not contiguous), '/******' (more than 5) + * + * NOTE: This file combines several works, under different + * licenses. See the @licstart / @licend sections below. + */ + +/*! Hammer.JS - v2.0.7 - 2016-04-22 + * http://hammerjs.github.io/ + * + * Copyright (c) 2016 Jorik Tangelder; + * Licensed under the MIT license */ +(function(window, document, exportName, undefined) { + 'use strict'; + +var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o']; +var TEST_ELEMENT = document.createElement('div'); + +var TYPE_FUNCTION = 'function'; + +var round = Math.round; +var abs = Math.abs; +var now = Date.now; + +/** + * polyfill for IE11 + */ +if (!Math.trunc) { + Math.trunc = function (v) { + return v < 0 ? Math.ceil(v) : Math.floor(v); + }; +} + +/** + * set a timeout with a given scope + * @param {Function} fn + * @param {Number} timeout + * @param {Object} context + * @returns {number} + */ +function setTimeoutContext(fn, timeout, context) { + return setTimeout(bindFn(fn, context), timeout); +} + +/** + * if the argument is an array, we want to execute the fn on each entry + * if it aint an array we don't want to do a thing. + * this is used by all the methods that accept a single and array argument. + * @param {*|Array} arg + * @param {String} fn + * @param {Object} [context] + * @returns {Boolean} + */ +function invokeArrayArg(arg, fn, context) { + if (Array.isArray(arg)) { + each(arg, context[fn], context); + return true; + } + return false; +} + +/** + * walk objects and arrays + * @param {Object} obj + * @param {Function} iterator + * @param {Object} context + */ +function each(obj, iterator, context) { + var i; + + if (!obj) { + return; + } + + if (obj.forEach) { + obj.forEach(iterator, context); + } else if (obj.length !== undefined) { + i = 0; + while (i < obj.length) { + iterator.call(context, obj[i], i, obj); + i++; + } + } else { + for (i in obj) { + obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj); + } + } +} + +/** + * wrap a method with a deprecation warning and stack trace + * @param {Function} method + * @param {String} name + * @param {String} message + * @returns {Function} A new function wrapping the supplied method. + */ +function deprecate(method, name, message) { + var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n'; + return function() { + var e = new Error('get-stack-trace'); + var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '') + .replace(/^\s+at\s+/gm, '') + .replace(/^Object.\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace'; + + var log = window.console && (window.console.warn || window.console.log); + if (log) { + log.call(window.console, deprecationMessage, stack); + } + return method.apply(this, arguments); + }; +} + +/** + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} target + * @param {...Object} objects_to_assign + * @returns {Object} target + */ +var assign; +if (typeof Object.assign !== 'function') { + assign = function assign(target) { + if (target === undefined || target === null) { + throw new TypeError('Cannot convert undefined or null to object'); + } + + var output = Object(target); + for (var index = 1; index < arguments.length; index++) { + var source = arguments[index]; + if (source !== undefined && source !== null) { + for (var nextKey in source) { + if (source.hasOwnProperty(nextKey)) { + output[nextKey] = source[nextKey]; + } + } + } + } + return output; + }; +} else { + assign = Object.assign; +} + +/** + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge=false] + * @returns {Object} dest + */ +var extend = deprecate(function extend(dest, src, merge) { + var keys = Object.keys(src); + var i = 0; + while (i < keys.length) { + if (!merge || (merge && dest[keys[i]] === undefined)) { + dest[keys[i]] = src[keys[i]]; + } + i++; + } + return dest; +}, 'extend', 'Use `assign`.'); + +/** + * merge the values from src in the dest. + * means that properties that exist in dest will not be overwritten by src + * @param {Object} dest + * @param {Object} src + * @returns {Object} dest + */ +var merge = deprecate(function merge(dest, src) { + return extend(dest, src, true); +}, 'merge', 'Use `assign`.'); + +/** + * simple class inheritance + * @param {Function} child + * @param {Function} base + * @param {Object} [properties] + */ +function inherit(child, base, properties) { + var baseP = base.prototype, + childP; + + childP = child.prototype = Object.create(baseP); + childP.constructor = child; + childP._super = baseP; + + if (properties) { + assign(childP, properties); + } +} + +/** + * simple function bind + * @param {Function} fn + * @param {Object} context + * @returns {Function} + */ +function bindFn(fn, context) { + return function boundFn() { + return fn.apply(context, arguments); + }; +} + +/** + * let a boolean value also be a function that must return a boolean + * this first item in args will be used as the context + * @param {Boolean|Function} val + * @param {Array} [args] + * @returns {Boolean} + */ +function boolOrFn(val, args) { + if (typeof val == TYPE_FUNCTION) { + return val.apply(args ? args[0] || undefined : undefined, args); + } + return val; +} + +/** + * use the val2 when val1 is undefined + * @param {*} val1 + * @param {*} val2 + * @returns {*} + */ +function ifUndefined(val1, val2) { + return (val1 === undefined) ? val2 : val1; +} + +/** + * addEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ +function addEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.addEventListener(type, handler, false); + }); +} + +/** + * removeEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ +function removeEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.removeEventListener(type, handler, false); + }); +} + +/** + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found + */ +function hasParent(node, parent) { + while (node) { + if (node == parent) { + return true; + } + node = node.parentNode; + } + return false; +} + +/** + * small indexOf wrapper + * @param {String} str + * @param {String} find + * @returns {Boolean} found + */ +function inStr(str, find) { + return str.indexOf(find) > -1; +} + +/** + * split string on whitespace + * @param {String} str + * @returns {Array} words + */ +function splitStr(str) { + return str.trim().split(/\s+/g); +} + +/** + * find if an array contains the object using indexOf or a simple polyFill + * @param {Array} src + * @param {String} find + * @param {String} [findByKey] + * @return {Boolean|Number} false when not found, or the index + */ +function inArray(src, find, findByKey) { + if (src.indexOf && !findByKey) { + return src.indexOf(find); + } else { + var i = 0; + while (i < src.length) { + if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) { + return i; + } + i++; + } + return -1; + } +} + +/** + * convert array-like objects to real arrays + * @param {Object} obj + * @returns {Array} + */ +function toArray(obj) { + return Array.prototype.slice.call(obj, 0); +} + +/** + * unique array with objects based on a key (like 'id') or just by the array's value + * @param {Array} src [{id:1},{id:2},{id:1}] + * @param {String} [key] + * @param {Boolean} [sort=False] + * @returns {Array} [{id:1},{id:2}] + */ +function uniqueArray(src, key, sort) { + var results = []; + var values = []; + var i = 0; + + while (i < src.length) { + var val = key ? src[i][key] : src[i]; + if (inArray(values, val) < 0) { + results.push(src[i]); + } + values[i] = val; + i++; + } + + if (sort) { + if (!key) { + results = results.sort(); + } else { + results = results.sort(function sortUniqueArray(a, b) { + return a[key] > b[key]; + }); + } + } + + return results; +} + +/** + * get the prefixed property + * @param {Object} obj + * @param {String} property + * @returns {String|Undefined} prefixed + */ +function prefixed(obj, property) { + // tml: Have to check for obj being undefined + if (obj === undefined) { + return undefined; + } + + var prefix, prop; + var camelProp = property[0].toUpperCase() + property.slice(1); + + var i = 0; + while (i < VENDOR_PREFIXES.length) { + prefix = VENDOR_PREFIXES[i]; + prop = (prefix) ? prefix + camelProp : property; + + if (prop in obj) { + return prop; + } + i++; + } + return undefined; +} + +/** + * get a unique id + * @returns {number} uniqueId + */ +var _uniqueId = 1; +function uniqueId() { + return _uniqueId++; +} + +/** + * get the window object of an element + * @param {HTMLElement} element + * @returns {DocumentView|Window} + */ +function getWindowForElement(element) { + var doc = element.ownerDocument || element; + return (doc.defaultView || doc.parentWindow || window); +} + +var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; + +var SUPPORT_TOUCH = ('ontouchstart' in window); +var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined; +var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent); + +var INPUT_TYPE_TOUCH = 'touch'; +var INPUT_TYPE_PEN = 'pen'; +var INPUT_TYPE_MOUSE = 'mouse'; +var INPUT_TYPE_KINECT = 'kinect'; + +var COMPUTE_INTERVAL = 25; + +var INPUT_START = 1; +var INPUT_MOVE = 2; +var INPUT_END = 4; +var INPUT_CANCEL = 8; + +var DIRECTION_NONE = 1; +var DIRECTION_LEFT = 2; +var DIRECTION_RIGHT = 4; +var DIRECTION_UP = 8; +var DIRECTION_DOWN = 16; + +var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT; +var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN; +var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; + +var PROPS_XY = ['x', 'y']; +var PROPS_CLIENT_XY = ['clientX', 'clientY']; + +/** + * create new input type manager + * @param {Manager} manager + * @param {Function} callback + * @returns {Input} + * @constructor + */ +function Input(manager, callback) { + var self = this; + this.manager = manager; + this.callback = callback; + this.element = manager.element; + this.target = manager.options.inputTarget; + + // smaller wrapper around the handler, for the scope and the enabled state of the manager, + // so when disabled the input events are completely bypassed. + this.domHandler = function(ev) { + if (boolOrFn(manager.options.enable, [manager])) { + self.handler(ev); + } + }; + + this.init(); + +} + +Input.prototype = { + /** + * should handle the inputEvent data and trigger the callback + * @virtual + */ + handler: function() { }, + + /** + * bind the events + */ + init: function() { + this.evEl && addEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + }, + + /** + * unbind the events + */ + destroy: function() { + this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + } +}; + +/** + * create new input type manager + * called by the Manager constructor + * @param {Hammer} manager + * @returns {Input} + */ +function createInputInstance(manager) { + var Type; + var inputClass = manager.options.inputClass; + + if (inputClass) { + Type = inputClass; + } else if (!SUPPORT_TOUCH && SUPPORT_POINTER_EVENTS) { + Type = PointerEventInput; + } else if (SUPPORT_ONLY_TOUCH) { + Type = TouchInput; + } else if (!SUPPORT_TOUCH) { + Type = MouseInput; + } else { + Type = TouchMouseInput; + } + return new (Type)(manager, inputHandler); +} + +/** + * handle input events + * @param {Manager} manager + * @param {String} eventType + * @param {Object} input + */ +function inputHandler(manager, eventType, input) { + var pointersLen = input.pointers.length; + var changedPointersLen = input.changedPointers.length; + var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0)); + var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0)); + + input.isFirst = !!isFirst; + input.isFinal = !!isFinal; + + if (isFirst) { + manager.session = {}; + } + + // source event is the normalized value of the domEvents + // like 'touchstart, mouseup, pointerdown' + input.eventType = eventType; + + // compute scale, rotation etc + computeInputData(manager, input); + + // emit secret event + manager.emit('hammer.input', input); + + manager.recognize(input); + manager.session.prevInput = input; +} + +/** + * extend the data with some usable properties like scale, rotate, velocity etc + * @param {Object} manager + * @param {Object} input + */ +function computeInputData(manager, input) { + var session = manager.session; + var pointers = input.pointers; + var pointersLength = pointers.length; + + // store the first input to calculate the distance and direction + if (!session.firstInput) { + session.firstInput = simpleCloneInputData(input); + } + + // to compute scale and rotation we need to store the multiple touches + if (pointersLength > 1 && !session.firstMultiple) { + session.firstMultiple = simpleCloneInputData(input); + } else if (pointersLength === 1) { + session.firstMultiple = false; + } + + var firstInput = session.firstInput; + var firstMultiple = session.firstMultiple; + var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center; + + var center = input.center = getCenter(pointers); + input.timeStamp = now(); + input.deltaTime = input.timeStamp - firstInput.timeStamp; + + input.angle = getAngle(offsetCenter, center); + input.distance = getDistance(offsetCenter, center); + + computeDeltaXY(session, input); + input.offsetDirection = getDirection(input.deltaX, input.deltaY); + + var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY); + input.overallVelocityX = overallVelocity.x; + input.overallVelocityY = overallVelocity.y; + input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y; + + input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1; + input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0; + + input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length > + session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers); + + computeIntervalInputData(session, input); + + // find the correct target + var target = manager.element; + if (hasParent(input.srcEvent.target, target)) { + target = input.srcEvent.target; + } + input.target = target; +} + +function computeDeltaXY(session, input) { + var center = input.center; + var offset = session.offsetDelta || {}; + var prevDelta = session.prevDelta || {}; + var prevInput = session.prevInput || {}; + + if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) { + prevDelta = session.prevDelta = { + x: prevInput.deltaX || 0, + y: prevInput.deltaY || 0 + }; + + offset = session.offsetDelta = { + x: center.x, + y: center.y + }; + } + + input.deltaX = prevDelta.x + (center.x - offset.x); + input.deltaY = prevDelta.y + (center.y - offset.y); +} + +/** + * velocity is calculated every x ms + * @param {Object} session + * @param {Object} input + */ +function computeIntervalInputData(session, input) { + var last = session.lastInterval || input, + deltaTime = input.timeStamp - last.timeStamp, + velocity, velocityX, velocityY, direction; + + if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) { + var deltaX = input.deltaX - last.deltaX; + var deltaY = input.deltaY - last.deltaY; + + var v = getVelocity(deltaTime, deltaX, deltaY); + velocityX = v.x; + velocityY = v.y; + velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y; + direction = getDirection(deltaX, deltaY); + + session.lastInterval = input; + } else { + // use latest velocity info if it doesn't overtake a minimum period + velocity = last.velocity; + velocityX = last.velocityX; + velocityY = last.velocityY; + direction = last.direction; + } + + input.velocity = velocity; + input.velocityX = velocityX; + input.velocityY = velocityY; + input.direction = direction; +} + +/** + * create a simple clone from the input used for storage of firstInput and firstMultiple + * @param {Object} input + * @returns {Object} clonedInputData + */ +function simpleCloneInputData(input) { + // make a simple copy of the pointers because we will get a reference if we don't + // we only need clientXY for the calculations + var pointers = []; + var i = 0; + while (i < input.pointers.length) { + pointers[i] = { + clientX: round(input.pointers[i].clientX), + clientY: round(input.pointers[i].clientY) + }; + i++; + } + + return { + timeStamp: now(), + pointers: pointers, + center: getCenter(pointers), + deltaX: input.deltaX, + deltaY: input.deltaY + }; +} + +/** + * get the center of all the pointers + * @param {Array} pointers + * @return {Object} center contains `x` and `y` properties + */ +function getCenter(pointers) { + var pointersLength = pointers.length; + + // no need to loop when only one touch + if (pointersLength === 1) { + return { + x: round(pointers[0].clientX), + y: round(pointers[0].clientY) + }; + } + + var x = 0, y = 0, i = 0; + while (i < pointersLength) { + x += pointers[i].clientX; + y += pointers[i].clientY; + i++; + } + + return { + x: round(x / pointersLength), + y: round(y / pointersLength) + }; +} + +/** + * calculate the velocity between two points. unit is in px per ms. + * @param {Number} deltaTime + * @param {Number} x + * @param {Number} y + * @return {Object} velocity `x` and `y` + */ +function getVelocity(deltaTime, x, y) { + return { + x: x / deltaTime || 0, + y: y / deltaTime || 0 + }; +} + +/** + * get the direction between two points + * @param {Number} x + * @param {Number} y + * @return {Number} direction + */ +function getDirection(x, y) { + if (x === y) { + return DIRECTION_NONE; + } + + if (abs(x) >= abs(y)) { + return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return y < 0 ? DIRECTION_UP : DIRECTION_DOWN; +} + +/** + * calculate the absolute distance between two points + * @param {Object} p1 {x, y} + * @param {Object} p2 {x, y} + * @param {Array} [props] containing x and y keys + * @return {Number} distance + */ +function getDistance(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + + return Math.sqrt((x * x) + (y * y)); +} + +/** + * calculate the angle between two coordinates + * @param {Object} p1 + * @param {Object} p2 + * @param {Array} [props] containing x and y keys + * @return {Number} angle + */ +function getAngle(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + return Math.atan2(y, x) * 180 / Math.PI; +} + +/** + * calculate the rotation degrees between two pointersets + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} rotation + */ +function getRotation(start, end) { + return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY); +} + +/** + * calculate the scale factor between two pointersets + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} scale + */ +function getScale(start, end) { + return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY); +} + +var MOUSE_INPUT_MAP = { + mousedown: INPUT_START, + mousemove: INPUT_MOVE, + mouseup: INPUT_END +}; + +var MOUSE_ELEMENT_EVENTS = 'mousedown'; +var MOUSE_WINDOW_EVENTS = 'mousemove mouseup'; + +/** + * Mouse events input + * @constructor + * @extends Input + */ +function MouseInput() { + this.evEl = MOUSE_ELEMENT_EVENTS; + this.evWin = MOUSE_WINDOW_EVENTS; + + this.pressed = false; // mousedown state + + Input.apply(this, arguments); +} + +inherit(MouseInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function MEhandler(ev) { + // console.log('==> MouseInput handler'); + var eventType = MOUSE_INPUT_MAP[ev.type]; + + // on start we want to have the left mouse button down + if (eventType & INPUT_START && ev.button === 0) { + this.pressed = true; + } + + if (eventType & INPUT_MOVE && ev.which !== 1) { + eventType = INPUT_END; + } + + // mouse must be down + if (!this.pressed) { + return; + } + + if (eventType & INPUT_END) { + this.pressed = false; + } + + this.callback(this.manager, eventType, { + pointers: [ev], + changedPointers: [ev], + pointerType: INPUT_TYPE_MOUSE, + srcEvent: ev + }); + } +}); + +var POINTER_INPUT_MAP = { + pointerdown: INPUT_START, + pointermove: INPUT_MOVE, + pointerup: INPUT_END, + pointercancel: INPUT_CANCEL, + pointerout: INPUT_CANCEL +}; + +// in IE10 the pointer types is defined as an enum +var IE10_POINTER_TYPE_ENUM = { + 2: INPUT_TYPE_TOUCH, + 3: INPUT_TYPE_PEN, + 4: INPUT_TYPE_MOUSE, + 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816 +}; + +var POINTER_ELEMENT_EVENTS = 'pointerdown'; +var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; + +// IE10 has prefixed support, and case-sensitive +if (window.MSPointerEvent && !window.PointerEvent) { + POINTER_ELEMENT_EVENTS = 'MSPointerDown'; + POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel'; +} + +/** + * Pointer events input + * @constructor + * @extends Input + */ +function PointerEventInput() { + this.evEl = POINTER_ELEMENT_EVENTS; + this.evWin = POINTER_WINDOW_EVENTS; + + Input.apply(this, arguments); + + this.store = (this.manager.session.pointerEvents = []); +} + +inherit(PointerEventInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function PEhandler(ev) { + // console.log('==> PointerEventInput handler'); + var store = this.store; + var removePointer = false; + + var eventTypeNormalized = ev.type.toLowerCase().replace('ms', ''); + var eventType = POINTER_INPUT_MAP[eventTypeNormalized]; + var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType; + + var isTouch = (pointerType == INPUT_TYPE_TOUCH); + + // get index of the event in the store + var storeIndex = inArray(store, ev.pointerId, 'pointerId'); + + // start and mouse must be down + if (eventType & INPUT_START && (ev.button === 0 || isTouch)) { + if (storeIndex < 0) { + store.push(ev); + storeIndex = store.length - 1; + } + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + removePointer = true; + } + + // it not found, so the pointer hasn't been down (so it's probably a hover) + if (storeIndex < 0) { + return; + } + + // update the event in the store + store[storeIndex] = ev; + + this.callback(this.manager, eventType, { + pointers: store, + changedPointers: [ev], + pointerType: pointerType, + srcEvent: ev + }); + + if (removePointer) { + // remove from the store + store.splice(storeIndex, 1); + } + } +}); + +var SINGLE_TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL +}; + +var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart'; +var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel'; + +/** + * Touch events input + * @constructor + * @extends Input + */ +function SingleTouchInput() { + this.evTarget = SINGLE_TOUCH_TARGET_EVENTS; + this.evWin = SINGLE_TOUCH_WINDOW_EVENTS; + this.started = false; + + Input.apply(this, arguments); +} + +inherit(SingleTouchInput, Input, { + handler: function TEhandler(ev) { + // console.log('==> SingleTouchInput handler'); + var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; + + // should we handle the touch events? + if (type === INPUT_START) { + this.started = true; + } + + if (!this.started) { + return; + } + + var touches = normalizeSingleTouches.call(this, ev, type); + + // when done, reset the started state + if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) { + this.started = false; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } +}); + +/** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ +function normalizeSingleTouches(ev, type) { + var all = toArray(ev.touches); + var changed = toArray(ev.changedTouches); + + if (type & (INPUT_END | INPUT_CANCEL)) { + all = uniqueArray(all.concat(changed), 'identifier', true); + } + + return [all, changed]; +} + +var TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL +}; + +var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel'; + +/** + * Multi-user touch events input + * @constructor + * @extends Input + */ +function TouchInput() { + this.evTarget = TOUCH_TARGET_EVENTS; + this.targetIds = {}; + + Input.apply(this, arguments); +} + +inherit(TouchInput, Input, { + handler: function MTEhandler(ev) { + // console.log('==> TouchInput handler'); + var type = TOUCH_INPUT_MAP[ev.type]; + var touches = getTouches.call(this, ev, type); + if (!touches) { + return; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } +}); + +/** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ +function getTouches(ev, type) { + var allTouches = toArray(ev.touches); + var targetIds = this.targetIds; + + // when there is only one touch, the process can be simplified + if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) { + targetIds[allTouches[0].identifier] = true; + return [allTouches, allTouches]; + } + + var i, + targetTouches, + changedTouches = toArray(ev.changedTouches), + changedTargetTouches = [], + target = this.target; + + // get target touches from touches + targetTouches = allTouches.filter(function(touch) { + return hasParent(touch.target, target); + }); + + // collect touches + if (type === INPUT_START) { + i = 0; + while (i < targetTouches.length) { + targetIds[targetTouches[i].identifier] = true; + i++; + } + } + + // filter changed touches to only contain touches that exist in the collected target ids + i = 0; + while (i < changedTouches.length) { + if (targetIds[changedTouches[i].identifier]) { + changedTargetTouches.push(changedTouches[i]); + } + + // cleanup removed touches + if (type & (INPUT_END | INPUT_CANCEL)) { + delete targetIds[changedTouches[i].identifier]; + } + i++; + } + + if (!changedTargetTouches.length) { + return; + } + + return [ + // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel' + uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), + changedTargetTouches + ]; +} + +/** + * Combined touch and mouse input + * + * Touch has a higher priority then mouse, and while touching no mouse events are allowed. + * This because touch devices also emit mouse events while doing a touch. + * + * @constructor + * @extends Input + */ + +var DEDUP_TIMEOUT = 2500; +var DEDUP_DISTANCE = 25; + +function TouchMouseInput() { + Input.apply(this, arguments); + + var handler = bindFn(this.handler, this); + this.touch = new TouchInput(this.manager, handler); + this.mouse = new MouseInput(this.manager, handler); + + this.primaryTouch = null; + this.lastTouches = []; +} + +inherit(TouchMouseInput, Input, { + /** + * handle mouse and touch events + * @param {Hammer} manager + * @param {String} inputEvent + * @param {Object} inputData + */ + handler: function TMEhandler(manager, inputEvent, inputData) { + // console.log('==> TouchMouseInput handler'); + var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH), + isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE); + + if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) { + return; + } + + // when we're in a touch event, record touches to de-dupe synthetic mouse event + if (isTouch) { + recordTouches.call(this, inputEvent, inputData); + } else if (isMouse && isSyntheticEvent.call(this, inputData)) { + return; + } + + this.callback(manager, inputEvent, inputData); + }, + + /** + * remove the event listeners + */ + destroy: function destroy() { + this.touch.destroy(); + this.mouse.destroy(); + } +}); + +function recordTouches(eventType, eventData) { + if (eventType & INPUT_START) { + this.primaryTouch = eventData.changedPointers[0].identifier; + setLastTouch.call(this, eventData); + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + setLastTouch.call(this, eventData); + } +} + +function setLastTouch(eventData) { + var touch = eventData.changedPointers[0]; + + if (touch.identifier === this.primaryTouch) { + var lastTouch = {x: touch.clientX, y: touch.clientY}; + this.lastTouches.push(lastTouch); + var lts = this.lastTouches; + var removeLastTouch = function() { + var i = lts.indexOf(lastTouch); + if (i > -1) { + lts.splice(i, 1); + } + }; + setTimeout(removeLastTouch, DEDUP_TIMEOUT); + } +} + +function isSyntheticEvent(eventData) { + var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY; + for (var i = 0; i < this.lastTouches.length; i++) { + var t = this.lastTouches[i]; + var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y); + if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) { + return true; + } + } + return false; +} + +var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction'); +var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined; + +// magical touchAction value +var TOUCH_ACTION_COMPUTE = 'compute'; +var TOUCH_ACTION_AUTO = 'auto'; +var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented +var TOUCH_ACTION_NONE = 'none'; +var TOUCH_ACTION_PAN_X = 'pan-x'; +var TOUCH_ACTION_PAN_Y = 'pan-y'; +var TOUCH_ACTION_MAP = getTouchActionProps(); + +/** + * Touch Action + * sets the touchAction property or uses the js alternative + * @param {Manager} manager + * @param {String} value + * @constructor + */ +function TouchAction(manager, value) { + this.manager = manager; + this.set(value); +} + +TouchAction.prototype = { + /** + * set the touchAction value on the element or enable the polyfill + * @param {String} value + */ + set: function(value) { + // find out the touch-action by the event handlers + if (value == TOUCH_ACTION_COMPUTE) { + value = this.compute(); + } + + if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) { + this.manager.element.style[PREFIXED_TOUCH_ACTION] = value; + } + this.actions = value.toLowerCase().trim(); + }, + + /** + * just re-set the touchAction value + */ + update: function() { + this.set(this.manager.options.touchAction); + }, + + /** + * compute the value for the touchAction property based on the recognizer's settings + * @returns {String} value + */ + compute: function() { + var actions = []; + each(this.manager.recognizers, function(recognizer) { + if (boolOrFn(recognizer.options.enable, [recognizer])) { + actions = actions.concat(recognizer.getTouchAction()); + } + }); + return cleanTouchActions(actions.join(' ')); + }, + + /** + * this method is called on each input cycle and provides the preventing of the browser behavior + * @param {Object} input + */ + preventDefaults: function(input) { + var srcEvent = input.srcEvent; + var direction = input.offsetDirection; + + // if the touch action did prevented once this session + if (this.manager.session.prevented) { + srcEvent.preventDefault(); + return; + } + + var actions = this.actions; + var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE]; + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y]; + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X]; + + if (hasNone) { + //do not prevent defaults if this is a tap gesture + + var isTapPointer = input.pointers.length === 1; + var isTapMovement = input.distance < 2; + var isTapTouchTime = input.deltaTime < 250; + + if (isTapPointer && isTapMovement && isTapTouchTime) { + return; + } + } + + if (hasPanX && hasPanY) { + // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent + return; + } + + if (hasNone || + (hasPanY && direction & DIRECTION_HORIZONTAL) || + (hasPanX && direction & DIRECTION_VERTICAL)) { + return this.preventSrc(srcEvent); + } + }, + + /** + * call preventDefault to prevent the browser's default behavior (scrolling in most cases) + * @param {Object} srcEvent + */ + preventSrc: function(srcEvent) { + this.manager.session.prevented = true; + srcEvent.preventDefault(); + } +}; + +/** + * when the touchActions are collected they are not a valid value, so we need to clean things up. * + * @param {String} actions + * @returns {*} + */ +function cleanTouchActions(actions) { + // none + if (inStr(actions, TOUCH_ACTION_NONE)) { + return TOUCH_ACTION_NONE; + } + + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X); + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); + + // if both pan-x and pan-y are set (different recognizers + // for different directions, e.g. horizontal pan but vertical swipe?) + // we need none (as otherwise with pan-x pan-y combined none of these + // recognizers will work, since the browser would handle all panning + if (hasPanX && hasPanY) { + return TOUCH_ACTION_NONE; + } + + // pan-x OR pan-y + if (hasPanX || hasPanY) { + return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y; + } + + // manipulation + if (inStr(actions, TOUCH_ACTION_MANIPULATION)) { + return TOUCH_ACTION_MANIPULATION; + } + + return TOUCH_ACTION_AUTO; +} + +function getTouchActionProps() { + if (!NATIVE_TOUCH_ACTION) { + return false; + } + var touchMap = {}; + var cssSupports = window.CSS && window.CSS.supports; + ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) { + + // If css.supports is not supported but there is native touch-action assume it supports + // all values. This is the case for IE 10 and 11. + touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true; + }); + return touchMap; +} + +/** + * Recognizer flow explained; * + * All recognizers have the initial state of POSSIBLE when an input session starts. + * The definition of an input session is from the first input until the last input, with all it's movement in it. * + * Example session for mouse-input: mousedown -> mousemove -> mouseup + * + * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed + * which determines with state it should be. + * + * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to + * POSSIBLE to give it another change on the next cycle. + * + * Possible + * | + * +-----+---------------+ + * | | + * +-----+-----+ | + * | | | + * Failed Cancelled | + * +-------+------+ + * | | + * Recognized Began + * | + * Changed + * | + * Ended/Recognized + */ +var STATE_POSSIBLE = 1; +var STATE_BEGAN = 2; +var STATE_CHANGED = 4; +var STATE_ENDED = 8; +var STATE_RECOGNIZED = STATE_ENDED; +var STATE_CANCELLED = 16; +var STATE_FAILED = 32; + +/** + * Recognizer + * Every recognizer needs to extend from this class. + * @constructor + * @param {Object} options + */ +function Recognizer(options) { + this.options = assign({}, this.defaults, options || {}); + + this.id = uniqueId(); + + this.manager = null; + + // default is enable true + this.options.enable = ifUndefined(this.options.enable, true); + + this.state = STATE_POSSIBLE; + + this.simultaneous = {}; + this.requireFail = []; +} + +Recognizer.prototype = { + /** + * @virtual + * @type {Object} + */ + defaults: {}, + + /** + * set options + * @param {Object} options + * @return {Recognizer} + */ + set: function(options) { + assign(this.options, options); + + // also update the touchAction, in case something changed about the directions/enabled state + this.manager && this.manager.touchAction.update(); + return this; + }, + + /** + * recognize simultaneous with another recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + recognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) { + return this; + } + + var simultaneous = this.simultaneous; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (!simultaneous[otherRecognizer.id]) { + simultaneous[otherRecognizer.id] = otherRecognizer; + otherRecognizer.recognizeWith(this); + } + return this; + }, + + /** + * drop the simultaneous link. It doesn't remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRecognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + delete this.simultaneous[otherRecognizer.id]; + return this; + }, + + /** + * recognizer can only run when another is failing + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + requireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) { + return this; + } + + var requireFail = this.requireFail; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (inArray(requireFail, otherRecognizer) === -1) { + requireFail.push(otherRecognizer); + otherRecognizer.requireFailure(this); + } + return this; + }, + + /** + * drop the requireFailure link. It does not remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRequireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + var index = inArray(this.requireFail, otherRecognizer); + if (index > -1) { + this.requireFail.splice(index, 1); + } + return this; + }, + + /** + * has require failures boolean + * @returns {boolean} + */ + hasRequireFailures: function() { + return this.requireFail.length > 0; + }, + + /** + * if the recognizer can recognize simultaneous with another recognizer + * @param {Recognizer} otherRecognizer + * @returns {Boolean} + */ + canRecognizeWith: function(otherRecognizer) { + return !!this.simultaneous[otherRecognizer.id]; + }, + + /** + * You should use `tryEmit` instead of `emit` directly to check + * that all the needed recognizers has failed before emitting. + * @param {Object} input + */ + emit: function(input) { + var self = this; + var state = this.state; + + function emit(event) { + self.manager.emit(event, input); + } + + // 'panstart' and 'panmove' + if (state < STATE_ENDED) { + emit(self.options.event + stateStr(state)); + } + + emit(self.options.event); // simple 'eventName' events + + if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...) + emit(input.additionalEvent); + } + + // panend and pancancel + if (state >= STATE_ENDED) { + emit(self.options.event + stateStr(state)); + } + }, + + /** + * Check that all the require failure recognizers has failed, + * if true, it emits a gesture event, + * otherwise, setup the state to FAILED. + * @param {Object} input + */ + tryEmit: function(input) { + if (this.canEmit()) { + return this.emit(input); + } + // it's failing anyway + this.state = STATE_FAILED; + }, + + /** + * can we emit? + * @returns {boolean} + */ + canEmit: function() { + var i = 0; + while (i < this.requireFail.length) { + if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) { + return false; + } + i++; + } + return true; + }, + + /** + * update the recognizer + * @param {Object} inputData + */ + recognize: function(inputData) { + // make a new copy of the inputData + // so we can change the inputData without messing up the other recognizers + var inputDataClone = assign({}, inputData); + + // is it enabled and allow recognizing? + if (!boolOrFn(this.options.enable, [this, inputDataClone])) { + this.reset(); + this.state = STATE_FAILED; + return; + } + + // reset when we've reached the end + if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) { + this.state = STATE_POSSIBLE; + } + + this.state = this.process(inputDataClone); + + // the recognizer has recognized a gesture + // so trigger an event + if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) { + this.tryEmit(inputDataClone); + } + }, + + /** + * return the state of the recognizer + * the actual recognizing happens in this method + * @virtual + * @param {Object} inputData + * @returns {Const} STATE + */ + process: function(inputData) { }, // jshint ignore:line + + /** + * return the preferred touch-action + * @virtual + * @returns {Array} + */ + getTouchAction: function() { }, + + /** + * called when the gesture isn't allowed to recognize + * like when another is being recognized or it is disabled + * @virtual + */ + reset: function() { } +}; + +/** + * get a usable string, used as event postfix + * @param {Const} state + * @returns {String} state + */ +function stateStr(state) { + if (state & STATE_CANCELLED) { + return 'cancel'; + } else if (state & STATE_ENDED) { + return 'end'; + } else if (state & STATE_CHANGED) { + return 'move'; + } else if (state & STATE_BEGAN) { + return 'start'; + } + return ''; +} + +/** + * direction cons to string + * @param {Const} direction + * @returns {String} + */ +function directionStr(direction) { + if (direction == DIRECTION_DOWN) { + return 'down'; + } else if (direction == DIRECTION_UP) { + return 'up'; + } else if (direction == DIRECTION_LEFT) { + return 'left'; + } else if (direction == DIRECTION_RIGHT) { + return 'right'; + } + return ''; +} + +/** + * get a recognizer by name if it is bound to a manager + * @param {Recognizer|String} otherRecognizer + * @param {Recognizer} recognizer + * @returns {Recognizer} + */ +function getRecognizerByNameIfManager(otherRecognizer, recognizer) { + var manager = recognizer.manager; + if (manager) { + return manager.get(otherRecognizer); + } + return otherRecognizer; +} + +/** + * This recognizer is just used as a base for the simple attribute recognizers. + * @constructor + * @extends Recognizer + */ +function AttrRecognizer() { + Recognizer.apply(this, arguments); +} + +inherit(AttrRecognizer, Recognizer, { + /** + * @namespace + * @memberof AttrRecognizer + */ + defaults: { + /** + * @type {Number} + * @default 1 + */ + pointers: 1 + }, + + /** + * Used to check if it the recognizer receives valid input, like input.distance > 10. + * @memberof AttrRecognizer + * @param {Object} input + * @returns {Boolean} recognized + */ + attrTest: function(input) { + var optionPointers = this.options.pointers; + return optionPointers === 0 || input.pointers.length === optionPointers; + }, + + /** + * Process the input and return the state for the recognizer + * @memberof AttrRecognizer + * @param {Object} input + * @returns {*} State + */ + process: function(input) { + var state = this.state; + var eventType = input.eventType; + + var isRecognized = state & (STATE_BEGAN | STATE_CHANGED); + var isValid = this.attrTest(input); + + // on cancel input and we've recognized before, return STATE_CANCELLED + if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) { + return state | STATE_CANCELLED; + } else if (isRecognized || isValid) { + if (eventType & INPUT_END) { + return state | STATE_ENDED; + } else if (!(state & STATE_BEGAN)) { + return STATE_BEGAN; + } + return state | STATE_CHANGED; + } + return STATE_FAILED; + } +}); + +/** + * Pan + * Recognized when the pointer is down and moved in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ +function PanRecognizer() { + AttrRecognizer.apply(this, arguments); + + this.pX = null; + this.pY = null; +} + +inherit(PanRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PanRecognizer + */ + defaults: { + event: 'pan', + threshold: 10, + pointers: 1, + direction: DIRECTION_ALL + }, + + getTouchAction: function() { + var direction = this.options.direction; + var actions = []; + if (direction & DIRECTION_HORIZONTAL) { + actions.push(TOUCH_ACTION_PAN_Y); + } + if (direction & DIRECTION_VERTICAL) { + actions.push(TOUCH_ACTION_PAN_X); + } + return actions; + }, + + directionTest: function(input) { + var options = this.options; + var hasMoved = true; + var distance = input.distance; + var direction = input.direction; + var x = input.deltaX; + var y = input.deltaY; + + // lock to axis? + if (!(direction & options.direction)) { + if (options.direction & DIRECTION_HORIZONTAL) { + direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + hasMoved = x != this.pX; + distance = Math.abs(input.deltaX); + } else { + direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN; + hasMoved = y != this.pY; + distance = Math.abs(input.deltaY); + } + } + input.direction = direction; + return hasMoved && distance > options.threshold && direction & options.direction; + }, + + attrTest: function(input) { + return AttrRecognizer.prototype.attrTest.call(this, input) && + (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input))); + }, + + emit: function(input) { + + this.pX = input.deltaX; + this.pY = input.deltaY; + + var direction = directionStr(input.direction); + + if (direction) { + input.additionalEvent = this.options.event + direction; + } + this._super.emit.call(this, input); + } +}); + +/** + * Pinch + * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out). + * @constructor + * @extends AttrRecognizer + */ +function PinchRecognizer() { + AttrRecognizer.apply(this, arguments); +} + +inherit(PinchRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'pinch', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN); + }, + + emit: function(input) { + if (input.scale !== 1) { + var inOut = input.scale < 1 ? 'in' : 'out'; + input.additionalEvent = this.options.event + inOut; + } + this._super.emit.call(this, input); + } +}); + +/** + * Press + * Recognized when the pointer is down for x ms without any movement. + * @constructor + * @extends Recognizer + */ +function PressRecognizer() { + Recognizer.apply(this, arguments); + + this._timer = null; + this._input = null; +} + +inherit(PressRecognizer, Recognizer, { + /** + * @namespace + * @memberof PressRecognizer + */ + defaults: { + event: 'press', + pointers: 1, + time: 251, // minimal time of the pointer to be pressed + threshold: 9 // a minimal movement is ok, but keep it low + }, + + getTouchAction: function() { + return [TOUCH_ACTION_AUTO]; + }, + + process: function(input) { + var options = this.options; + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTime = input.deltaTime > options.time; + + this._input = input; + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) { + this.reset(); + } else if (input.eventType & INPUT_START) { + this.reset(); + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.time, this); + } else if (input.eventType & INPUT_END) { + return STATE_RECOGNIZED; + } + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function(input) { + if (this.state !== STATE_RECOGNIZED) { + return; + } + + if (input && (input.eventType & INPUT_END)) { + this.manager.emit(this.options.event + 'up', input); + } else { + this._input.timeStamp = now(); + this.manager.emit(this.options.event, this._input); + } + } +}); + +/** + * Rotate + * Recognized when two or more pointer are moving in a circular motion. + * @constructor + * @extends AttrRecognizer + */ +function RotateRecognizer() { + AttrRecognizer.apply(this, arguments); +} + +inherit(RotateRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof RotateRecognizer + */ + defaults: { + event: 'rotate', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN); + } +}); + +/** + * Swipe + * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ +function SwipeRecognizer() { + AttrRecognizer.apply(this, arguments); +} + +inherit(SwipeRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof SwipeRecognizer + */ + defaults: { + event: 'swipe', + threshold: 10, + velocity: 0.3, + direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL, + pointers: 1 + }, + + getTouchAction: function() { + return PanRecognizer.prototype.getTouchAction.call(this); + }, + + attrTest: function(input) { + var direction = this.options.direction; + var velocity; + + if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) { + velocity = input.overallVelocity; + } else if (direction & DIRECTION_HORIZONTAL) { + velocity = input.overallVelocityX; + } else if (direction & DIRECTION_VERTICAL) { + velocity = input.overallVelocityY; + } + + return this._super.attrTest.call(this, input) && + direction & input.offsetDirection && + input.distance > this.options.threshold && + input.maxPointers == this.options.pointers && + abs(velocity) > this.options.velocity && input.eventType & INPUT_END; + }, + + emit: function(input) { + var direction = directionStr(input.offsetDirection); + if (direction) { + this.manager.emit(this.options.event + direction, input); + } + + this.manager.emit(this.options.event, input); + } +}); + +/** + * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur + * between the given interval and position. The delay option can be used to recognize multi-taps without firing + * a single tap. + * + * The eventData from the emitted event contains the property `tapCount`, which contains the amount of + * multi-taps being recognized. + * @constructor + * @extends Recognizer + */ +function TapRecognizer() { + Recognizer.apply(this, arguments); + + // previous time and center, + // used for tap counting + this.pTime = false; + this.pCenter = false; + + this._timer = null; + this._input = null; + this.count = 0; +} + +inherit(TapRecognizer, Recognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'tap', + pointers: 1, + taps: 1, + interval: 300, // max time between the multi-tap taps + time: 250, // max time of the pointer to be down (like finger on the screen) + threshold: 9, // a minimal movement is ok, but keep it low + posThreshold: 10 // a multi-tap can be a bit off the initial position + }, + + getTouchAction: function() { + return [TOUCH_ACTION_MANIPULATION]; + }, + + process: function(input) { + var options = this.options; + + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTouchTime = input.deltaTime < options.time; + + this.reset(); + + if ((input.eventType & INPUT_START) && (this.count === 0)) { + return this.failTimeout(); + } + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (validMovement && validTouchTime && validPointers) { + if (input.eventType != INPUT_END) { + return this.failTimeout(); + } + + var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true; + var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold; + + this.pTime = input.timeStamp; + this.pCenter = input.center; + + if (!validMultiTap || !validInterval) { + this.count = 1; + } else { + this.count += 1; + } + + this._input = input; + + // if tap count matches we have recognized it, + // else it has begun recognizing... + var tapCount = this.count % options.taps; + if (tapCount === 0) { + // no failing requirements, immediately trigger the tap event + // or wait as long as the multitap interval to trigger + if (!this.hasRequireFailures()) { + return STATE_RECOGNIZED; + } else { + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.interval, this); + return STATE_BEGAN; + } + } + } + return STATE_FAILED; + }, + + failTimeout: function() { + this._timer = setTimeoutContext(function() { + this.state = STATE_FAILED; + }, this.options.interval, this); + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function() { + if (this.state == STATE_RECOGNIZED) { + this._input.tapCount = this.count; + this.manager.emit(this.options.event, this._input); + } + } +}); + +/** + * Simple way to create a manager with a default set of recognizers. + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ +function Hammer(element, options) { + options = options || {}; + options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset); + return new Manager(element, options); +} + +/** + * @const {string} + */ +Hammer.VERSION = '2.0.7'; + +/** + * default settings + * @namespace + */ +Hammer.defaults = { + /** + * set if DOM events are being triggered. + * But this is slower and unused by simple implementations, so disabled by default. + * @type {Boolean} + * @default false + */ + domEvents: false, + + /** + * The value for the touchAction property/fallback. + * When set to `compute` it will magically set the correct value based on the added recognizers. + * @type {String} + * @default compute + */ + touchAction: TOUCH_ACTION_COMPUTE, + + /** + * @type {Boolean} + * @default true + */ + enable: true, + + /** + * EXPERIMENTAL FEATURE -- can be removed/changed + * Change the parent input target element. + * If Null, then it is being set the to main element. + * @type {Null|EventTarget} + * @default null + */ + inputTarget: null, + + /** + * force an input class + * @type {Null|Function} + * @default null + */ + inputClass: null, + + /** + * Default recognizer setup when calling `Hammer()` + * When creating a new Manager these will be skipped. + * @type {Array} + */ + preset: [ + // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...] + [RotateRecognizer, {enable: false}], + [PinchRecognizer, {enable: false}, ['rotate']], + [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}], + [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']], + [TapRecognizer], + [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']], + [PressRecognizer] + ], + + /** + * Some CSS properties can be used to improve the working of Hammer. + * Add them to this method and they will be set when creating a new Manager. + * @namespace + */ + cssProps: { + /** + * Disables text selection to improve the dragging gesture. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userSelect: 'none', + + /** + * Disable the Windows Phone grippers when pressing an element. + * @type {String} + * @default 'none' + */ + touchSelect: 'none', + + /** + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @type {String} + * @default 'none' + */ + touchCallout: 'none', + + /** + * Specifies whether zooming is enabled. Used by IE10> + * @type {String} + * @default 'none' + */ + contentZooming: 'none', + + /** + * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userDrag: 'none', + + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in iOS. This property obeys the alpha value, if specified. + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' + } +}; + +var STOP = 1; +var FORCED_STOP = 2; + +/** + * Manager + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ +function Manager(element, options) { + this.options = assign({}, Hammer.defaults, options || {}); + + this.options.inputTarget = this.options.inputTarget || element; + + this.handlers = {}; + this.session = {}; + this.recognizers = []; + this.oldCssProps = {}; + + this.element = element; + this.input = createInputInstance(this); + this.touchAction = new TouchAction(this, this.options.touchAction); + + toggleCssProps(this, true); + + each(this.options.recognizers, function(item) { + var recognizer = this.add(new (item[0])(item[1])); + item[2] && recognizer.recognizeWith(item[2]); + item[3] && recognizer.requireFailure(item[3]); + }, this); +} + +Manager.prototype = { + /** + * set options + * @param {Object} options + * @returns {Manager} + */ + set: function(options) { + assign(this.options, options); + + // Options that need a little more setup + if (options.touchAction) { + this.touchAction.update(); + } + if (options.inputTarget) { + // Clean up existing event listeners and reinitialize + this.input.destroy(); + this.input.target = options.inputTarget; + this.input.init(); + } + return this; + }, + + /** + * stop recognizing for this session. + * This session will be discarded, when a new [input]start event is fired. + * When forced, the recognizer cycle is stopped immediately. + * @param {Boolean} [force] + */ + stop: function(force) { + this.session.stopped = force ? FORCED_STOP : STOP; + }, + + /** + * run the recognizers! + * called by the inputHandler function on every movement of the pointers (touches) + * it walks through all the recognizers and tries to detect the gesture that is being made + * @param {Object} inputData + */ + recognize: function(inputData) { + var session = this.session; + if (session.stopped) { + return; + } + + // run the touch-action polyfill + this.touchAction.preventDefaults(inputData); + + var recognizer; + var recognizers = this.recognizers; + + // this holds the recognizer that is being recognized. + // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED + // if no recognizer is detecting a thing, it is set to `null` + var curRecognizer = session.curRecognizer; + + // reset when the last recognizer is recognized + // or when we're in a new session + if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) { + curRecognizer = session.curRecognizer = null; + } + + var i = 0; + while (i < recognizers.length) { + recognizer = recognizers[i]; + + // find out if we are allowed try to recognize the input for this one. + // 1. allow if the session is NOT forced stopped (see the .stop() method) + // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one + // that is being recognized. + // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer. + // this can be setup with the `recognizeWith()` method on the recognizer. + if (session.stopped !== FORCED_STOP && ( // 1 + !curRecognizer || recognizer == curRecognizer || // 2 + recognizer.canRecognizeWith(curRecognizer))) { // 3 + recognizer.recognize(inputData); + } else { + recognizer.reset(); + } + + // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the + // current active recognizer. but only if we don't already have an active recognizer + if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) { + curRecognizer = session.curRecognizer = recognizer; + } + i++; + } + }, + + /** + * get a recognizer by its event name. + * @param {Recognizer|String} recognizer + * @returns {Recognizer|Null} + */ + get: function(recognizer) { + if (recognizer instanceof Recognizer) { + return recognizer; + } + + var recognizers = this.recognizers; + for (var i = 0; i < recognizers.length; i++) { + if (recognizers[i].options.event == recognizer) { + return recognizers[i]; + } + } + return null; + }, + + /** + * add a recognizer to the manager + * existing recognizers with the same event name will be removed + * @param {Recognizer} recognizer + * @returns {Recognizer|Manager} + */ + add: function(recognizer) { + if (invokeArrayArg(recognizer, 'add', this)) { + return this; + } + + // remove existing + var existing = this.get(recognizer.options.event); + if (existing) { + this.remove(existing); + } + + this.recognizers.push(recognizer); + recognizer.manager = this; + + this.touchAction.update(); + return recognizer; + }, + + /** + * remove a recognizer by name or instance + * @param {Recognizer|String} recognizer + * @returns {Manager} + */ + remove: function(recognizer) { + if (invokeArrayArg(recognizer, 'remove', this)) { + return this; + } + + recognizer = this.get(recognizer); + + // let's make sure this recognizer exists + if (recognizer) { + var recognizers = this.recognizers; + var index = inArray(recognizers, recognizer); + + if (index !== -1) { + recognizers.splice(index, 1); + this.touchAction.update(); + } + } + + return this; + }, + + /** + * bind event + * @param {String} events + * @param {Function} handler + * @returns {EventEmitter} this + */ + on: function(events, handler) { + if (events === undefined) { + return; + } + if (handler === undefined) { + return; + } + + var handlers = this.handlers; + each(splitStr(events), function(event) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + }); + return this; + }, + + /** + * unbind event, leave emit blank to remove all handlers + * @param {String} events + * @param {Function} [handler] + * @returns {EventEmitter} this + */ + off: function(events, handler) { + if (events === undefined) { + return; + } + + var handlers = this.handlers; + each(splitStr(events), function(event) { + if (!handler) { + delete handlers[event]; + } else { + handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1); + } + }); + return this; + }, + + /** + * emit event to the listeners + * @param {String} event + * @param {Object} data + */ + emit: function(event, data) { + // we also want to trigger dom events + if (this.options.domEvents) { + triggerDomEvent(event, data); + } + + // no handlers, so skip it all + var handlers = this.handlers[event] && this.handlers[event].slice(); + if (!handlers || !handlers.length) { + return; + } + + data.type = event; + data.preventDefault = function() { + data.srcEvent.preventDefault(); + }; + + var i = 0; + while (i < handlers.length) { + handlers[i](data); + i++; + } + }, + + /** + * destroy the manager and unbinds all events + * it doesn't unbind dom events, that is the user own responsibility + */ + destroy: function() { + this.element && toggleCssProps(this, false); + + this.handlers = {}; + this.session = {}; + this.input.destroy(); + this.element = null; + } +}; + +/** + * add/remove the css properties as defined in manager.options.cssProps + * @param {Manager} manager + * @param {Boolean} add + */ +function toggleCssProps(manager, add) { + var element = manager.element; + if (!element.style) { + return; + } + var prop; + each(manager.options.cssProps, function(value, name) { + prop = prefixed(element.style, name); + if (add) { + manager.oldCssProps[prop] = element.style[prop]; + element.style[prop] = value; + } else { + element.style[prop] = manager.oldCssProps[prop] || ''; + } + }); + if (!add) { + manager.oldCssProps = {}; + } +} + +/** + * trigger dom event + * @param {String} event + * @param {Object} data + */ +function triggerDomEvent(event, data) { + var gestureEvent = document.createEvent('Event'); + gestureEvent.initEvent(event, true, true); + gestureEvent.gesture = data; + data.target.dispatchEvent(gestureEvent); +} + +assign(Hammer, { + INPUT_START: INPUT_START, + INPUT_MOVE: INPUT_MOVE, + INPUT_END: INPUT_END, + INPUT_CANCEL: INPUT_CANCEL, + + STATE_POSSIBLE: STATE_POSSIBLE, + STATE_BEGAN: STATE_BEGAN, + STATE_CHANGED: STATE_CHANGED, + STATE_ENDED: STATE_ENDED, + STATE_RECOGNIZED: STATE_RECOGNIZED, + STATE_CANCELLED: STATE_CANCELLED, + STATE_FAILED: STATE_FAILED, + + DIRECTION_NONE: DIRECTION_NONE, + DIRECTION_LEFT: DIRECTION_LEFT, + DIRECTION_RIGHT: DIRECTION_RIGHT, + DIRECTION_UP: DIRECTION_UP, + DIRECTION_DOWN: DIRECTION_DOWN, + DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL, + DIRECTION_VERTICAL: DIRECTION_VERTICAL, + DIRECTION_ALL: DIRECTION_ALL, + + Manager: Manager, + Input: Input, + TouchAction: TouchAction, + + TouchInput: TouchInput, + MouseInput: MouseInput, + PointerEventInput: PointerEventInput, + TouchMouseInput: TouchMouseInput, + SingleTouchInput: SingleTouchInput, + + Recognizer: Recognizer, + AttrRecognizer: AttrRecognizer, + Tap: TapRecognizer, + Pan: PanRecognizer, + Swipe: SwipeRecognizer, + Pinch: PinchRecognizer, + Rotate: RotateRecognizer, + Press: PressRecognizer, + + on: addEventListeners, + off: removeEventListeners, + each: each, + merge: merge, + extend: extend, + assign: assign, + inherit: inherit, + bindFn: bindFn, + prefixed: prefixed +}); + +// this prevents errors when Hammer is loaded in the presence of an AMD +// style loader but by script tag, not by the loader. +var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line +freeGlobal.Hammer = Hammer; + +if (typeof define === 'function' && define.amd) { + define(function() { + return Hammer; + }); +} else if (typeof module != 'undefined' && module.exports) { + module.exports = Hammer; +} else { + window[exportName] = Hammer; +} + +})(window, document, 'Hammer'); + +/***** + * @licstart + * + * The following is the license notice for the part of JavaScript code of this + * page included between the '@jessyinkstart' and the '@jessyinkend' notes. + */ + +/***** ****************************************************************** + * + * Copyright 2008-2013 Hannes Hochreiner + * + * The JavaScript code included between the start note '@jessyinkstart' + * and the end note '@jessyinkend' 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/. + * + * Alternatively, you can redistribute and/or that part of this file + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +/***** + * You can find the complete source code of the JessyInk project at: + * @source http://code.google.com/p/jessyink/ + */ + +/***** + * @licend + * + * The above is the license notice for the part of JavaScript code of this + * page included between the '@jessyinkstart' and the '@jessyinkend' notes. + */ + + + +/***** + * @jessyinkstart + * + * The following code is a derivative work of some parts of the JessyInk + * project. + * @source http://code.google.com/p/jessyink/ + */ + +/** Convenience function to get an element depending on whether it has a + * property with a particular name. + * + * @param node element of the document + * @param name attribute name + * + * @returns Array array containing all the elements of the tree with root + * 'node' that own the property 'name' + */ +function getElementsByProperty( node, name ) +{ + var elements = []; + + if( node.getAttribute( name ) ) + elements.push( node ); + + for( var counter = 0; counter < node.childNodes.length; ++counter ) + { + if( node.childNodes[counter].nodeType == 1 ) + { + var subElements = getElementsByProperty( node.childNodes[counter], name ); + elements = elements.concat( subElements ); + } + } + return elements; +} + +/** Event handler for key press. + * + * @param aEvt the event + */ +function onKeyDown( aEvt ) +{ + if ( !aEvt ) + aEvt = window.event; + + var code = aEvt.keyCode || aEvt.charCode; + + // console.log('===> onKeyDown: ' + code); + + // Handle arrow keys in iOS WebKit (including Mobile Safari) + if (code == 0 && aEvt.key != undefined) { + switch (aEvt.key) { + case 'UIKeyInputLeftArrow': + code = LEFT_KEY; + break; + case 'UIKeyInputUpArrow': + code = UP_KEY; + break; + case 'UIKeyInputRightArrow': + code = RIGHT_KEY; + break; + case 'UIKeyInputDownArrow': + code = DOWN_KEY; + break; + } + + // console.log(' now: ' + code); + } + + if( !processingEffect && keyCodeDictionary[currentMode] && keyCodeDictionary[currentMode][code] ) + { + return keyCodeDictionary[currentMode][code](); + } + else + { + document.onkeypress = onKeyPress; + return null; + } +} +//Set event handler for key down. +document.onkeydown = onKeyDown; + +/** Event handler for key press. + * + * @param aEvt the event + */ +function onKeyPress( aEvt ) +{ + document.onkeypress = null; + + if ( !aEvt ) + aEvt = window.event; + + var str = String.fromCharCode( aEvt.keyCode || aEvt.charCode ); + + if ( !processingEffect && charCodeDictionary[currentMode] && charCodeDictionary[currentMode][str] ) + return charCodeDictionary[currentMode][str](); + + return null; +} + +/** Function to supply the default key code dictionary. + * + * @returns Object default key code dictionary + */ +function getDefaultKeyCodeDictionary() +{ + var keyCodeDict = {}; + + keyCodeDict[SLIDE_MODE] = {}; + keyCodeDict[INDEX_MODE] = {}; + + // slide mode + keyCodeDict[SLIDE_MODE][LEFT_KEY] + = function() { return aSlideShow.rewindEffect(); }; + keyCodeDict[SLIDE_MODE][RIGHT_KEY] + = function() { return dispatchEffects(1); }; + keyCodeDict[SLIDE_MODE][UP_KEY] + = function() { return aSlideShow.rewindEffect(); }; + keyCodeDict[SLIDE_MODE][DOWN_KEY] + = function() { return skipEffects(1); }; + keyCodeDict[SLIDE_MODE][PAGE_UP_KEY] + = function() { return aSlideShow.rewindAllEffects(); }; + keyCodeDict[SLIDE_MODE][PAGE_DOWN_KEY] + = function() { return skipAllEffects(); }; + keyCodeDict[SLIDE_MODE][HOME_KEY] + = function() { return aSlideShow.displaySlide( 0, true ); }; + keyCodeDict[SLIDE_MODE][END_KEY] + = function() { return aSlideShow.displaySlide( theMetaDoc.nNumberOfSlides - 1, true ); }; + keyCodeDict[SLIDE_MODE][SPACE_KEY] + = function() { return dispatchEffects(1); }; + // The ESC key can't actually be handled on iOS, it seems to be hardcoded to work like the home button? But try anyway. + keyCodeDict[SLIDE_MODE][ESCAPE_KEY] + = function() { return aSlideShow.exitSlideShowInApp(); }; + keyCodeDict[SLIDE_MODE][Q_KEY] + = function() { return aSlideShow.exitSlideShowInApp(); }; + + // index mode + keyCodeDict[INDEX_MODE][LEFT_KEY] + = function() { return indexSetPageSlide( theSlideIndexPage.selectedSlideIndex - 1 ); }; + keyCodeDict[INDEX_MODE][RIGHT_KEY] + = function() { return indexSetPageSlide( theSlideIndexPage.selectedSlideIndex + 1 ); }; + keyCodeDict[INDEX_MODE][UP_KEY] + = function() { return indexSetPageSlide( theSlideIndexPage.selectedSlideIndex - theSlideIndexPage.indexColumns ); }; + keyCodeDict[INDEX_MODE][DOWN_KEY] + = function() { return indexSetPageSlide( theSlideIndexPage.selectedSlideIndex + theSlideIndexPage.indexColumns ); }; + keyCodeDict[INDEX_MODE][PAGE_UP_KEY] + = function() { return indexSetPageSlide( theSlideIndexPage.selectedSlideIndex - theSlideIndexPage.getTotalThumbnails() ); }; + keyCodeDict[INDEX_MODE][PAGE_DOWN_KEY] + = function() { return indexSetPageSlide( theSlideIndexPage.selectedSlideIndex + theSlideIndexPage.getTotalThumbnails() ); }; + keyCodeDict[INDEX_MODE][HOME_KEY] + = function() { return indexSetPageSlide( 0 ); }; + keyCodeDict[INDEX_MODE][END_KEY] + = function() { return indexSetPageSlide( theMetaDoc.nNumberOfSlides - 1 ); }; + keyCodeDict[INDEX_MODE][ENTER_KEY] + = function() { return toggleSlideIndex(); }; + keyCodeDict[INDEX_MODE][SPACE_KEY] + = function() { return toggleSlideIndex(); }; + keyCodeDict[INDEX_MODE][ESCAPE_KEY] + = function() { return abandonIndexMode(); }; + + return keyCodeDict; +} + +/** Function to supply the default char code dictionary. + * + * @returns Object char code dictionary + */ +function getDefaultCharCodeDictionary() +{ + var charCodeDict = {}; + + charCodeDict[SLIDE_MODE] = {}; + charCodeDict[INDEX_MODE] = {}; + + // slide mode + charCodeDict[SLIDE_MODE]['i'] + = function () { return toggleSlideIndex(); }; + + // index mode + charCodeDict[INDEX_MODE]['i'] + = function () { return toggleSlideIndex(); }; + charCodeDict[INDEX_MODE]['-'] + = function () { return theSlideIndexPage.decreaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]['='] + = function () { return theSlideIndexPage.increaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]['+'] + = function () { return theSlideIndexPage.increaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]['0'] + = function () { return theSlideIndexPage.resetNumberOfColumns(); }; + + return charCodeDict; +} + + +function slideOnMouseUp( aEvt ) +{ + if (!aEvt) + aEvt = window.event; + + var nOffset = 0; + + if( aEvt.button == 0 ) + nOffset = 1; + else if( aEvt.button == 2 ) + nOffset = -1; + + if( 0 != nOffset ) + dispatchEffects( nOffset ); + return true; // the click has been handled +} + +document.handleClick = slideOnMouseUp; + + +/** Event handler for mouse wheel events in slide mode. + * based on http://adomas.org/javascript-mouse-wheel/ + * + * @param aEvt the event + */ +function slideOnMouseWheel(aEvt) +{ + var delta = 0; + + if (!aEvt) + aEvt = window.event; + + if (aEvt.wheelDelta) + { // IE Opera + delta = aEvt.wheelDelta/120; + } + else if (aEvt.detail) + { // MOZ + delta = -aEvt.detail/3; + } + + if (delta > 0) + skipEffects(-1); + else if (delta < 0) + skipEffects(1); + + if (aEvt.preventDefault) + aEvt.preventDefault(); + + aEvt.returnValue = false; +} + +//Mozilla +if( window.addEventListener ) +{ + window.addEventListener( 'DOMMouseScroll', function( aEvt ) { return mouseHandlerDispatch( aEvt, MOUSE_WHEEL ); }, false ); +} + +//Opera Safari OK - may not work in IE +window.onmousewheel + = function( aEvt ) { return mouseHandlerDispatch( aEvt, MOUSE_WHEEL ); }; + +/** Function to handle all mouse events. + * + * @param aEvt event + * @param anAction type of event (e.g. mouse up, mouse wheel) + */ +function mouseHandlerDispatch( aEvt, anAction ) +{ + if( !aEvt ) + aEvt = window.event; + + var retVal = true; + + if ( mouseHandlerDictionary[currentMode] && mouseHandlerDictionary[currentMode][anAction] ) + { + var subRetVal = mouseHandlerDictionary[currentMode][anAction]( aEvt ); + + if( subRetVal != null && subRetVal != undefined ) + retVal = subRetVal; + } + + if( aEvt.preventDefault && !retVal ) + aEvt.preventDefault(); + + aEvt.returnValue = retVal; + + return retVal; +} + +//Set mouse event handler. +document.onmouseup = function( aEvt ) { return mouseHandlerDispatch( aEvt, MOUSE_UP ); }; + + +/** mouseClickHelper + * + * @return {Object} + * a mouse click handler + */ +function mouseClickHelper( aEvt ) +{ + // In case text is selected we stay on the current slide. + // Anyway if we are dealing with Firefox there is an issue: + // Firefox supports a naive way of selecting svg text, if you click + // on text the current selection is set to the whole text fragment + // wrapped by the related element. + // That means until you click on text you never move to the next slide. + // In order to avoid this case we do not test the status of current + // selection, when the presentation is running on a mozilla browser. + if( !Detect.isMozilla ) + { + var aWindowObject = document.defaultView; + if( aWindowObject ) + { + var aTextSelection = aWindowObject.getSelection(); + var sSelectedText = aTextSelection.toString(); + if( sSelectedText ) + { + DBGLOG( 'text selection: ' + sSelectedText ); + if( sLastSelectedText !== sSelectedText ) + { + bTextHasBeenSelected = true; + sLastSelectedText = sSelectedText; + } + else + { + bTextHasBeenSelected = false; + } + return null; + } + else if( bTextHasBeenSelected ) + { + bTextHasBeenSelected = false; + sLastSelectedText = ''; + return null; + } + } + else + { + log( 'error: HyperlinkElement.handleClick: invalid window object.' ); + } + } + + var aSlideAnimationsHandler = theMetaDoc.aMetaSlideSet[nCurSlide].aSlideAnimationsHandler; + if( aSlideAnimationsHandler ) + { + var aCurrentEventMultiplexer = aSlideAnimationsHandler.aEventMultiplexer; + if( aCurrentEventMultiplexer ) + { + if( aCurrentEventMultiplexer.hasRegisteredMouseClickHandlers() ) + { + return aCurrentEventMultiplexer.notifyMouseClick( aEvt ); + } + } + } + return slideOnMouseUp( aEvt ); +} + + +/** Function to supply the default mouse handler dictionary. + * + * @returns Object default mouse handler dictionary + */ +function getDefaultMouseHandlerDictionary() +{ + var mouseHandlerDict = {}; + + mouseHandlerDict[SLIDE_MODE] = {}; + mouseHandlerDict[INDEX_MODE] = {}; + + // slide mode + mouseHandlerDict[SLIDE_MODE][MOUSE_UP] + = mouseClickHelper; + + mouseHandlerDict[SLIDE_MODE][MOUSE_WHEEL] + = function( aEvt ) { return slideOnMouseWheel( aEvt ); }; + + // index mode + mouseHandlerDict[INDEX_MODE][MOUSE_UP] + = function( ) { return toggleSlideIndex(); }; + + return mouseHandlerDict; +} + +/** Function to set the page and active slide in index view. + * + * @param nIndex index of the active slide + * + * NOTE: To force a redraw, + * set INDEX_OFFSET to -1 before calling indexSetPageSlide(). + * + * This is necessary for zooming (otherwise the index might not + * get redrawn) and when switching to index mode. + * + * INDEX_OFFSET = -1 + * indexSetPageSlide(activeSlide); + */ +function indexSetPageSlide( nIndex ) +{ + var aMetaSlideSet = theMetaDoc.aMetaSlideSet; + nIndex = getSafeIndex( nIndex, 0, aMetaSlideSet.length - 1 ); + + //calculate the offset + var nSelectedThumbnailIndex = nIndex % theSlideIndexPage.getTotalThumbnails(); + var offset = nIndex - nSelectedThumbnailIndex; + + if( offset < 0 ) + offset = 0; + + //if different from kept offset, then record and change the page + if( offset != INDEX_OFFSET ) + { + INDEX_OFFSET = offset; + displayIndex( INDEX_OFFSET ); + } + + //set the selected thumbnail and the current slide + theSlideIndexPage.setSelection( nSelectedThumbnailIndex ); +} + + +/***** + * @jessyinkend + * + * The above code is a derivative work of some parts of the JessyInk project. + * @source http://code.google.com/p/jessyink/ + */ + + + + + +/***** + * @licstart + * + * The following is the license notice for the part of JavaScript code of this + * page included between the '@dojostart' and the '@dojoend' notes. + */ + +/***** ********************************************************************** + * + * The 'New' BSD License: + * ********************** + * Copyright (c) 2005-2012, The Dojo Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Dojo Foundation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + + +/***** + * @licend + * + * The above is the license notice for the part of JavaScript code of this + * page included between the '@dojostart' and the '@dojoend' notes. + */ + + + +/***** + * @dojostart + * + * The following code is a derivative work of some part of the dojox.gfx library. + * @source http://svn.dojotoolkit.org/src/dojox/trunk/_base/sniff.js + */ + +function has( name ) +{ + return has.cache[name]; +} + +has.cache = {}; + +has.add = function( name, test ) +{ + has.cache[name] = test; +}; + +function configureDetectionTools() +{ + if( !navigator ) + { + log( 'error: configureDetectionTools: configuration failed' ); + return null; + } + + var n = navigator, + dua = n.userAgent, + dav = n.appVersion, + tv = parseFloat(dav); + + has.add('air', dua.indexOf('AdobeAIR') >= 0); + has.add('khtml', dav.indexOf('Konqueror') >= 0 ? tv : undefined); + has.add('webkit', parseFloat(dua.split('WebKit/')[1]) || undefined); + has.add('chrome', parseFloat(dua.split('Chrome/')[1]) || undefined); + has.add('safari', dav.indexOf('Safari')>=0 && !has('chrome') ? parseFloat(dav.split('Version/')[1]) : undefined); + has.add('mac', dav.indexOf('Macintosh') >= 0); + has.add('quirks', document.compatMode == 'BackCompat'); + has.add('ios', /iPhone|iPod|iPad/.test(dua)); + has.add('android', parseFloat(dua.split('Android ')[1]) || undefined); + + if(!has('webkit')){ + // Opera + if(dua.indexOf('Opera') >= 0){ + // see http://dev.opera.com/articles/view/opera-ua-string-changes and http://www.useragentstring.com/pages/Opera/ + // 9.8 has both styles; <9.8, 9.9 only old style + has.add('opera', tv >= 9.8 ? parseFloat(dua.split('Version/')[1]) || tv : tv); + } + + // Mozilla and firefox + if(dua.indexOf('Gecko') >= 0 && !has('khtml') && !has('webkit')){ + has.add('mozilla', tv); + } + if(has('mozilla')){ + //We really need to get away from this. Consider a sane isGecko approach for the future. + has.add('ff', parseFloat(dua.split('Firefox/')[1] || dua.split('Minefield/')[1]) || undefined); + } + + // IE + if(document.all && !has('opera')){ + var isIE = parseFloat(dav.split('MSIE ')[1]) || undefined; + + //In cases where the page has an HTTP header or META tag with + //X-UA-Compatible, then it is in emulation mode. + //Make sure isIE reflects the desired version. + //document.documentMode of 5 means quirks mode. + //Only switch the value if documentMode's major version + //is different from isIE major version. + var mode = document.documentMode; + if(mode && mode != 5 && Math.floor(isIE) != mode){ + isIE = mode; + } + + has.add('ie', isIE); + } + + // Wii + has.add('wii', typeof opera != 'undefined' && opera.wiiremote); + } + + var detect = + { + // isFF: Number|undefined + // Version as a Number if client is FireFox. undefined otherwise. Corresponds to + // major detected FireFox version (1.5, 2, 3, etc.) + isFF: has('ff'), + + // isIE: Number|undefined + // Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to + // major detected IE version (6, 7, 8, etc.) + isIE: has('ie'), + + // isKhtml: Number|undefined + // Version as a Number if client is a KHTML browser. undefined otherwise. Corresponds to major + // detected version. + isKhtml: has('khtml'), + + // isWebKit: Number|undefined + // Version as a Number if client is a WebKit-derived browser (Konqueror, + // Safari, Chrome, etc.). undefined otherwise. + isWebKit: has('webkit'), + + // isMozilla: Number|undefined + // Version as a Number if client is a Mozilla-based browser (Firefox, + // SeaMonkey). undefined otherwise. Corresponds to major detected version. + isMozilla: has('mozilla'), + // isMoz: Number|undefined + // Version as a Number if client is a Mozilla-based browser (Firefox, + // SeaMonkey). undefined otherwise. Corresponds to major detected version. + isMoz: has('mozilla'), + + // isOpera: Number|undefined + // Version as a Number if client is Opera. undefined otherwise. Corresponds to + // major detected version. + isOpera: has('opera'), + + // isSafari: Number|undefined + // Version as a Number if client is Safari or iPhone. undefined otherwise. + isSafari: has('safari'), + + // isChrome: Number|undefined + // Version as a Number if client is Chrome browser. undefined otherwise. + isChrome: has('chrome'), + + // isMac: Boolean + // True if the client runs on Mac + isMac: has('mac'), + + // isIos: Boolean + // True if client is iPhone, iPod, or iPad + isIos: has('ios'), + + // isAndroid: Number|undefined + // Version as a Number if client is android browser. undefined otherwise. + isAndroid: has('android'), + + // isWii: Boolean + // True if client is Wii + isWii: has('wii'), + + // isQuirks: Boolean + // Page is in quirks mode. + isQuirks: has('quirks'), + + // isAir: Boolean + // True if client is Adobe Air + isAir: has('air') + }; + return detect; +} + +/***** + * @dojoend + * + * The above code is a derivative work of some part of the dojox.gfx library. + * @source http://svn.dojotoolkit.org/src/dojox/trunk/_base/sniff.js + */ + +/***** + * @licstart + * + * The following is the license notice for the part of JavaScript code of this + * file included between the '@svgpathstart' and the '@svgpathend' notes. + */ + +/***** ********************************************************************** + * + * Copyright 2015 The Chromium Authors. All rights reserved. + * + * The Chromium Authors can be found at + * http://src.chromium.org/svn/trunk/src/AUTHORS + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/***** + * @licend + * + * The above is the license notice for the part of JavaScript code of this + * file included between the '@svgpathstart' and the '@svgpathend' notes. + */ + + +/***** + * @svgpathstart + * + * The following code is a derivative work of some part of the SVGPathSeg API. + * + * This API is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from + * SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec + * changes which were implemented in Firefox 43 and Chrome 46. + * + * @source https://github.com/progers/pathseg + */ + +(function() { 'use strict'; + if (!('SVGPathSeg' in window)) { + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg + window.SVGPathSeg = function(type, typeAsLetter, owningPathSegList) { + this.pathSegType = type; + this.pathSegTypeAsLetter = typeAsLetter; + this._owningPathSegList = owningPathSegList; + } + + window.SVGPathSeg.prototype.classname = 'SVGPathSeg'; + + window.SVGPathSeg.PATHSEG_UNKNOWN = 0; + window.SVGPathSeg.PATHSEG_CLOSEPATH = 1; + window.SVGPathSeg.PATHSEG_MOVETO_ABS = 2; + window.SVGPathSeg.PATHSEG_MOVETO_REL = 3; + window.SVGPathSeg.PATHSEG_LINETO_ABS = 4; + window.SVGPathSeg.PATHSEG_LINETO_REL = 5; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9; + window.SVGPathSeg.PATHSEG_ARC_ABS = 10; + window.SVGPathSeg.PATHSEG_ARC_REL = 11; + window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12; + window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13; + window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14; + window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16; + window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18; + window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; + + // Notify owning PathSegList on any changes so they can be synchronized back to the path element. + window.SVGPathSeg.prototype._segmentChanged = function() { + if (this._owningPathSegList) + this._owningPathSegList.segmentChanged(this); + } + + window.SVGPathSegClosePath = function(owningPathSegList) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CLOSEPATH, 'z', owningPathSegList); + } + window.SVGPathSegClosePath.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegClosePath.prototype.toString = function() { return '[object SVGPathSegClosePath]'; } + window.SVGPathSegClosePath.prototype._asPathString = function() { return this.pathSegTypeAsLetter; } + window.SVGPathSegClosePath.prototype.clone = function() { return new window.SVGPathSegClosePath(undefined); } + + window.SVGPathSegMovetoAbs = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_ABS, 'M', owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegMovetoAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegMovetoAbs.prototype.toString = function() { return '[object SVGPathSegMovetoAbs]'; } + window.SVGPathSegMovetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegMovetoAbs.prototype.clone = function() { return new window.SVGPathSegMovetoAbs(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegMovetoRel = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_REL, 'm', owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegMovetoRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegMovetoRel.prototype.toString = function() { return '[object SVGPathSegMovetoRel]'; } + window.SVGPathSegMovetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegMovetoRel.prototype.clone = function() { return new window.SVGPathSegMovetoRel(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegMovetoRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegMovetoRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoAbs = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_ABS, 'L', owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegLinetoAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoAbs.prototype.toString = function() { return '[object SVGPathSegLinetoAbs]'; } + window.SVGPathSegLinetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegLinetoAbs.prototype.clone = function() { return new window.SVGPathSegLinetoAbs(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoRel = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_REL, 'l', owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegLinetoRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoRel.prototype.toString = function() { return '[object SVGPathSegLinetoRel]'; } + window.SVGPathSegLinetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegLinetoRel.prototype.clone = function() { return new window.SVGPathSegLinetoRel(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegLinetoRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegLinetoRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicAbs = function(owningPathSegList, x, y, x1, y1, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, 'C', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicAbs.prototype.toString = function() { return '[object SVGPathSegCurvetoCubicAbs]'; } + window.SVGPathSegCurvetoCubicAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoCubicAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, 'x1', { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, 'y1', { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, 'x2', { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, 'y2', { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicRel = function(owningPathSegList, x, y, x1, y1, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, 'c', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicRel.prototype.toString = function() { return '[object SVGPathSegCurvetoCubicRel]'; } + window.SVGPathSegCurvetoCubicRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoCubicRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, 'x1', { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, 'y1', { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, 'x2', { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, 'y2', { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticAbs = function(owningPathSegList, x, y, x1, y1) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, 'Q', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + } + window.SVGPathSegCurvetoQuadraticAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticAbs.prototype.toString = function() { return '[object SVGPathSegCurvetoQuadraticAbs]'; } + window.SVGPathSegCurvetoQuadraticAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoQuadraticAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, 'x1', { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, 'y1', { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticRel = function(owningPathSegList, x, y, x1, y1) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, 'q', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + } + window.SVGPathSegCurvetoQuadraticRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticRel.prototype.toString = function() { return '[object SVGPathSegCurvetoQuadraticRel]'; } + window.SVGPathSegCurvetoQuadraticRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoQuadraticRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, 'x1', { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, 'y1', { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegArcAbs = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_ABS, 'A', owningPathSegList); + this._x = x; + this._y = y; + this._r1 = r1; + this._r2 = r2; + this._angle = angle; + this._largeArcFlag = largeArcFlag; + this._sweepFlag = sweepFlag; + } + window.SVGPathSegArcAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegArcAbs.prototype.toString = function() { return '[object SVGPathSegArcAbs]'; } + window.SVGPathSegArcAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegArcAbs.prototype.clone = function() { return new window.SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); } + Object.defineProperty(window.SVGPathSegArcAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, 'r1', { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, 'r2', { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, 'angle', { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, 'largeArcFlag', { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcAbs.prototype, 'sweepFlag', { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegArcRel = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_REL, 'a', owningPathSegList); + this._x = x; + this._y = y; + this._r1 = r1; + this._r2 = r2; + this._angle = angle; + this._largeArcFlag = largeArcFlag; + this._sweepFlag = sweepFlag; + } + window.SVGPathSegArcRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegArcRel.prototype.toString = function() { return '[object SVGPathSegArcRel]'; } + window.SVGPathSegArcRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegArcRel.prototype.clone = function() { return new window.SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); } + Object.defineProperty(window.SVGPathSegArcRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, 'r1', { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, 'r2', { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, 'angle', { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, 'largeArcFlag', { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegArcRel.prototype, 'sweepFlag', { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoHorizontalAbs = function(owningPathSegList, x) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, 'H', owningPathSegList); + this._x = x; + } + window.SVGPathSegLinetoHorizontalAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoHorizontalAbs.prototype.toString = function() { return '[object SVGPathSegLinetoHorizontalAbs]'; } + window.SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x; } + window.SVGPathSegLinetoHorizontalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalAbs(undefined, this._x); } + Object.defineProperty(window.SVGPathSegLinetoHorizontalAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoHorizontalRel = function(owningPathSegList, x) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, 'h', owningPathSegList); + this._x = x; + } + window.SVGPathSegLinetoHorizontalRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoHorizontalRel.prototype.toString = function() { return '[object SVGPathSegLinetoHorizontalRel]'; } + window.SVGPathSegLinetoHorizontalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x; } + window.SVGPathSegLinetoHorizontalRel.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalRel(undefined, this._x); } + Object.defineProperty(window.SVGPathSegLinetoHorizontalRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoVerticalAbs = function(owningPathSegList, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, 'V', owningPathSegList); + this._y = y; + } + window.SVGPathSegLinetoVerticalAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoVerticalAbs.prototype.toString = function() { return '[object SVGPathSegLinetoVerticalAbs]'; } + window.SVGPathSegLinetoVerticalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._y; } + window.SVGPathSegLinetoVerticalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalAbs(undefined, this._y); } + Object.defineProperty(window.SVGPathSegLinetoVerticalAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegLinetoVerticalRel = function(owningPathSegList, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, 'v', owningPathSegList); + this._y = y; + } + window.SVGPathSegLinetoVerticalRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegLinetoVerticalRel.prototype.toString = function() { return '[object SVGPathSegLinetoVerticalRel]'; } + window.SVGPathSegLinetoVerticalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._y; } + window.SVGPathSegLinetoVerticalRel.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalRel(undefined, this._y); } + Object.defineProperty(window.SVGPathSegLinetoVerticalRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicSmoothAbs = function(owningPathSegList, x, y, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, 'S', owningPathSegList); + this._x = x; + this._y = y; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicSmoothAbs.prototype.toString = function() { return '[object SVGPathSegCurvetoCubicSmoothAbs]'; } + window.SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoCubicSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, 'x2', { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, 'y2', { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoCubicSmoothRel = function(owningPathSegList, x, y, x2, y2) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, 's', owningPathSegList); + this._x = x; + this._y = y; + this._x2 = x2; + this._y2 = y2; + } + window.SVGPathSegCurvetoCubicSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoCubicSmoothRel.prototype.toString = function() { return '[object SVGPathSegCurvetoCubicSmoothRel]'; } + window.SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoCubicSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); } + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, 'x2', { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, 'y2', { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticSmoothAbs = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, 'T', owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString = function() { return '[object SVGPathSegCurvetoQuadraticSmoothAbs]'; } + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + window.SVGPathSegCurvetoQuadraticSmoothRel = function(owningPathSegList, x, y) { + window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, 't', owningPathSegList); + this._x = x; + this._y = y; + } + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype); + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString = function() { return '[object SVGPathSegCurvetoQuadraticSmoothRel]'; } + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; } + window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); } + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, 'x', { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); + Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, 'y', { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); + + // Add createSVGPathSeg* functions to window.SVGPathElement. + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-Interfacewindow.SVGPathElement. + window.SVGPathElement.prototype.createSVGPathSegClosePath = function() { return new window.SVGPathSegClosePath(undefined); } + window.SVGPathElement.prototype.createSVGPathSegMovetoAbs = function(x, y) { return new window.SVGPathSegMovetoAbs(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegMovetoRel = function(x, y) { return new window.SVGPathSegMovetoRel(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegLinetoAbs = function(x, y) { return new window.SVGPathSegLinetoAbs(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegLinetoRel = function(x, y) { return new window.SVGPathSegLinetoRel(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); } + window.SVGPathElement.prototype.createSVGPathSegArcAbs = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); } + window.SVGPathElement.prototype.createSVGPathSegArcRel = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); } + window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function(x) { return new window.SVGPathSegLinetoHorizontalAbs(undefined, x); } + window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function(x) { return new window.SVGPathSegLinetoHorizontalRel(undefined, x); } + window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function(y) { return new window.SVGPathSegLinetoVerticalAbs(undefined, y); } + window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function(y) { return new window.SVGPathSegLinetoVerticalRel(undefined, y); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); } + window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); } + + if (!('getPathSegAtLength' in window.SVGPathElement.prototype)) { + // Add getPathSegAtLength to SVGPathElement. + // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-__svg__SVGPathElement__getPathSegAtLength + // This polyfill requires SVGPathElement.getTotalLength to implement the distance-along-a-path algorithm. + window.SVGPathElement.prototype.getPathSegAtLength = function(distance) { + if (distance === undefined || !isFinite(distance)) + throw 'Invalid arguments.'; + + var measurementElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + measurementElement.setAttribute('d', this.getAttribute('d')); + var lastPathSegment = measurementElement.pathSegList.numberOfItems - 1; + + // If the path is empty, return 0. + if (lastPathSegment <= 0) + return 0; + + do { + measurementElement.pathSegList.removeItem(lastPathSegment); + if (distance > measurementElement.getTotalLength()) + break; + lastPathSegment--; + } while (lastPathSegment > 0); + return lastPathSegment; + } + } + } + + // Checking for SVGPathSegList in window checks for the case of an implementation without the + // SVGPathSegList API. + // The second check for appendItem is specific to Firefox 59+ which removed only parts of the + // SVGPathSegList API (e.g., appendItem). In this case we need to re-implement the entire API + // so the polyfill data (i.e., _list) is used throughout. + if (!('SVGPathSegList' in window) || !('appendItem' in window.SVGPathSegList.prototype)) { + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList + window.SVGPathSegList = function(pathElement) { + this._pathElement = pathElement; + this._list = this._parsePath(this._pathElement.getAttribute('d')); + + // Use a MutationObserver to catch changes to the path's 'd' attribute. + this._mutationObserverConfig = { 'attributes': true, 'attributeFilter': ['d'] }; + this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this)); + this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); + } + + window.SVGPathSegList.prototype.classname = 'SVGPathSegList'; + + Object.defineProperty(window.SVGPathSegList.prototype, 'numberOfItems', { + get: function() { + this._checkPathSynchronizedToList(); + return this._list.length; + }, + enumerable: true + }); + + // The length property was not specified but was in Firefox 58. + Object.defineProperty(window.SVGPathSegList.prototype, 'length', { + get: function() { + this._checkPathSynchronizedToList(); + return this._list.length; + }, + enumerable: true + }); + + // Add the pathSegList accessors to window.SVGPathElement. + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData + Object.defineProperty(window.SVGPathElement.prototype, 'pathSegList', { + get: function() { + if (!this._pathSegList) + this._pathSegList = new window.SVGPathSegList(this); + return this._pathSegList; + }, + enumerable: true + }); + // FIXME: The following are not implemented and simply return window.SVGPathElement.pathSegList. + Object.defineProperty(window.SVGPathElement.prototype, 'normalizedPathSegList', { get: function() { return this.pathSegList; }, enumerable: true }); + Object.defineProperty(window.SVGPathElement.prototype, 'animatedPathSegList', { get: function() { return this.pathSegList; }, enumerable: true }); + Object.defineProperty(window.SVGPathElement.prototype, 'animatedNormalizedPathSegList', { get: function() { return this.pathSegList; }, enumerable: true }); + + // Process any pending mutations to the path element and update the list as needed. + // This should be the first call of all public functions and is needed because + // MutationObservers are not synchronous so we can have pending asynchronous mutations. + window.SVGPathSegList.prototype._checkPathSynchronizedToList = function() { + this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords()); + } + + window.SVGPathSegList.prototype._updateListFromPathMutations = function(mutationRecords) { + if (!this._pathElement) + return; + var hasPathMutations = false; + mutationRecords.forEach(function(record) { + if (record.attributeName == 'd') + hasPathMutations = true; + }); + if (hasPathMutations) + this._list = this._parsePath(this._pathElement.getAttribute('d')); + } + + // Serialize the list and update the path's 'd' attribute. + window.SVGPathSegList.prototype._writeListToPath = function() { + this._pathElementMutationObserver.disconnect(); + this._pathElement.setAttribute('d', window.SVGPathSegList._pathSegArrayAsString(this._list)); + this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); + } + + // When a path segment changes the list needs to be synchronized back to the path element. + window.SVGPathSegList.prototype.segmentChanged = function(pathSeg) { + this._writeListToPath(); + } + + window.SVGPathSegList.prototype.clear = function() { + this._checkPathSynchronizedToList(); + + this._list.forEach(function(pathSeg) { + pathSeg._owningPathSegList = null; + }); + this._list = []; + this._writeListToPath(); + } + + window.SVGPathSegList.prototype.initialize = function(newItem) { + this._checkPathSynchronizedToList(); + + this._list = [newItem]; + newItem._owningPathSegList = this; + this._writeListToPath(); + return newItem; + } + + window.SVGPathSegList.prototype._checkValidIndex = function(index) { + if (isNaN(index) || index < 0 || index >= this.numberOfItems) + throw 'INDEX_SIZE_ERR'; + } + + window.SVGPathSegList.prototype.getItem = function(index) { + this._checkPathSynchronizedToList(); + + this._checkValidIndex(index); + return this._list[index]; + } + + window.SVGPathSegList.prototype.insertItemBefore = function(newItem, index) { + this._checkPathSynchronizedToList(); + + // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list. + if (index > this.numberOfItems) + index = this.numberOfItems; + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + this._list.splice(index, 0, newItem); + newItem._owningPathSegList = this; + this._writeListToPath(); + return newItem; + } + + window.SVGPathSegList.prototype.replaceItem = function(newItem, index) { + this._checkPathSynchronizedToList(); + + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + this._checkValidIndex(index); + this._list[index] = newItem; + newItem._owningPathSegList = this; + this._writeListToPath(); + return newItem; + } + + window.SVGPathSegList.prototype.removeItem = function(index) { + this._checkPathSynchronizedToList(); + + this._checkValidIndex(index); + var item = this._list[index]; + this._list.splice(index, 1); + this._writeListToPath(); + return item; + } + + window.SVGPathSegList.prototype.appendItem = function(newItem) { + this._checkPathSynchronizedToList(); + + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + this._list.push(newItem); + newItem._owningPathSegList = this; + // TODO: Optimize this to just append to the existing attribute. + this._writeListToPath(); + return newItem; + }; + + window.SVGPathSegList.prototype.matrixTransform = function(aSVGMatrix) { + this._checkPathSynchronizedToList(); + + var nLength = this._list.length; + for( var i = 0; i < nLength; ++i ) + { + var nX; + var aPathSeg = this._list[i]; + switch( aPathSeg.pathSegTypeAsLetter ) + { + case 'C': + nX = aPathSeg._x2; + aPathSeg._x2 = aSVGMatrix.a * nX + aSVGMatrix.c * aPathSeg._y2 + aSVGMatrix.e; + aPathSeg._y2 = aSVGMatrix.b * nX + aSVGMatrix.d * aPathSeg._y2 + aSVGMatrix.f; + // fall through intended + case 'Q': + nX = aPathSeg._x1; + aPathSeg._x1 = aSVGMatrix.a * nX + aSVGMatrix.c * aPathSeg._y1 + aSVGMatrix.e; + aPathSeg._y1 = aSVGMatrix.b * nX + aSVGMatrix.d * aPathSeg._y1 + aSVGMatrix.f; + // fall through intended + case 'M': + case 'L': + nX = aPathSeg._x; + aPathSeg._x = aSVGMatrix.a * nX + aSVGMatrix.c * aPathSeg._y + aSVGMatrix.e; + aPathSeg._y = aSVGMatrix.b * nX + aSVGMatrix.d * aPathSeg._y + aSVGMatrix.f; + break; + default: + log( 'SVGPathSeg.matrixTransform: unexpected path segment type: ' + + aPathSeg.pathSegTypeAsLetter ); + } + } + + this._writeListToPath(); + }; + + window.SVGPathSegList.prototype.changeOrientation = function() { + this._checkPathSynchronizedToList(); + + var aPathSegList = this._list; + var nLength = aPathSegList.length; + if( nLength == 0 ) return; + + var nCurrentX = 0; + var nCurrentY = 0; + + var aPathSeg = aPathSegList[0]; + if( aPathSeg.pathSegTypeAsLetter == 'M' ) + { + nCurrentX = aPathSeg.x; + nCurrentY = aPathSeg.y; + aPathSegList.shift(); + --nLength; + } + + var i; + for( i = 0; i < nLength; ++i ) + { + aPathSeg = aPathSegList[i]; + switch( aPathSeg.pathSegTypeAsLetter ) + { + case 'C': + var nX = aPathSeg._x1; + aPathSeg._x1 = aPathSeg._x2; + aPathSeg._x2 = nX; + var nY = aPathSeg._y1; + aPathSeg._y1 = aPathSeg._y2; + aPathSeg._y2 = nY; + // fall through intended + case 'M': + case 'L': + case 'Q': + var aPoint = { x: aPathSeg._x, y: aPathSeg._y }; + aPathSeg._x = nCurrentX; + aPathSeg._y = nCurrentY; + nCurrentX = aPoint.x; + nCurrentY = aPoint.y; + break; + default: + log( 'SVGPathSegList.changeOrientation: unexpected path segment type: ' + + aPathSeg.pathSegTypeAsLetter ); + } + + } + + aPathSegList.reverse(); + + var aMovePathSeg = new window.SVGPathSegMovetoAbs( this, nCurrentX, nCurrentY ); + aPathSegList.unshift( aMovePathSeg ); + + this._writeListToPath(); + }; + + window.SVGPathSegList._pathSegArrayAsString = function(pathSegArray) { + var string = ''; + var first = true; + pathSegArray.forEach(function(pathSeg) { + if (first) { + first = false; + string += pathSeg._asPathString(); + } else { + string += ' ' + pathSeg._asPathString(); + } + }); + return string; + } + + // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp. + window.SVGPathSegList.prototype._parsePath = function(string) { + if (!string || string.length == 0) + return []; + + var owningPathSegList = this; + + var Builder = function() { + this.pathSegList = []; + } + + Builder.prototype.appendSegment = function(pathSeg) { + this.pathSegList.push(pathSeg); + } + + var Source = function(string) { + this._string = string; + this._currentIndex = 0; + this._endIndex = this._string.length; + this._previousCommand = window.SVGPathSeg.PATHSEG_UNKNOWN; + + this._skipOptionalSpaces(); + } + + Source.prototype._isCurrentSpace = function() { + var character = this._string[this._currentIndex]; + return character <= ' ' && (character == ' ' || character == '\n' || character == '\t' || character == '\r' || character == '\f'); + } + + Source.prototype._skipOptionalSpaces = function() { + while (this._currentIndex < this._endIndex && this._isCurrentSpace()) + this._currentIndex++; + return this._currentIndex < this._endIndex; + } + + Source.prototype._skipOptionalSpacesOrDelimiter = function() { + if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ',') + return false; + if (this._skipOptionalSpaces()) { + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ',') { + this._currentIndex++; + this._skipOptionalSpaces(); + } + } + return this._currentIndex < this._endIndex; + } + + Source.prototype.hasMoreData = function() { + return this._currentIndex < this._endIndex; + } + + Source.prototype.peekSegmentType = function() { + var lookahead = this._string[this._currentIndex]; + return this._pathSegTypeFromChar(lookahead); + } + + Source.prototype._pathSegTypeFromChar = function(lookahead) { + switch (lookahead) { + case 'Z': + case 'z': + return window.SVGPathSeg.PATHSEG_CLOSEPATH; + case 'M': + return window.SVGPathSeg.PATHSEG_MOVETO_ABS; + case 'm': + return window.SVGPathSeg.PATHSEG_MOVETO_REL; + case 'L': + return window.SVGPathSeg.PATHSEG_LINETO_ABS; + case 'l': + return window.SVGPathSeg.PATHSEG_LINETO_REL; + case 'C': + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS; + case 'c': + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL; + case 'Q': + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS; + case 'q': + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL; + case 'A': + return window.SVGPathSeg.PATHSEG_ARC_ABS; + case 'a': + return window.SVGPathSeg.PATHSEG_ARC_REL; + case 'H': + return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS; + case 'h': + return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL; + case 'V': + return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS; + case 'v': + return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL; + case 'S': + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; + case 's': + return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL; + case 'T': + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS; + case 't': + return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL; + default: + return window.SVGPathSeg.PATHSEG_UNKNOWN; + } + } + + Source.prototype._nextCommandHelper = function(lookahead, previousCommand) { + // Check for remaining coordinates in the current command. + if ((lookahead == '+' || lookahead == '-' || lookahead == '.' || (lookahead >= '0' && lookahead <= '9')) && previousCommand != window.SVGPathSeg.PATHSEG_CLOSEPATH) { + if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_ABS) + return window.SVGPathSeg.PATHSEG_LINETO_ABS; + if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_REL) + return window.SVGPathSeg.PATHSEG_LINETO_REL; + return previousCommand; + } + return window.SVGPathSeg.PATHSEG_UNKNOWN; + } + + Source.prototype.initialCommandIsMoveTo = function() { + // If the path is empty it is still valid, so return true. + if (!this.hasMoreData()) + return true; + var command = this.peekSegmentType(); + // Path must start with moveTo. + return command == window.SVGPathSeg.PATHSEG_MOVETO_ABS || command == window.SVGPathSeg.PATHSEG_MOVETO_REL; + } + + // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp. + // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF + Source.prototype._parseNumber = function() { + var exponent = 0; + var integer = 0; + var frac = 1; + var decimal = 0; + var sign = 1; + var expsign = 1; + + var startIndex = this._currentIndex; + + this._skipOptionalSpaces(); + + // Read the sign. + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '+') + this._currentIndex++; + else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '-') { + this._currentIndex++; + sign = -1; + } + + if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') && this._string.charAt(this._currentIndex) != '.')) + // The first character of a number must be one of [0-9+-.]. + return undefined; + + // Read the integer part, build right-to-left. + var startIntPartIndex = this._currentIndex; + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') + this._currentIndex++; // Advance to first non-digit. + + if (this._currentIndex != startIntPartIndex) { + var scanIntPartIndex = this._currentIndex - 1; + var multiplier = 1; + while (scanIntPartIndex >= startIntPartIndex) { + integer += multiplier * (this._string.charAt(scanIntPartIndex--) - '0'); + multiplier *= 10; + } + } + + // Read the decimals. + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '.') { + this._currentIndex++; + + // There must be a least one digit following the . + if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') + return undefined; + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { + frac *= 10; + decimal += (this._string.charAt(this._currentIndex) - '0') / frac; + this._currentIndex += 1; + } + } + + // Read the exponent part. + if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == 'e' || this._string.charAt(this._currentIndex) == 'E') && (this._string.charAt(this._currentIndex + 1) != 'x' && this._string.charAt(this._currentIndex + 1) != 'm')) { + this._currentIndex++; + + // Read the sign of the exponent. + if (this._string.charAt(this._currentIndex) == '+') { + this._currentIndex++; + } else if (this._string.charAt(this._currentIndex) == '-') { + this._currentIndex++; + expsign = -1; + } + + // There must be an exponent. + if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') + return undefined; + + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { + exponent *= 10; + exponent += (this._string.charAt(this._currentIndex) - '0'); + this._currentIndex++; + } + } + + var number = integer + decimal; + number *= sign; + + if (exponent) + number *= Math.pow(10, expsign * exponent); + + if (startIndex == this._currentIndex) + return undefined; + + this._skipOptionalSpacesOrDelimiter(); + + return number; + } + + Source.prototype._parseArcFlag = function() { + if (this._currentIndex >= this._endIndex) + return undefined; + var flag = false; + var flagChar = this._string.charAt(this._currentIndex++); + if (flagChar == '0') + flag = false; + else if (flagChar == '1') + flag = true; + else + return undefined; + + this._skipOptionalSpacesOrDelimiter(); + return flag; + } + + Source.prototype.parseSegment = function() { + var lookahead = this._string[this._currentIndex]; + var command = this._pathSegTypeFromChar(lookahead); + if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) { + // Possibly an implicit command. Not allowed if this is the first command. + if (this._previousCommand == window.SVGPathSeg.PATHSEG_UNKNOWN) + return null; + command = this._nextCommandHelper(lookahead, this._previousCommand); + if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) + return null; + } else { + this._currentIndex++; + } + + this._previousCommand = command; + + switch (command) { + case window.SVGPathSeg.PATHSEG_MOVETO_REL: + return new window.SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_MOVETO_ABS: + return new window.SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_REL: + return new window.SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_ABS: + return new window.SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: + return new window.SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: + return new window.SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: + return new window.SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: + return new window.SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber()); + case window.SVGPathSeg.PATHSEG_CLOSEPATH: + this._skipOptionalSpaces(); + return new window.SVGPathSegClosePath(owningPathSegList); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + return new window.SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + return new window.SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + case window.SVGPathSeg.PATHSEG_ARC_REL: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep); + case window.SVGPathSeg.PATHSEG_ARC_ABS: + var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()}; + return new window.SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep); + default: + throw 'Unknown path seg type.' + } + } + + var builder = new Builder(); + var source = new Source(string); + + if (!source.initialCommandIsMoveTo()) + return []; + while (source.hasMoreData()) { + var pathSeg = source.parseSegment(); + if (!pathSeg) + return []; + builder.appendSegment(pathSeg); + } + + return builder.pathSegList; + } + } +}()); + +/***** + * @svgpathend + * + * The above code is a derivative work of some part of the SVGPathSeg API. + * + * This API is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from + * SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec + * changes which were implemented in Firefox 43 and Chrome 46. + * + * @source https://github.com/progers/pathseg + */ + + +/***** + * @licstart + * + * The following is the license notice for the part of JavaScript code of + * this page included between the '@libreofficestart' and the '@libreofficeend' + * notes. + */ + +/***** ****************************************************************** + * + * 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 . + * + ************************************************************************/ + +/***** + * @licend + * + * The above is the license notice for the part of JavaScript code of + * this page included between the '@libreofficestart' and the '@libreofficeend' + * notes. + */ + + +/***** + * @libreofficestart + * + * Several parts of the following code are the result of the porting, + * started on August 2011, of the C++ code included in the source + * files placed under the folder '/slideshow/source' and + * sub-folders. This got later rebased onto the AL2-licensed versions + * of those files in early 2013. + * @source https://cgit.freedesktop.org/libreoffice/core/tree/slideshow/source + * + */ + + +window.onload = init; + + +// ooo elements +var aOOOElemMetaSlides = 'ooo:meta_slides'; +var aOOOElemMetaSlide = 'ooo:meta_slide'; +var aOOOElemTextField = 'ooo:text_field'; +var aPresentationClipPathId = 'presentation_clip_path'; +var aPresentationClipPathShrinkId = 'presentation_clip_path_shrink'; + +// ooo attributes +var aOOOAttrNumberOfSlides = 'number-of-slides'; +var aOOOAttrStartSlideNumber= 'start-slide-number'; +var aOOOAttrNumberingType = 'page-numbering-type'; +var aOOOAttrListItemNumberingType= 'numbering-type'; +var aOOOAttrUsePositionedChars = 'use-positioned-chars'; + +var aOOOAttrSlide = 'slide'; +var aOOOAttrMaster = 'master'; +var aOOOAttrDisplayName = 'display-name'; +var aOOOAttrSlideDuration = 'slide-duration'; +var aOOOAttrHasTransition = 'has-transition'; +var aOOOAttrHasCustomBackground = 'has-custom-background'; +var aOOOAttrBackgroundVisibility = 'background-visibility'; +var aOOOAttrMasterObjectsVisibility = 'master-objects-visibility'; +var aOOOAttrPageNumberVisibility = 'page-number-visibility'; +var aOOOAttrDateTimeVisibility = 'date-time-visibility'; +var aOOOAttrFooterVisibility = 'footer-visibility'; +var aOOOAttrHeaderVisibility = 'header-visibility'; +var aOOOAttrDateTimeField = 'date-time-field'; +var aOOOAttrFooterField = 'footer-field'; +var aOOOAttrHeaderField = 'header-field'; + +var aOOOAttrDateTimeFormat = 'date-time-format'; + +var aOOOAttrTextAdjust = 'text-adjust'; + +// element class names +var aClipPathGroupClassName = 'ClipPathGroup'; +var aPageClassName = 'Page'; +var aSlideNumberClassName = 'Slide_Number'; +var aDateTimeClassName = 'Date/Time'; +var aFooterClassName = 'Footer'; +var aHeaderClassName = 'Header'; +var aDateClassName = 'Date'; +var aTimeClassName = 'Time'; +var aSlideNameClassName='SlideName'; + +// Creating a namespace dictionary. +var NSS = {}; +NSS['svg']='http://www.w3.org/2000/svg'; +NSS['rdf']='http://www.w3.org/1999/02/22-rdf-syntax-ns#'; +NSS['xlink']='http://www.w3.org/1999/xlink'; +NSS['xml']='http://www.w3.org/XML/1998/namespace'; +NSS['ooo'] = 'http://xml.openoffice.org/svg/export'; +NSS['presentation'] = 'http://sun.com/xmlns/staroffice/presentation'; +NSS['smil'] = 'http://www.w3.org/2001/SMIL20/'; +NSS['anim'] = 'urn:oasis:names:tc:opendocument:xmlns:animation:1.0'; + +// Presentation modes. +var SLIDE_MODE = 1; +var INDEX_MODE = 2; + +// Mouse handler actions. +var MOUSE_UP = 1; +var MOUSE_DOWN = 2; // eslint-disable-line no-unused-vars +var MOUSE_MOVE = 3; // eslint-disable-line no-unused-vars +var MOUSE_WHEEL = 4; + +// Key-codes. +var LEFT_KEY = 37; // cursor left keycode +var UP_KEY = 38; // cursor up keycode +var RIGHT_KEY = 39; // cursor right keycode +var DOWN_KEY = 40; // cursor down keycode +var PAGE_UP_KEY = 33; // page up keycode +var PAGE_DOWN_KEY = 34; // page down keycode +var HOME_KEY = 36; // home keycode +var END_KEY = 35; // end keycode +var ENTER_KEY = 13; +var SPACE_KEY = 32; +var ESCAPE_KEY = 27; +var Q_KEY = 81; + +// Visibility Values +var HIDDEN = 0; +var VISIBLE = 1; +var INHERIT = 2; +var aVisibilityAttributeValue = [ 'hidden', 'visible', 'inherit' ]; // eslint-disable-line no-unused-vars +var aVisibilityValue = { 'hidden' : HIDDEN, 'visible' : VISIBLE, 'inherit' : INHERIT }; + +// Parameters +var ROOT_NODE = document.getElementsByTagNameNS( NSS['svg'], 'svg' )[0]; +var WIDTH = 0; +var HEIGHT = 0; +var INDEX_COLUMNS_DEFAULT = 3; +var INDEX_OFFSET = 0; + +// Initialization. +var Detect = configureDetectionTools(); +var theMetaDoc; +var theSlideIndexPage; +var currentMode = SLIDE_MODE; +var processingEffect = false; +var nCurSlide = undefined; +var bTextHasBeenSelected = false; +var sLastSelectedText = ''; + + +// Initialize char and key code dictionaries. +var charCodeDictionary = getDefaultCharCodeDictionary(); +var keyCodeDictionary = getDefaultKeyCodeDictionary(); + +// Initialize mouse handler dictionary. +var mouseHandlerDictionary = getDefaultMouseHandlerDictionary(); + +/*************************** + ** OOP support functions ** + ***************************/ + +function object( aObject ) +{ + var F = function() {}; + F.prototype = aObject; + return new F(); +} + + +function extend( aSubType, aSuperType ) +{ + if (!aSuperType || !aSubType) + { + alert('extend failed, verify dependencies'); + } + var OP = Object.prototype; + var sp = aSuperType.prototype; + var rp = object( sp ); + aSubType.prototype = rp; + + rp.constructor = aSubType; + aSubType.superclass = sp; + + // assign constructor property + if (aSuperType != Object && sp.constructor == OP.constructor) + { + sp.constructor = aSuperType; + } + + return aSubType; +} + + +function instantiate( TemplateClass, BaseType ) +{ + if( !TemplateClass.instanceSet ) + TemplateClass.instanceSet = []; + + var nSize = TemplateClass.instanceSet.length; + + for( var i = 0; i < nSize; ++i ) + { + if( TemplateClass.instanceSet[i].base === BaseType ) + return TemplateClass.instanceSet[i].instance; + } + + TemplateClass.instanceSet[ nSize ] = {}; + TemplateClass.instanceSet[ nSize ].base = BaseType; + TemplateClass.instanceSet[ nSize ].instance = TemplateClass( BaseType ); + + return TemplateClass.instanceSet[ nSize ].instance; +} + + + +/********************************** + ** Helper functions and classes ** + **********************************/ + +function Rectangle( aSVGRectElem ) +{ + var x = parseInt( aSVGRectElem.getAttribute( 'x' ) ); + var y = parseInt( aSVGRectElem.getAttribute( 'y' ) ); + var width = parseInt( aSVGRectElem.getAttribute( 'width' ) ); + var height = parseInt( aSVGRectElem.getAttribute( 'height' ) ); + + this.left = x; + this.right = x + width; + this.top = y; + this.bottom = y + height; +} + +/* + * Returns key corresponding to a value in object, null otherwise. + * + * @param Object + * @param value + */ +function getKeyByValue(aObj, value) { + for(var key in aObj) { + if(aObj[key] == value) + return key; + } + return null; +} + +function log( message ) +{ + if( typeof console == 'object' ) + { + // eslint-disable-next-line no-console + console.log( message ); + } + else if( typeof opera == 'object' ) + { + opera.postError( message ); + } + // eslint-disable-next-line no-undef + else if( typeof java == 'object' && typeof java.lang == 'object' ) + { + // eslint-disable-next-line no-undef + java.lang.System.out.println( message ); + } +} + +function getNSAttribute( sNSPrefix, aElem, sAttrName ) +{ + if( !aElem ) return null; + if( 'getAttributeNS' in aElem ) + { + return aElem.getAttributeNS( NSS[sNSPrefix], sAttrName ); + } + else + { + return aElem.getAttribute( sNSPrefix + ':' + sAttrName ); + } +} + +function getOOOAttribute( aElem, sAttrName ) +{ + return getNSAttribute( 'ooo', aElem, sAttrName ); +} + +function setNSAttribute( sNSPrefix, aElem, sAttrName, aValue ) +{ + if( !aElem ) return false; + if( 'setAttributeNS' in aElem ) + { + aElem.setAttributeNS( NSS[sNSPrefix], sAttrName, aValue ); + return true; + } + else + { + aElem.setAttribute(sNSPrefix + ':' + sAttrName, aValue ); + return true; + } +} + +function getElementsByClassName( aElem, sClassName ) +{ + + var aElementSet = []; + // not all browsers support the 'getElementsByClassName' method + if( 'getElementsByClassName' in aElem ) + { + aElementSet = aElem.getElementsByClassName( sClassName ); + } + else + { + var aElementSetByClassProperty = getElementsByProperty( aElem, 'class' ); + for( var i = 0; i < aElementSetByClassProperty.length; ++i ) + { + var sAttrClassName = aElementSetByClassProperty[i].getAttribute( 'class' ); + if( sAttrClassName == sClassName ) + { + aElementSet.push( aElementSetByClassProperty[i] ); + } + } + } + return aElementSet; +} + +function getElementByClassName( aElem, sClassName /*, sTagName */) +{ + var aElementSet = getElementsByClassName( aElem, sClassName ); + if ( aElementSet.length == 1 ) + return aElementSet[0]; + else + return null; +} + +function getClassAttribute( aElem ) +{ + if( aElem ) + return aElem.getAttribute( 'class' ); + return ''; +} + +function createElementGroup( aParentElement, aElementList, nFrom, nCount, sGroupClass, sGroupId ) +{ + var nTo = nFrom + nCount; + if( nCount < 1 || aElementList.length < nTo ) + { + log( 'createElementGroup: not enough elements available.' ); + return; + } + var firstElement = aElementList[nFrom]; + if( !firstElement ) + { + log( 'createElementGroup: element not found.' ); + return; + } + var aGroupElement = document.createElementNS( NSS['svg'], 'g' ); + if( sGroupId ) + aGroupElement.setAttribute( 'id', sGroupId ); + if( sGroupClass ) + aGroupElement.setAttribute( 'class', sGroupClass ); + aParentElement.insertBefore( aGroupElement, firstElement ); + var i = nFrom; + for( ; i < nTo; ++i ) + { + aParentElement.removeChild( aElementList[i] ); + aGroupElement.appendChild( aElementList[i] ); + } +} + +function initVisibilityProperty( aElement ) +{ + var nVisibility = VISIBLE; + var sVisibility = aElement.getAttribute( 'visibility' ); + if( sVisibility ) nVisibility = aVisibilityValue[ sVisibility ]; + return nVisibility; +} + +function getSafeIndex( nIndex, nMin, nMax ) +{ + if( nIndex < nMin ) + return nMin; + else if( nIndex > nMax ) + return nMax; + else + return nIndex; +} + +function getUrlParameter(name) +{ + name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); + var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); + var results = regex.exec(window.location.search); + return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); +} + +/** getRandomInt + * + * @param nMax + * @returns {number} + * an integer in [0,nMax[ + */ +function getRandomInt( nMax ) +{ + return Math.floor( Math.random() * nMax ); +} + +function isTextFieldElement( aElement ) // eslint-disable-line no-unused-vars +{ + var sClassName = aElement.getAttribute( 'class' ); + return ( sClassName === aSlideNumberClassName ) || + ( sClassName === aFooterClassName ) || + ( sClassName === aHeaderClassName ) || + ( sClassName === aDateTimeClassName ); +} + + +/********************* + ** Debug Utilities ** + *********************/ + +function DebugPrinter() +{ + this.bEnabled = false; +} + + +DebugPrinter.prototype.on = function() +{ + this.bEnabled = true; +}; + +DebugPrinter.prototype.off = function() +{ + this.bEnabled = false; +}; + +DebugPrinter.prototype.isEnabled = function() +{ + return this.bEnabled; +}; + +DebugPrinter.prototype.print = function( sMessage, nTime ) +{ + if( this.isEnabled() ) + { + var sInfo = 'DBG: ' + sMessage; + if( nTime ) + sInfo += ' (at: ' + String( nTime / 1000 ) + 's)'; + log( sInfo ); + } +}; + + +// - Debug Printers - +var aGenericDebugPrinter = new DebugPrinter(); +aGenericDebugPrinter.on(); +var DBGLOG = bind2( DebugPrinter.prototype.print, aGenericDebugPrinter ); + +var NAVDBG = new DebugPrinter(); +NAVDBG.off(); + +var ANIMDBG = new DebugPrinter(); +ANIMDBG.off(); + +var aRegisterEventDebugPrinter = new DebugPrinter(); +aRegisterEventDebugPrinter.off(); + +var aTimerEventQueueDebugPrinter = new DebugPrinter(); +aTimerEventQueueDebugPrinter.off(); + +var aEventMultiplexerDebugPrinter = new DebugPrinter(); +aEventMultiplexerDebugPrinter.off(); + +var aNextEffectEventArrayDebugPrinter = new DebugPrinter(); +aNextEffectEventArrayDebugPrinter.off(); + +var aActivityQueueDebugPrinter = new DebugPrinter(); +aActivityQueueDebugPrinter.off(); + +var aAnimatedElementDebugPrinter = new DebugPrinter(); +aAnimatedElementDebugPrinter.off(); + + + + +/************************ + *** Core Classes *** + ************************/ + +/** Class MetaDocument + * This class provides a pool of properties related to the whole presentation. + * Moreover it is responsible for: + * - initializing the set of MetaSlide objects that handle the meta information + * for each slide; + * - creating a map with key an id and value the svg element containing + * the animations performed on the slide with such an id. + * + */ +function MetaDocument() +{ + // We look for the svg element that provides the following presentation + // properties: + // - the number of slides in the presentation; + // - the type of numbering used in the presentation. + // Moreover it wraps svg elements providing meta information on each slide + // and svg elements providing content and properties of each text field. + var aMetaDocElem = document.getElementById( aOOOElemMetaSlides ); + assert( aMetaDocElem, 'MetaDocument: the svg element with id:' + aOOOElemMetaSlides + 'is not valid.'); + + // We initialize general presentation properties: + // - the number of slides in the presentation; + this.nNumberOfSlides = parseInt( aMetaDocElem.getAttributeNS( NSS['ooo'], aOOOAttrNumberOfSlides ) ); + assert( typeof this.nNumberOfSlides == 'number' && this.nNumberOfSlides > 0, + 'MetaDocument: number of slides is zero or undefined.' ); + // - the index of the slide to show when the presentation starts; + this.nStartSlideNumber = parseInt( aMetaDocElem.getAttributeNS( NSS['ooo'], aOOOAttrStartSlideNumber ) ) || 0; + // - get the parameter StartSlideNumber in the URL for online presentation + var aParmStartSlideNumber = getUrlParameter('StartSlideNumber'); + if (aParmStartSlideNumber !== '') + { + this.nStartSlideNumber = parseInt(aParmStartSlideNumber); + } + // - the numbering type used in the presentation, default type is arabic. + this.sPageNumberingType = aMetaDocElem.getAttributeNS( NSS['ooo'], aOOOAttrNumberingType ) || 'arabic'; + // - the way text is exported + this.bIsUsePositionedChars = ( aMetaDocElem.getAttributeNS( NSS['ooo'], aOOOAttrUsePositionedChars ) === 'true' ); + + // The element used for wrapping . + this.aClipPathGroup = getElementByClassName( ROOT_NODE, aClipPathGroupClassName ); + assert( this.aClipPathGroup, 'MetaDocument: the clip path group element is not valid.'); + + // The element used to clip all slides. + this.aPresentationClipPath = document.getElementById( aPresentationClipPathId ); + assert( this.aPresentationClipPath, + 'MetaDocument: the presentation clip path element element is not valid.'); + + // The collections for handling properties of each slide, svg elements + // related to master pages and content and properties of text fields. + this.aMetaSlideSet = []; + this.aMasterPageSet = {}; + this.aTextFieldHandlerSet = {}; + this.aTextFieldContentProviderSet = []; + this.aSlideNumberProvider = new SlideNumberProvider( this.nStartSlideNumber + 1, this.sPageNumberingType ); + this.aCurrentDateProvider = new CurrentDateTimeProvider( null, '' ); + this.aCurrentTimeProvider = new CurrentDateTimeProvider( null, '