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/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 + 647 files changed, 171094 insertions(+) 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 (limited to 'filter/source') 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, '