diff options
Diffstat (limited to 'sw/source/filter/ww8/wrtww8.hxx')
-rw-r--r-- | sw/source/filter/ww8/wrtww8.hxx | 1662 |
1 files changed, 1662 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx new file mode 100644 index 000000000..34d7eed5d --- /dev/null +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -0,0 +1,1662 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SW_SOURCE_FILTER_WW8_WRTWW8_HXX +#define INCLUDED_SW_SOURCE_FILTER_WW8_WRTWW8_HXX + +#include <sot/storage.hxx> +#include <svl/nfkeytab.hxx> +#include <tools/solar.h> +#include <tools/gen.hxx> +#include <editeng/editdata.hxx> +#include <filter/msfilter/ww8fields.hxx> + +#include <shellio.hxx> + +#include "ww8struc.hxx" +#include "ww8scan.hxx" +#include "types.hxx" +#include "writerhelper.hxx" +#include <msfilter.hxx> +#include <expfld.hxx> +#include "WW8TableInfo.hxx" +#include <calbck.hxx> +#include <IDocumentRedlineAccess.hxx> + +#include <vcl/graph.hxx> + +#include <optional> +#include <o3tl/typed_flags_set.hxx> +#include <o3tl/sorted_vector.hxx> + +#include <cstddef> +#include <memory> +#include <map> +#include <string_view> +#include <vector> + + +class SvxBrushItem; +class EditTextObject; + +// some forward declarations +class SwWW8AttrIter; +namespace msfilter +{ + class MSCodec_Std97; +} + +namespace editeng { class SvxBorderLine; } + +class AttributeOutputBase; +class DocxAttributeOutput; +class RtfAttributeOutput; +class BitmapPalette; +class SwEscherEx; +class DateTime; +namespace vcl { class Font; } +class MSWordExportBase; +class SdrObject; +class SdrTextObj; +class SfxItemSet; +class SvStream; +class SvxFontItem; +class SvxBoxItem; +class SwAttrSet; +class SwCharFormat; +class SwContentNode; +class SwField; +class SwFormat; +class SwFormatContent; +class SwFormatFootnote; +class SwFrameFormat; +class SwGrfNode; +class SwNumFormat; +class SwNumRule; +class SwNumRuleTable; +class SwPageDesc; +class SwFormatPageDesc; +class SwOLENode; +class SwPostItField; +class SwRedlineData; +class SwSectionFormat; +class SwSectionNode; +class SwTableNode; +class SwTOXType; +class SwTextFormatColl; +class SwTextNode; +class SwWW8WrGrf; +class SwWW8Writer; +class MSWordStyles; +class WW8AttributeOutput; +class WW8Export; +class MSWordAttrIter; +class WW8_WrFkp; +class WW8_WrPlc0; +class WW8_WrPlc1; +class WW8_WrPlcField; +class WW8_WrMagicTable; +class WW8_WrPlcFootnoteEdn; +class WW8_WrPlcPn; +class WW8_WrPlcAnnotations; +class WW8_WrtFactoids; +class MSWordSections; +class WW8_WrPlcTextBoxes; +class WW8_WrPct; // administration +class WW8_WrtBookmarks; +class WW8_WrtRedlineAuthor; +class SvxMSExportOLEObjects; +class SwMSConvertControls; +class WW8_WrPc; +struct WW8_PdAttrDesc; +class SvxBrushItem; +namespace sw::mark { class IFieldmark; } +namespace com::sun::star::embed { class XEmbeddedObject; } + +typedef std::map<const css::embed::XEmbeddedObject*, sal_Int32> WW8OleMap; +typedef o3tl::sorted_vector< sal_Int32 > SwSoftPageBreakList; + +#define GRF_MAGIC_1 0x12 // 3 magic bytes for PicLocFc attribute +#define GRF_MAGIC_2 0x34 +#define GRF_MAGIC_3 0x56 +#define GRF_MAGIC_321 0x563412L + +#define OLE_PREVIEW_AS_EMF //If we want to export ole2 previews as emf in ww8+ + +enum class FieldFlags : sal_uInt8 // for InsertField- Method +{ + NONE = 0x00, + Start = 0x01, + CmdStart = 0x02, + CmdEnd = 0x04, + End = 0x10, + Close = 0x20, + All = 0x37 +}; +namespace o3tl { + template<> struct typed_flags<FieldFlags> : is_typed_flags<FieldFlags, 0x37> {}; +} + +enum TextTypes //enums for TextTypes +{ + TXT_MAINTEXT = 0, /*TXT_FTNEDN = 1,*/ TXT_HDFT = 2, TXT_FTN = 3, + TXT_EDN = 4, TXT_ATN = 5, TXT_TXTBOX = 6, TXT_HFTXTBOX= 7 +}; + +/** +enum to state the present state of the fly +*/ +enum FlyProcessingState +{ + FLY_NONE, + FLY_PROCESSED, + FLY_POSTPONED, + FLY_NOT_PROCESSED +}; + +struct WW8_SepInfo +{ + const SwPageDesc* pPageDesc; + const SwSectionFormat* pSectionFormat; + const SwNode* pPDNd; + sal_uLong nLnNumRestartNo; + ::std::optional<sal_uInt16> oPgRestartNo; + bool bIsFirstParagraph; + + WW8_SepInfo( const SwPageDesc* pPD, const SwSectionFormat* pFormat, + sal_uLong nLnRestart, ::std::optional<sal_uInt16> oPgRestart = std::nullopt, + const SwNode* pNd = nullptr, bool bIsFirstPara = false ) + : pPageDesc( pPD ), pSectionFormat( pFormat ), pPDNd( pNd ), + nLnNumRestartNo( nLnRestart ), oPgRestartNo( oPgRestart ), + bIsFirstParagraph( bIsFirstPara ) + {} + + bool IsProtected() const; +}; + +/// Class to collect and output the sections/headers/footers. +// Plc for PageDescs -> Sepx ( Section Extensions ) +class MSWordSections +{ +protected: + bool mbDocumentIsProtected; + std::vector<WW8_SepInfo> m_aSects; + + void CheckForFacinPg( const WW8Export& rWrt ) const; + void NeedsDocumentProtected(const WW8_SepInfo &rInfo); + + //No copy, no assign + MSWordSections( const MSWordSections& ); + MSWordSections& operator=( const MSWordSections& ); +public: + explicit MSWordSections( MSWordExportBase& rExport ); + virtual ~MSWordSections(); + + virtual bool HeaderFooterWritten(); + + void AppendSection( const SwPageDesc* pPd, + const SwSectionFormat* pSectionFormat, + sal_uLong nLnNumRestartNo, + bool bIsFirstParagraph = false ); + void AppendSection( const SwFormatPageDesc& rPd, + const SwNode& rNd, + const SwSectionFormat* pSectionFormat, + sal_uLong nLnNumRestartNo ); + + /// Number of columns based on the most recent WW8_SepInfo. + sal_uInt16 CurrentNumberOfColumns( const SwDoc &rDoc ) const; + + /// Number of columns of the provided WW8_SepInfo. + static sal_uInt16 NumberOfColumns( const SwDoc &rDoc, const WW8_SepInfo& rInfo ); + + bool DocumentIsProtected() const { return mbDocumentIsProtected; } + + /// The most recent WW8_SepInfo. + const WW8_SepInfo* CurrentSectionInfo(); + + static void SetHeaderFlag( sal_uInt8& rHeadFootFlags, const SwFormat& rFormat, + sal_uInt8 nFlag ); + static void SetFooterFlag( sal_uInt8& rHeadFootFlags, const SwFormat& rFormat, + sal_uInt8 nFlag ); + + /// Should we output borders? + static bool HasBorderItem( const SwFormat& rFormat ); +}; + +class WW8_WrPlcSepx : public MSWordSections +{ + std::vector<WW8_CP> m_aCps; + std::vector< std::shared_ptr<WW8_PdAttrDesc> > m_SectionAttributes; + // hack to prevent adding sections in endnotes + bool m_bHeaderFooterWritten; + std::unique_ptr<WW8_WrPlc0> m_pTextPos; // Position of the headers/footers + + WW8_WrPlcSepx( const WW8_WrPlcSepx& ) = delete; + WW8_WrPlcSepx& operator=( const WW8_WrPlcSepx& ) = delete; + +public: + explicit WW8_WrPlcSepx( MSWordExportBase& rExport ); + virtual ~WW8_WrPlcSepx() override; + + virtual bool HeaderFooterWritten() override; // override + + void AppendSep( WW8_CP nStartCp, + const SwPageDesc* pPd, + const SwSectionFormat* pSectionFormat, + sal_uLong nLnNumRestartNo ); + void AppendSep( WW8_CP nStartCp, const SwFormatPageDesc& rPd, + const SwNode& rNd, + const SwSectionFormat* pSectionFormat, + sal_uLong nLnNumRestartNo ); + void Finish( WW8_CP nEndCp ) { m_aCps.push_back( nEndCp ); } + + bool WriteKFText( WW8Export& rWrt ); + void WriteSepx( SvStream& rStrm ) const; + void WritePlcSed( WW8Export& rWrt ) const; + void WritePlcHdd( WW8Export& rWrt ) const; + +private: + void WriteFootnoteEndText( WW8Export& rWrt, sal_uLong nCpStt ); +public: + void OutHeaderFooter(WW8Export& rWrt, bool bHeader, + const SwFormat& rFormat, sal_uLong& rCpPos, sal_uInt8 nHFFlags, sal_uInt8 nFlag, sal_uInt8 nBreakCode); +}; + +// class WW8_WrPct to construct the piece table +class WW8_WrPct +{ + std::vector<std::unique_ptr<WW8_WrPc>> m_Pcts; + WW8_FC m_nOldFc; +public: + explicit WW8_WrPct(WW8_FC nStartFc); + ~WW8_WrPct(); + void AppendPc(WW8_FC nStartFc); + void WritePc( WW8Export& rWrt ); + void SetParaBreak(); + WW8_CP Fc2Cp( sal_uLong nFc ) const; +}; + +/// Collects and outputs fonts. +class wwFont +{ +//In some future land the stream could be converted to a nice stream interface +//and we could have harmony +private: + sal_uInt8 maWW8_FFN[6] = {}; + OUString msFamilyNm; + OUString msAltNm; + bool mbAlt; + FontPitch mePitch; + FontFamily meFamily; + rtl_TextEncoding meChrSet; +public: + wwFont( std::u16string_view rFamilyName, FontPitch ePitch, FontFamily eFamily, + rtl_TextEncoding eChrSet); + void Write( SvStream *pTableStram ) const; + void WriteDocx( DocxAttributeOutput* rAttrOutput ) const; + void WriteRtf( const RtfAttributeOutput* rAttrOutput ) const; + OUString const & GetFamilyName() const { return msFamilyNm; } + friend bool operator < (const wwFont &r1, const wwFont &r2); +}; + +class wwFontHelper +{ +private: + /// Keep track of fonts that need to be exported. + std::map<wwFont, sal_uInt16> maFonts; + + /// Convert from fast insertion map to linear vector in the order that we want to write. + std::vector< const wwFont* > AsVector() const; + +public: + wwFontHelper() : m_bLoadAllFonts(false) {} + /// rDoc used only to get the initial standard font(s) in use. + void InitFontTable(const SwDoc& rDoc); + sal_uInt16 GetId(const SvxFontItem& rFont); + sal_uInt16 GetId(const wwFont& rFont); + void WriteFontTable( SvStream *pTableStream, WW8Fib& pFib ); + void WriteFontTable( DocxAttributeOutput& rAttrOutput ); + void WriteFontTable( const RtfAttributeOutput& rAttrOutput ); + + /// If true, all fonts are loaded before processing the document. + bool m_bLoadAllFonts: 1; +}; + +class DrawObj +{ +public: + WW8_CP mnCp; // CP-Pos of references + sal_uInt32 mnShapeId; // ShapeId for the SwFrameFormats + ww8::Frame maContent; // the frame itself + Point maParentPos; // Points + sal_Int32 mnThick; // Border Thicknesses + SvxFrameDirection mnDirection; // If BiDi or not + unsigned int mnHdFtIndex; // 0 for main text, +1 for each subsequent + // msword hd/ft + + DrawObj(const ww8::Frame &rContent, WW8_CP nCp, Point aParentPos, SvxFrameDirection nDir, + unsigned int nHdFtIndex) + : mnCp(nCp), mnShapeId(0), maContent(rContent), maParentPos(aParentPos), + mnThick(0), mnDirection(nDir), mnHdFtIndex(nHdFtIndex) {} + void SetShapeDetails(sal_uInt32 nId, sal_Int32 nThick); +}; + +typedef std::vector<DrawObj> DrawObjVector; +typedef std::vector<DrawObj *> DrawObjPointerVector; + +class PlcDrawObj // PC for DrawObjects and Text-/OLE-/GRF-Boxes +{ +private: + DrawObjVector maDrawObjs; // vector of drawobjs +protected: + virtual void RegisterWithFib(WW8Fib &rFib, sal_uInt32 nStart, + sal_uInt32 nLen) const = 0; + virtual WW8_CP GetCpOffset(const WW8Fib &rFib) const = 0; +public: + PlcDrawObj() {} + void WritePlc( WW8Export& rWrt ) const; + bool Append( WW8Export const &, WW8_CP nCp, const ww8::Frame& rFormat, + const Point& rNdTopLeft ); + int size() { return maDrawObjs.size(); }; + DrawObjVector &GetObjArr() { return maDrawObjs; } + virtual ~PlcDrawObj(); +private: + PlcDrawObj(const PlcDrawObj&) = delete; + PlcDrawObj& operator=(const PlcDrawObj&) = delete; +}; + +class MainTextPlcDrawObj : public PlcDrawObj +{ +public: + MainTextPlcDrawObj() {} +private: + virtual void RegisterWithFib(WW8Fib &rFib, sal_uInt32 nStart, + sal_uInt32 nLen) const override; + virtual WW8_CP GetCpOffset(const WW8Fib &) const override; +private: + MainTextPlcDrawObj(const MainTextPlcDrawObj&) = delete; + MainTextPlcDrawObj& operator=(const MainTextPlcDrawObj&) = delete; +}; + +class HdFtPlcDrawObj : public PlcDrawObj +{ +public: + HdFtPlcDrawObj() {} +private: + virtual void RegisterWithFib(WW8Fib &rFib, sal_uInt32 nStart, + sal_uInt32 nLen) const override; + virtual WW8_CP GetCpOffset(const WW8Fib &rFib) const override; +private: + HdFtPlcDrawObj(const HdFtPlcDrawObj&) = delete; + HdFtPlcDrawObj& operator=(const HdFtPlcDrawObj&) = delete; +}; + +typedef std::pair<OUString, SwNodeOffset> aBookmarkPair; + +class WW8_WrtRedlineAuthor : public sw::util::WrtRedlineAuthor +{ + public: + virtual void Write(Writer &rWrt) override; +}; + +/** Structure that is used to save some of the WW8Export/DocxExport data. + + It is used to be able to recurse inside of the WW8Export/DocxExport (eg. + for the needs of the tables) - you need to tall WriteText() from there with + new values of PaM etc. + + It must contain all the stuff that might be saved either in WW8Export or in + DocxExport, because it makes no sense to do it abstract, and specialize it + for each of the cases. If you implement other *Export, just add the needed + members here, and store them in the appropriate SaveData() method. + */ +struct MSWordSaveData +{ + Point* pOldFlyOffset; + RndStdIds eOldAnchorType; + std::unique_ptr<ww::bytes> pOOld; ///< WW8Export only + std::shared_ptr<SwUnoCursor> pOldPam; + SwPaM* pOldEnd; + SwNodeOffset nOldStart, nOldEnd; + const ww8::Frame* pOldFlyFormat; + const SwPageDesc* pOldPageDesc; + + bool bOldWriteAll : 1; ///< WW8Export only + bool bOldOutTable : 1; + bool bOldFlyFrameAttrs : 1; + bool bOldStartTOX : 1; + bool bOldInWriteTOX : 1; + // m_bOutPageDescs does not have to be saved in MSWordExportBase::SaveData + // since it is only modified when outputting special texts. +}; + +/// Base class for WW8Export and DocxExport +class MSWordExportBase +{ +public: + wwFontHelper m_aFontHelper; + std::vector<SwNodeOffset> m_aChapterFieldLocs; + OUString m_aMainStg; + std::vector<const SwTOXType*> m_aTOXArr; + const SfxItemSet* m_pISet; // for double attributes + const SwFrameFormat* m_pFirstPageFormat = nullptr; + std::unique_ptr<WW8_WrPct> m_pPiece; // Pointer to Piece-Table + std::unique_ptr<SwNumRuleTable> m_pUsedNumTable; // all used NumRules + /// overriding numdef index -> (existing numdef index, abstractnumdef index) + std::map<size_t, std::pair<size_t, size_t>> m_OverridingNums; + /// list-id -> abstractnumdef index + std::map<OUString, size_t> m_Lists; + + /// Map of maps for list levels overrides + /// listid -> level number -> restart value + std::map < size_t, std::map<size_t, size_t> > m_ListLevelOverrides; + + const SwTextNode *m_pTopNodeOfHdFtPage; ///< Top node of host page when in hd/ft + std::stack< sal_Int32 > m_aCurrentCharPropStarts; ///< To remember the position in a run. + std::unique_ptr<WW8_WrtBookmarks> m_pBkmks; + std::unique_ptr<WW8_WrtRedlineAuthor> m_pRedlAuthors; + std::shared_ptr<NfKeywordTable> m_pKeyMap; + std::unique_ptr<SvxMSExportOLEObjects> m_pOLEExp; + std::unique_ptr<SwMSConvertControls> m_pOCXExp; + WW8OleMap m_aOleMap; // To remember all already exported ole objects + ww8::WW8TableInfo::Pointer_t m_pTableInfo; + + sal_uInt16 m_nCharFormatStart; + sal_uInt16 m_nFormatCollStart; + sal_uInt16 m_nStyleBeforeFly; ///< style number of the node + ///< to which the Fly is connected + sal_uInt16 m_nLastFormatId; ///< Style of last TextNode in normal range + sal_uInt16 m_nUniqueList; ///< current number for creating unique list names + unsigned int m_nHdFtIndex; + + RedlineFlags m_nOrigRedlineFlags; ///< Remember the original redline mode + bool m_bOrigShowChanges; ///< Remember the original Show Changes mode + +public: + /* implicit bookmark vector containing pairs of node indexes and bookmark names */ + std::vector<aBookmarkPair> m_aImplicitBookmarks; + std::unordered_map<OUString, OUString> m_TOXMarkBookmarksByURL; + std::unordered_map<SwTOXMark const*, OUString> m_TOXMarkBookmarksByTOXMark; + ww8::Frames m_aFrames; // The floating frames in this document + const SwPageDesc *m_pCurrentPageDesc; + bool m_bFirstTOCNodeWithSection; + std::unique_ptr<WW8_WrPlcPn> m_pPapPlc; + std::unique_ptr<WW8_WrPlcPn> m_pChpPlc; + MSWordAttrIter* m_pChpIter; + std::unique_ptr<MSWordStyles> m_pStyles; + std::unique_ptr<WW8_WrPlcAnnotations> m_pAtn; + std::unique_ptr<WW8_WrtFactoids> m_pFactoids; + std::unique_ptr<WW8_WrPlcTextBoxes> m_pTextBxs, m_pHFTextBxs; + + struct LinkedTextboxInfo //help analyze textbox flow links + { + sal_Int32 nId; + sal_Int32 nSeq; + OUString sNextChain; + OUString sPrevChain; + LinkedTextboxInfo(): nId(0), nSeq(0) {} + }; + std::map<OUString,LinkedTextboxInfo> m_aLinkedTextboxesHelper; + bool m_bLinkedTextboxesHelperInitialized = false; + sal_Int32 m_nLinkedTextboxesChainId=0; + + const ww8::Frame *m_pParentFrame; // If set we are exporting content inside + // a frame, e.g. a graphic node + + Point* m_pFlyOffset; // for adjusting of character-bound Fly in the Writer, + RndStdIds m_eNewAnchorType; // that is paragraph-bound in the WW. + + std::unique_ptr<WW8_WrPlcField> m_pFieldMain; // fields in MainText + std::unique_ptr<WW8_WrPlcField> m_pFieldHdFt; // fields in Header/Footer + std::unique_ptr<WW8_WrPlcField> m_pFieldFootnote; // fields in FootNotes + std::unique_ptr<WW8_WrPlcField> m_pFieldEdn; // fields in EndNotes + std::unique_ptr<WW8_WrPlcField> m_pFieldAtn; // fields in Annotations + std::unique_ptr<WW8_WrPlcField> m_pFieldTextBxs; // fields in textboxes + std::unique_ptr<WW8_WrPlcField> m_pFieldHFTextBxs; // fields in header/footer textboxes + std::unique_ptr<WW8_WrMagicTable> m_pMagicTable; // keeps track of table cell positions, and + // marks those that contain graphics, + // which is required to make word display + // graphics inside tables + std::unique_ptr<SwWW8WrGrf> m_pGrf; + const SwAttrSet* m_pStyAttr; // StyleAttr for Tabs + const sw::BroadcastingModify* m_pOutFormatNode; // write Format or Node + const SwFormat *m_pCurrentStyle; // iff bStyDef=true, then this store the current style + + std::unique_ptr<MainTextPlcDrawObj> m_pSdrObjs; // Draw-/Fly-Objects + std::unique_ptr<HdFtPlcDrawObj> m_pHFSdrObjs; // Draw-/Fly-Objects in header or footer + + SwEscherEx* m_pEscher; // escher export class + // #i43447# - removed +// SwTwips nFlyWidth, nFlyHeight; // for adaptation of graphics + + sal_uInt8 m_nTextTyp; + + bool m_bStyDef : 1; // should Style be written? + bool m_bBreakBefore : 1; // Breaks are being written 2 times + bool m_bOutKF : 1; // Header/Footer texts are being written + bool m_bOutFlyFrameAttrs : 1; // Frame-attr of Flys are being written + bool m_bOutPageDescs : 1; ///< PageDescs (section properties) are being written + bool m_bOutFirstPage : 1; // write Attrset of FirstPageDesc + bool m_bOutTable : 1; // table is being written + // ( is reset e.g. for Flys in a table ) + bool m_bOutGrf : 1; // graphics are being written + bool m_bInWriteEscher : 1; // in write textboxes + bool m_bStartTOX : 1; // true: a TOX is started + bool m_bInWriteTOX : 1; // true: all content are in a TOX + bool m_bFootnoteAtTextEnd : 1; // true: all FTN at Textend + bool m_bEndAtTextEnd : 1; // true: all END at Textend + bool m_bHasHdr : 1; + bool m_bHasFtr : 1; + bool m_bSubstituteBullets : 1; // true: SubstituteBullet() gets called + bool m_bTabInTOC : 1; //true for TOC field flag 'w' + + bool m_bHideTabLeaderAndPageNumbers : 1 ; // true: the 'z' field of TOC is set. + bool m_bExportModeRTF; + /// Is font size written already as part of the current character properties? + bool m_bFontSizeWritten; + bool m_bAddFootnoteTab; // only one aesthetic spacing tab per footnote + + SwDoc& m_rDoc; + SwNodeOffset m_nCurStart, m_nCurEnd; + std::shared_ptr<SwUnoCursor> & m_pCurPam; + SwPaM *m_pOrigPam; + + /// Stack to remember the nesting (see MSWordSaveData for more) + std::stack< MSWordSaveData > m_aSaveData; + + /// Used to split the runs according to the bookmarks start and ends + typedef std::vector< ::sw::mark::IMark* > IMarkVector; + IMarkVector m_rSortedBookmarksStart; + IMarkVector m_rSortedBookmarksEnd; + IMarkVector m_rSortedAnnotationMarksStart; + IMarkVector m_rSortedAnnotationMarksEnd; + +public: + /// The main function to export the document. + ErrCode ExportDocument( bool bWriteAll ); + + /// Iterate through the nodes and call the appropriate OutputNode() on them. + void WriteText(); + + /// Return whether currently exported node is in table. + bool IsInTable() const; + + /// Set the pCurPam appropriately and call WriteText(). + /// + /// Used to export paragraphs in footnotes/endnotes/etc. + void WriteSpecialText( SwNodeOffset nStart, SwNodeOffset nEnd, sal_uInt8 nTTyp ); + + /// Export the pool items to attributes (through an attribute output class). + void ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont, bool bWriteCombChars = false ); + + /// Return the numeric id of the numbering rule + sal_uInt16 GetNumberingId( const SwNumRule& rNumRule ); + + /// Return the numeric id of the style. + sal_uInt16 GetId( const SwTextFormatColl& rColl ) const; + + /// Return the numeric id of the style. + sal_uInt16 GetId( const SwCharFormat* pFormat ) const; + + sal_uInt16 GetId( const SwTOXType& rTOXType ); + + /// Return the numeric id of the font (and add it to the font list if needed) + sal_uInt16 GetId( const SvxFontItem& rFont) + { + return m_aFontHelper.GetId(rFont); + } + /// @overload + void GetId( const wwFont& rFont) + { + m_aFontHelper.GetId(rFont); + } + + const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const; + template<class T> const T& GetItem( TypedWhichId<T> nWhich ) const + { + return static_cast<const T&>(GetItem(sal_uInt16(nWhich))); + } + + /// Find the reference. + bool HasRefToAttr(const OUString& rName); + bool HasRefToFootOrEndnote(const bool isEndNote, const sal_uInt16 nSeqNo); + + /// Find the bookmark name. + static OUString GetBookmarkName( sal_uInt16 nTyp, const OUString* pName, sal_uInt16 nSeqNo ); + + /// Use OutputItem() on an item set according to the parameters. + void OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, bool bChpFormat, sal_uInt16 nScript, bool bExportParentItemSet ); + + SvxFrameDirection GetDefaultFrameDirection( ) const; + + /// Right to left? + SvxFrameDirection TrueFrameDirection( const SwFrameFormat& rFlyFormat ) const; + + /// Right to left? + SvxFrameDirection GetCurrentPageDirection() const; + + /// In case of numbering restart. + + /// List is set to restart at a particular value so for export make a + /// completely new list based on this one and export that instead, + /// which duplicates words behaviour in this respect. + sal_uInt16 DuplicateNumRule(const SwNumRule* pRule, sal_uInt8 nLevel, sal_uInt16 nVal); + SwNumRule * DuplicateNumRuleImpl(const SwNumRule *pRule); + + /// check if a new abstractNum is needed for this list + sal_uInt16 DuplicateAbsNum(OUString const& rListId, + SwNumRule const& rAbstractRule); + + + /// Create a overriding numbering definition (if it does not yet exist) + /// @return index of the overriding numbering definition + sal_uInt16 OverrideNumRule(SwNumRule const& rExistingRule, + OUString const& rListId, + SwNumRule const& rAbstractRule); + + /// Store list level overrides (restart of list) + void AddListLevelOverride(sal_uInt16 nListId, + sal_uInt16 nLevelNum, + sal_uInt16 nStartAt); + + /// Access to the attribute output class. + virtual AttributeOutputBase& AttrOutput() const = 0; + + /// Access to the sections/headers/footres. + virtual MSWordSections& Sections() const = 0; + + /// Determines if the import filter already quoted fields or not. + virtual bool FieldsQuoted() const = 0; + + /// Determines the Section Breaks are to be added for TOX Section + virtual bool AddSectionBreaksForTOX() const = 0; + + /// Used to filter out attributes that can be e.g. written to .doc but not to .docx + virtual bool ignoreAttributeForStyleDefaults( sal_uInt16 /*nWhich*/ ) const { return false; } + + /// If saving page break is preferred as a paragraph attribute (yes) or as a special character (no). + virtual bool PreferPageBreakBefore() const = 0; + + /// Guess the script (asian/western). + /// + /// Sadly word does not have two different sizes for asian font size and + /// western font size, it has two different fonts, but not sizes, so we + /// have to use our guess as to the script used and disable the export of + /// one type. The same occurs for font weight and posture (bold and + /// italic). + /// + /// In addition WW7- has only one character language identifier while WW8+ + /// has two + virtual bool CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich ) = 0; + + virtual void AppendBookmarks( const SwTextNode& rNd, sal_Int32 nCurrentPos, sal_Int32 nLen, const SwRedlineData* pSwRedline = nullptr ) = 0; + + virtual void AppendBookmark( const OUString& rName ) = 0; + + virtual void AppendAnnotationMarks( const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, sal_Int32 nLen ) = 0; + + virtual void AppendSmartTags(SwTextNode& /*rTextNode*/) { } + + //For i120928,add this interface to export graphic of bullet + virtual void ExportGrfBullet(const SwTextNode& rNd) = 0; + + // FIXME probably a hack... + virtual void WriteCR( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner = ww8::WW8TableNodeInfoInner::Pointer_t() ) = 0; + + // FIXME definitely a hack, must not be here - it can't do anything + // sensible for docx + virtual void WriteChar( sal_Unicode c ) = 0; + + /// Output attributes. + void OutputFormat( const SwFormat& rFormat, bool bPapFormat, bool bChpFormat, bool bFlyFormat = false ); + + /// Getter for pISet. + const SfxItemSet* GetCurItemSet() const { return m_pISet; } + + /// Setter for pISet. + void SetCurItemSet( const SfxItemSet* pS ) { m_pISet = pS; } + + /// Remember some of the members so that we can recurse in WriteText(). + virtual void SaveData( SwNodeOffset nStt, SwNodeOffset nEnd ); + + /// Restore what was saved in SaveData(). + virtual void RestoreData(); + + /// The return value indicates, if a follow page desc is written. + bool OutputFollowPageDesc( const SfxItemSet* pSet, + const SwTextNode* pNd ); + + /// Write header/footer text. + void WriteHeaderFooterText( const SwFormat& rFormat, bool bHeader); + + /// Format of the section. + static const SwSectionFormat* GetSectionFormat( const SwNode& rNd ); + + /// Line number of the section start. + static sal_uLong GetSectionLineNo( const SfxItemSet* pSet, const SwNode& rNd ); + + /// Start new section. + void OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen = false ); + + /// Write section properties. + /// + /// pA is ignored for docx. + void SectionProperties( const WW8_SepInfo& rSectionInfo, WW8_PdAttrDesc* pA = nullptr ); + + /// Output the numbering table. + virtual void WriteNumbering() = 0; + + /// Write static data of SwNumRule - LSTF + void NumberingDefinitions(); + + /// Write all Levels for all SwNumRules - LVLF + void AbstractNumberingDefinitions(); + + /// Write one numbering level + void NumberingLevel(SwNumRule const& rRule, sal_uInt8 nLvl); + + // Convert the bullet according to the font. + void SubstituteBullet( OUString& rNumStr, rtl_TextEncoding& rChrSet, + OUString& rFontName ) const; + + /// Setup the pA's info. + virtual void SetupSectionPositions( WW8_PdAttrDesc* /*pA*/ ) {} + + /// Top node of host page when in header/footer. + void SetHdFtPageRoot( const SwTextNode *pNd ) { m_pTopNodeOfHdFtPage = pNd; } + + /// Top node of host page when in header/footer. + const SwTextNode *GetHdFtPageRoot() const { return m_pTopNodeOfHdFtPage; } + + /// Output the actual headers and footers. + virtual void WriteHeadersFooters( sal_uInt8 nHeadFootFlags, + const SwFrameFormat& rFormat, const SwFrameFormat& rLeftHeaderFormat, const SwFrameFormat& rLeftFooterFormat, const SwFrameFormat& rFirstPageFormat, + sal_uInt8 nBreakCode, bool bEvenAndOddHeaders) = 0; + + /// Write the field + virtual void OutputField( const SwField* pField, ww::eField eFieldType, + const OUString& rFieldCmd, FieldFlags nMode = FieldFlags::All ) = 0; + + /// Write the data of the form field + virtual void WriteFormData( const ::sw::mark::IFieldmark& rFieldmark ) = 0; + virtual void WriteHyperlinkData( const ::sw::mark::IFieldmark& rFieldmark ) = 0; + + virtual void DoComboBox(const OUString &rName, + const OUString &rHelp, + const OUString &ToolTip, + const OUString &rSelected, + const css::uno::Sequence<OUString> &rListItems) = 0; + + virtual void DoFormText(const SwInputField * pField) = 0; + + static bool NoPageBreakSection( const SfxItemSet *pSet ); + + // Compute the number format for WW dates + bool GetNumberFormat(const SwField& rField, OUString& rStr); + + virtual sal_uInt64 ReplaceCr( sal_uInt8 nChar ) = 0; + + const SfxPoolItem* HasItem( sal_uInt16 nWhich ) const; + template<class T> const T* HasItem(TypedWhichId<T> nWhich) const + { + return static_cast<const T*>(HasItem(sal_uInt16(nWhich))); + } + + /// Returns the index of a picture bullet, used in numberings. + int GetGrfIndex(const SvxBrushItem& rBrush); + + enum ExportFormat { DOC = 0, RTF = 1, DOCX = 2}; + virtual ExportFormat GetExportFormat() const = 0; + +protected: + /// Format-dependent part of the actual export. + virtual ErrCode ExportDocument_Impl() = 0; + + /// Get the next position in the text node to output + sal_Int32 GetNextPos( SwWW8AttrIter const * pAttrIter, const SwTextNode& rNode, sal_Int32 nCurrentPos ); + + /// Update the information for GetNextPos(). + void UpdatePosition( SwWW8AttrIter* pAttrIter, sal_Int32 nCurrentPos ); + + /// Output SwTextNode + virtual void OutputTextNode( SwTextNode& ); + + /// Setup the chapter fields (maChapterFieldLocs). + void GatherChapterFields(); + + void AddLinkTarget( std::u16string_view rURL ); + void CollectOutlineBookmarks( const SwDoc &rDoc ); + + bool SetCurrentPageDescFromNode(const SwNode &rNd); + bool ContentContainsChapterField(const SwFormatContent &rContent) const; + bool FormatHdFtContainsChapterField(const SwFrameFormat &rFormat) const; + + virtual void SectionBreaksAndFrames( const SwTextNode& rNode ) = 0; + + virtual void PrepareNewPageDesc( const SfxItemSet* pSet, + const SwNode& rNd, + const SwFormatPageDesc* pNewPgDescFormat, + const SwPageDesc* pNewPgDesc, + bool bExtraPageBreak = false ) = 0; + + /// Return value indicates if an inherited outline numbering is suppressed. + virtual bool DisallowInheritingOutlineNumbering(const SwFormat &rFormat) = 0; + + /// Output SwStartNode + void OutputStartNode( const SwStartNode& ); + + /// Output SwEndNode + virtual void OutputEndNode( const SwEndNode& ); + + /// Output SwGrfNode + virtual void OutputGrfNode( const SwGrfNode& ) = 0; + + /// Output SwOLENode + virtual void OutputOLENode( const SwOLENode& ) = 0; + + virtual void OutputLinkedOLE( const OUString& ) = 0; + + /// Output SwSectionNode + void OutputSectionNode( const SwSectionNode& ); + static void UpdateTocSectionNodeProperties(const SwSectionNode& rSectionNode); + + virtual void AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum ) = 0; + + /// Call the right (virtual) function according to the type of the item. + /// + /// One of OutputTextNode(), OutputGrfNode(), or OutputOLENode() + void OutputContentNode( SwContentNode& ); + + /// Find the nearest bookmark from the current position. + /// + /// Returns false when there is no bookmark. + bool NearestBookmark( sal_Int32& rNearest, const sal_Int32 nCurrentPos, bool bNextPositionOnly ); + + void GetSortedBookmarks( const SwTextNode& rNd, sal_Int32 nCurrentPos, sal_Int32 nLen ); + + bool GetBookmarks( const SwTextNode& rNd, sal_Int32 nStt, sal_Int32 nEnd, + IMarkVector& rArr ); + + /// Find the nearest annotation mark from the current position. + /// + void NearestAnnotationMark( sal_Int32& rNearest, const sal_Int32 nCurrentPos, bool bNextPositionOnly ); + + void GetSortedAnnotationMarks( const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, sal_Int32 nLen ); + + bool GetAnnotationMarks( const SwWW8AttrIter& rAttrs, sal_Int32 nStt, sal_Int32 nEnd, + IMarkVector& rArr ); + + const NfKeywordTable & GetNfKeywordTable(); + + void SetCurPam(SwNodeOffset nStt, SwNodeOffset nEnd); + + /// Get background color of the document, if there is one. + std::unique_ptr<SvxBrushItem> getBackground(); + /// Populates m_vecBulletPic with all the bullet graphics used by numberings. + int CollectGrfsOfBullets(); + /// Write the numbering picture bullets. + void BulletDefinitions(); + + bool NeedSectionBreak( const SwNode& rNd ) const; + bool NeedTextNodeSplit( const SwTextNode& rNd, SwSoftPageBreakList& pList ) const; + + std::vector<const Graphic*> m_vecBulletPic; ///< Vector to record all the graphics of bullets + +public: + MSWordExportBase(SwDoc& rDocument, std::shared_ptr<SwUnoCursor> & pCurrentPam, SwPaM* pOriginalPam); + virtual ~MSWordExportBase(); + + // TODO move as much as possible here from WW8Export! ;-) + + static void CorrectTabStopInSet( SfxItemSet& rSet, sal_Int32 nAbsLeft ); + +private: + MSWordExportBase( const MSWordExportBase& ) = delete; + MSWordExportBase& operator=( const MSWordExportBase& ) = delete; +}; + +/// The writer class that gets called for the WW8 filter. +class SwWW8Writer: public StgWriter +{ +// friends to get access to m_pExport +// FIXME avoid that, this is probably not what we want +// (if yes, remove the friends, and provide here a GetExport() method) +friend void WW8_WrtRedlineAuthor::Write(Writer &rWrt); + + WW8Export *m_pExport; + SfxMedium *mpMedium; + +public: + SwWW8Writer(std::u16string_view rFltName, const OUString& rBaseURL); + virtual ~SwWW8Writer() override; + + virtual ErrCode WriteStorage() override; + virtual ErrCode WriteMedium( SfxMedium& ) override; + + // TODO most probably we want to be able to get these in + // MSExportFilterBase + using Writer::getIDocumentSettingAccess; + +public: + static void InsUInt16(ww::bytes &rO, sal_uInt16 n); + static void InsUInt32(ww::bytes &rO, sal_uInt32 n); + static void InsAsString16(ww::bytes &rO, const OUString& rStr); + static void InsAsString8(ww::bytes & O, std::u16string_view rStr, + rtl_TextEncoding eCodeSet); + + static sal_uLong FillUntil( SvStream& rStrm, sal_uLong nEndPos = 0 ); + static void FillCount( SvStream& rStrm, sal_uLong nCount ); + + static void WriteShort( SvStream& rStrm, sal_Int16 nVal ) { rStrm.WriteInt16( nVal ); } + static void WriteShort( SvStream& rStrm, sal_uLong nPos, sal_Int16 nVal ); + + static void WriteLong( SvStream& rStrm, sal_Int32 nVal ) { rStrm.WriteInt32( nVal ); } + static void WriteLong( SvStream& rStrm, sal_uLong nPos, sal_Int32 nVal ); + + static void WriteString16(SvStream& rStrm, const OUString& rStr, + bool bAddZero); + static void WriteString8(SvStream& rStrm, std::u16string_view rStr, + bool bAddZero, rtl_TextEncoding eCodeSet); + + static void WriteString_xstz(SvStream& rStrm, const OUString& rStr, bool bAddZero); + + bool InitStd97CodecUpdateMedium( ::msfilter::MSCodec_Std97& rCodec ); + + using StgWriter::Write; + virtual ErrCode Write( SwPaM&, SfxMedium&, const OUString* ) override; + //Seems not an expected to provide method to access the private member + SfxMedium* GetMedia() { return mpMedium; } + +private: + SwWW8Writer(const SwWW8Writer&) = delete; + SwWW8Writer& operator=(const SwWW8Writer&) = delete; + ErrCode WriteStorageImpl(); +}; + +/// Exporter of the binary Word file formats. +class WW8Export : public MSWordExportBase +{ +public: + std::unique_ptr<ww::bytes> m_pO; ///< Buffer + + SvStream *m_pTableStrm, *m_pDataStrm; ///< Streams for WW97 Export + + std::unique_ptr<WW8Fib> m_pFib; ///< File Information Block + std::unique_ptr<WW8Dop> m_pDop; ///< Document Properties + std::unique_ptr<WW8_WrPlcFootnoteEdn> m_pFootnote; ///< Footnotes - structure to remember them, and output + std::unique_ptr<WW8_WrPlcFootnoteEdn> m_pEdn; ///< Endnotes - structure to remember them, and output + std::unique_ptr<WW8_WrPlcSepx> m_pSepx; ///< Sections/headers/footers + + bool m_bDot; ///< Template or document. + +protected: + SwWW8Writer *m_pWriter; ///< Pointer to the writer + std::unique_ptr<WW8AttributeOutput> m_pAttrOutput; ///< Converting attributes to stream data + +private: + tools::SvRef<SotStorage> m_xEscherStg; /// memory leak #i120098#, to hold the reference to unnamed SotStorage obj + +public: + /// Access to the attribute output class. + virtual AttributeOutputBase& AttrOutput() const override; + + /// Access to the sections/headers/footres. + virtual MSWordSections& Sections() const override; + + virtual bool PreferPageBreakBefore() const override { return true; } + + virtual bool FieldsQuoted() const override { return false; } + + virtual bool AddSectionBreaksForTOX() const override { return false; } +private: + /// Format-dependent part of the actual export. + virtual ErrCode ExportDocument_Impl() override; + + void PrepareStorage(); + void WriteFkpPlcUsw(); + void WriteMainText(); + void StoreDoc1(); + + /// Output the numbering table. + virtual void WriteNumbering() override; + + void OutOverrideListTab(); + void OutListNamesTab(); + + void RestoreMacroCmds(); + + void DoComboBox(css::uno::Reference<css::beans::XPropertySet> const & xPropSet); + +public: + + /// Setup the pA's info. + virtual void SetupSectionPositions( WW8_PdAttrDesc* pA ) override; + + bool MiserableFormFieldExportHack(const SwFrameFormat& rFrameFormat); + + SwMSConvertControls& GetOCXExp() { return *m_pOCXExp; } + void ExportDopTypography(WW8DopTypography &rTypo); + + sal_uInt16 AddRedlineAuthor( std::size_t nId ); + + void WriteFootnoteBegin( const SwFormatFootnote& rFootnote, ww::bytes* pO = nullptr ); + void WritePostItBegin( ww::bytes* pO = nullptr ); + const SvxBrushItem* GetCurrentPageBgBrush() const; + std::shared_ptr<SvxBrushItem> TrueFrameBgBrush(const SwFrameFormat &rFlyFormat) const; + + void AppendFlyInFlys(const ww8::Frame& rFrameFormat, const Point& rNdTopLeft); + void WriteOutliner(const OutlinerParaObject& rOutliner, sal_uInt8 nTyp); + void WriteSdrTextObj(const SdrTextObj& rObj, sal_uInt8 nTyp); + + sal_uInt32 GetSdrOrdNum( const SwFrameFormat& rFormat ) const; + void CreateEscher(); + void WriteEscher(); + + /// Write the field + virtual void OutputField( const SwField* pField, ww::eField eFieldType, + const OUString& rFieldCmd, FieldFlags nMode = FieldFlags::All ) override; + + void StartCommentOutput( std::u16string_view rName ); + void EndCommentOutput( std::u16string_view rName ); + void OutGrf(const ww8::Frame &rFrame); + bool TestOleNeedsGraphic(const SwAttrSet& rSet, tools::SvRef<SotStorage> const& xOleStg, + const tools::SvRef<SotStorage>& xObjStg, OUString const& rStorageName, + SwOLENode* pOLENd); + + virtual void AppendBookmarks( const SwTextNode& rNd, sal_Int32 nCurrentPos, sal_Int32 nLen, const SwRedlineData* pRedlineData = nullptr ) override; + virtual void AppendBookmark( const OUString& rName ) override; + void AppendBookmarkEndWithCorrection( const OUString& rName ); + + virtual void AppendAnnotationMarks( const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, sal_Int32 nLen ) override; + + virtual void AppendSmartTags(SwTextNode& rTextNode) override; + + virtual void ExportGrfBullet(const SwTextNode& rNd) override; + void OutGrfBullets(const ww8::Frame &rFrame); + + void MoveFieldMarks(WW8_CP nFrom, WW8_CP nTo); + + void WriteAsStringTable(const std::vector<OUString>&, sal_Int32& rfcSttbf, + sal_Int32& rlcbSttbf); + + virtual sal_uInt64 ReplaceCr( sal_uInt8 nChar ) override; + + virtual void WriteCR( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner = ww8::WW8TableNodeInfoInner::Pointer_t() ) override; + void WriteChar( sal_Unicode c ) override; + + void OutSwString(const OUString&, sal_Int32 nStt, sal_Int32 nLen); + + WW8_CP Fc2Cp( sal_uLong nFc ) const { return m_pPiece->Fc2Cp( nFc ); } + + // some partly static semi-internal function declarations + + void OutSprmBytes( sal_uInt8* pBytes, sal_uInt16 nSiz ) + { m_pO->insert( m_pO->end(), pBytes, pBytes+nSiz ); } + + virtual void SectionBreaksAndFrames( const SwTextNode& rNode ) override; + + /// Helper method for OutputSectionBreaks() and OutputFollowPageDesc(). + // #i76300# + virtual void PrepareNewPageDesc( const SfxItemSet* pSet, + const SwNode& rNd, + const SwFormatPageDesc* pNewPgDescFormat, + const SwPageDesc* pNewPgDesc, + bool bExtraPageBreak = false ) override; + + static void Out_BorderLine(ww::bytes& rO, const ::editeng::SvxBorderLine* pLine, + sal_uInt16 nDist, sal_uInt16 nSprmNo, sal_uInt16 nSprmNoVer9, + bool bShadow); + + void Out_SwFormatBox(const SvxBoxItem& rBox, bool bShadow); + static void Out_SwFormatTableBox( ww::bytes& rO, const SvxBoxItem * rBox ); + void Out_CellRangeBorders(const SvxBoxItem * pBox, sal_uInt8 nStart, + sal_uInt8 nLimit); + static bool TransBrush(const Color& rCol, WW8_SHD& rShd); + static WW8_BRCVer9 TranslateBorderLine(const ::editeng::SvxBorderLine& pLine, + sal_uInt16 nDist, bool bShadow); + + // #i77805# - new return value indicates, if an inherited outline numbering is suppressed + virtual bool DisallowInheritingOutlineNumbering(const SwFormat &rFormat) override; + + unsigned int GetHdFtIndex() const { return m_nHdFtIndex; } + void SetHdFtIndex(unsigned int nHdFtIndex) { m_nHdFtIndex = nHdFtIndex; } + void IncrementHdFtIndex() { ++m_nHdFtIndex; } + + /** + * Converts the SVX numbering type to MSONFC. + * + * This is used for section, footnote and endnote numbering purposes. + */ + static sal_uInt8 GetNumId( sal_uInt16 eNumType ); + + /// Guess the script (asian/western). + virtual bool CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich ) override; + + SwTwips CurrentPageWidth(SwTwips &rLeft, SwTwips &rRight) const; + + /// Nasty swap for bidi if necessary + void MiserableRTLFrameFormatHack(SwTwips &rLeft, SwTwips &rRight, + const ww8::Frame &rFrameFormat); + + void InsUInt16( sal_uInt16 n ) { SwWW8Writer::InsUInt16( *m_pO, n ); } + void InsInt16(sal_Int16 n) { InsUInt16(sal_uInt16(n)); } + void InsUInt32( sal_uInt32 n ) { SwWW8Writer::InsUInt32( *m_pO, n ); } + void WriteStringAsPara( const OUString& rText ); + + /// Setup the exporter. + WW8Export( SwWW8Writer *pWriter, + SwDoc& rDocument, std::shared_ptr<SwUnoCursor> & pCurrentPam, SwPaM* pOriginalPam, + bool bDot ); + virtual ~WW8Export() override; + + virtual void DoComboBox(const OUString &rName, + const OUString &rHelp, + const OUString &ToolTip, + const OUString &rSelected, + const css::uno::Sequence<OUString> &rListItems) override; + + virtual void DoFormText(const SwInputField * pField) override; + + void GetCurrentItems(ww::bytes &rItems) const; + + /// Write the data of the form field + virtual void WriteFormData( const ::sw::mark::IFieldmark& rFieldmark ) override; + virtual void WriteHyperlinkData( const ::sw::mark::IFieldmark& rFieldmark ) override; + + /// Fields. + WW8_WrPlcField* CurrentFieldPlc() const; + + SwWW8Writer& GetWriter() const { return *m_pWriter; } + SvStream& Strm() const { return m_pWriter->Strm(); } + + /// Remember some of the members so that we can recurse in WriteText(). + virtual void SaveData( SwNodeOffset nStt, SwNodeOffset nEnd ) override; + + /// Restore what was saved in SaveData(). + virtual void RestoreData() override; + + /// Output the actual headers and footers. + virtual void WriteHeadersFooters( sal_uInt8 nHeadFootFlags, + const SwFrameFormat& rFormat, const SwFrameFormat& rLeftHeaderFormat, const SwFrameFormat& rLeftFooterFormat, const SwFrameFormat& rFirstPageFormat, + sal_uInt8 nBreakCode, bool bEvenAndOddHeaders) override; + + virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOC; } + +protected: + /// Output SwGrfNode + virtual void OutputGrfNode( const SwGrfNode& ) override; + + /// Output SwOLENode + virtual void OutputOLENode( const SwOLENode& ) override; + + virtual void OutputLinkedOLE( const OUString& ) override; + + virtual void AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum ) override; + +private: + WW8Export(const WW8Export&) = delete; + WW8Export& operator=(const WW8Export&) = delete; +}; + +class WW8_WrPlcSubDoc // double Plc for Footnotes/Endnotes and Postits +{ +private: + WW8_WrPlcSubDoc(const WW8_WrPlcSubDoc&) = delete; + WW8_WrPlcSubDoc& operator=(const WW8_WrPlcSubDoc&) = delete; +protected: + std::vector<WW8_CP> m_aCps; + std::vector<const void*> m_aContent; // PTRARR of SwFormatFootnote/PostIts/.. + std::vector<const SwFrameFormat*> m_aSpareFormats; // a backup for aContent: if there's no SdrObject, stores the fmt directly here + std::unique_ptr<WW8_WrPlc0> m_pTextPos; // positions of the individual texts + + WW8_WrPlcSubDoc(); + virtual ~WW8_WrPlcSubDoc(); + + bool WriteGenericText( WW8Export& rWrt, sal_uInt8 nTTyp, WW8_CP& rCount ); + void WriteGenericPlc( WW8Export& rWrt, sal_uInt8 nTTyp, WW8_FC& rTextStt, + sal_Int32& rTextCnt, WW8_FC& rRefStt, sal_Int32& rRefCnt ) const; + + virtual const std::vector<sal_uInt32>* GetShapeIdArr() const; +}; + +// double Plc for Footnotes/Endnotes +class WW8_WrPlcFootnoteEdn : public WW8_WrPlcSubDoc +{ +private: + sal_uInt8 m_nTyp; + + WW8_WrPlcFootnoteEdn(const WW8_WrPlcFootnoteEdn&) = delete; + WW8_WrPlcFootnoteEdn& operator=(WW8_WrPlcFootnoteEdn const &) = delete; +public: + explicit WW8_WrPlcFootnoteEdn( sal_uInt8 nTTyp ) : m_nTyp( nTTyp ) {} + + bool WriteText( WW8Export& rWrt ); + void WritePlc( WW8Export& rWrt ) const; + + void Append( WW8_CP nCp, const SwFormatFootnote& rFootnote ); +}; + +struct WW8_Annotation +{ + const OutlinerParaObject* mpRichText; + OUString msSimpleText; + OUString msOwner; + OUString m_sInitials; + DateTime maDateTime; + WW8_CP m_nRangeStart, m_nRangeEnd; + bool m_bIgnoreEmpty = true; + WW8_Annotation(const SwPostItField* pPostIt, WW8_CP nRangeStart, WW8_CP nRangeEnd); + explicit WW8_Annotation(const SwRedlineData* pRedline); + /// An annotation has a range if start != end or the m_bIgnoreEmpty flag is cleared. + bool HasRange() const; +}; + +class WW8_WrPlcAnnotations : public WW8_WrPlcSubDoc // double Plc for Postits +{ +private: + WW8_WrPlcAnnotations(const WW8_WrPlcAnnotations&) = delete; + WW8_WrPlcAnnotations& operator=(WW8_WrPlcAnnotations const &) = delete; + o3tl::sorted_vector<const SwRedlineData*> maProcessedRedlines; + + std::map<const OUString, std::pair<WW8_CP, bool>> m_aRangeStartPositions; +public: + WW8_WrPlcAnnotations() {} + virtual ~WW8_WrPlcAnnotations() override; + + void AddRangeStartPosition(const OUString& rName, WW8_CP nStartCp, bool bIgnoreEmpty); + void Append( WW8_CP nCp, const SwPostItField* pPostIt ); + void Append( WW8_CP nCp, const SwRedlineData* pRedLine ); + bool IsNewRedlineComment( const SwRedlineData* pRedLine ); + bool WriteText( WW8Export& rWrt ); + void WritePlc( WW8Export& rWrt ) const; +}; + +class WW8_WrPlcTextBoxes : public WW8_WrPlcSubDoc // double Plc for Textboxes +{ // Frame/DrawTextboxes! +private: + sal_uInt8 m_nTyp; + std::vector<sal_uInt32> m_aShapeIds; // VARARR of ShapeIds for the SwFrameFormats + virtual const std::vector<sal_uInt32>* GetShapeIdArr() const override; + + WW8_WrPlcTextBoxes(const WW8_WrPlcTextBoxes&) = delete; + WW8_WrPlcTextBoxes& operator=(WW8_WrPlcTextBoxes const &) = delete; +public: + explicit WW8_WrPlcTextBoxes( sal_uInt8 nTTyp ) : m_nTyp( nTTyp ) {} + + bool WriteText( WW8Export& rWrt ); + void WritePlc( WW8Export& rWrt ) const; + void Append( const SdrObject& rObj, sal_uInt32 nShapeId ); + void Append( const SwFrameFormat* pFormat, sal_uInt32 nShapeId ); + sal_uInt16 Count() const { return m_aContent.size(); } + sal_uInt16 GetPos( const void* p ) const + { + std::vector<const void*>::const_iterator it + = std::find( m_aContent.begin(), m_aContent.end(), p ); + return it == m_aContent.end() ? USHRT_MAX : it - m_aContent.begin(); + } +}; + +class WW8_WrPlcPn // Plc for Page Numbers +{ +private: + WW8Export& m_rWrt; + // Plc for Chpx and Papx ( incl PN-Plc ) + std::vector<std::unique_ptr<WW8_WrFkp>> m_Fkps; + sal_uInt16 m_nFkpStartPage; + ePLCFT m_ePlc; + + WW8_WrPlcPn(const WW8_WrPlcPn&) = delete; + WW8_WrPlcPn& operator=(const WW8_WrPlcPn&) = delete; +public: + WW8_WrPlcPn( WW8Export& rWrt, ePLCFT ePl, WW8_FC nStartFc ); + ~WW8_WrPlcPn(); + void AppendFkpEntry(WW8_FC nEndFc,short nVarLen = 0,const sal_uInt8* pSprms = nullptr); + void WriteFkps(); + void WritePlc(); + sal_uInt8 *CopyLastSprms(sal_uInt8 &rLen); +}; + +// class WW8_WrPlc1 is only used for fields +class WW8_WrPlc1 +{ +private: + std::vector<WW8_CP> m_aPos; + std::unique_ptr<sal_uInt8[]> m_pData; // content ( structures ) + sal_uLong m_nDataLen; + sal_uInt16 m_nStructSiz; + + WW8_WrPlc1(const WW8_WrPlc1&) = delete; + WW8_WrPlc1& operator=(const WW8_WrPlc1&) = delete; +protected: + sal_uInt16 Count() const { return m_aPos.size(); } + void Write( SvStream& rStrm ); + WW8_CP Prev() const; +public: + explicit WW8_WrPlc1( sal_uInt16 nStructSz ); + ~WW8_WrPlc1(); + void Append( WW8_CP nCp, const void* pData ); + void Finish( sal_uLong nLastCp, sal_uLong nStartCp ); +}; + +// class WW8_WrPlcField is for fields +class WW8_WrPlcField : public WW8_WrPlc1 +{ +private: + sal_uInt8 m_nTextTyp; + sal_uInt16 m_nResults; + + WW8_WrPlcField(const WW8_WrPlcField&) = delete; + WW8_WrPlcField& operator=(const WW8_WrPlcField&) = delete; +public: + WW8_WrPlcField( sal_uInt16 nStructSz, sal_uInt8 nTTyp ) + : WW8_WrPlc1( nStructSz ), m_nTextTyp( nTTyp ), m_nResults(0) + {} + void Write( WW8Export& rWrt ); + void ResultAdded() { ++m_nResults; } + sal_uInt16 ResultCount() const { return m_nResults; } +}; + +class WW8_WrMagicTable : public WW8_WrPlc1 +{ +private: + WW8_WrMagicTable(const WW8_WrMagicTable&) = delete; + WW8_WrMagicTable& operator=(const WW8_WrMagicTable&) = delete; +public: + WW8_WrMagicTable() : WW8_WrPlc1( 4 ) {Append(0,0);} + void Append( WW8_CP nCp, sal_uLong nData ); + void Write( WW8Export& rWrt ); +}; + +class GraphicDetails +{ +public: + ww8::Frame maFly; // surrounding FlyFrames + sal_uLong mnPos; // FilePos of the graphics + sal_uInt16 mnWid; // Width of the graphics + sal_uInt16 mnHei; // Height of the graphics + + GraphicDetails(const ww8::Frame &rFly, sal_uInt16 nWid, sal_uInt16 nHei) + : maFly(rFly), mnPos(0), mnWid(nWid), mnHei(nHei) + {} + + bool operator==(const GraphicDetails& rIn) const + { + return ( + (mnWid == rIn.mnWid) && (mnHei == rIn.mnHei) && + (maFly.RefersToSameFrameAs(rIn.maFly)) + ); + } +}; + +// class SwWW8WrGrf collects graphics and issues them +class SwWW8WrGrf +{ +private: + /// for access to the variables + WW8Export& m_rWrt; + + std::vector<GraphicDetails> maDetails; + sal_uInt16 mnIdx; // index in file positions + + static void WritePICFHeader(SvStream& rStrm, const ww8::Frame &rFly, + sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, + const SwAttrSet* pAttrSet = nullptr); + void WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem); + void WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rNd, + const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight); + + static void WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight); + void WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight); + + SwWW8WrGrf(const SwWW8WrGrf&) = delete; + SwWW8WrGrf& operator=(const SwWW8WrGrf&) = delete; +public: + explicit SwWW8WrGrf( WW8Export& rW ) : m_rWrt( rW ), mnIdx( 0 ) {} + void Insert(const ww8::Frame &rFly); + void Write(); + sal_uLong GetFPos() + { return (mnIdx < maDetails.size()) ? maDetails[mnIdx++].mnPos : 0; } +}; + +/** The class MSWordAttrIter is a helper class to build the Fkp.chpx. + This is a base class to output the SwTextAttrs and the EditEngineTextAttrs. +*/ +class MSWordAttrIter +{ +private: + MSWordAttrIter* m_pOld; + MSWordAttrIter(const MSWordAttrIter&) = delete; + MSWordAttrIter& operator=(const MSWordAttrIter&) = delete; +protected: + MSWordExportBase& m_rExport; +public: + explicit MSWordAttrIter( MSWordExportBase& rExport ); + virtual ~MSWordAttrIter(); + + virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const = 0; + template<class T> const T* HasTextItem( TypedWhichId<T> nWhich ) const + { + return static_cast<const T*>(HasTextItem(sal_uInt16(nWhich))); + } + virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const = 0; +}; + +/// Used to export formatted text associated to drawings. +class MSWord_SdrAttrIter : public MSWordAttrIter +{ +private: + const EditTextObject* m_pEditObj; + const SfxItemPool* m_pEditPool; + std::vector<EECharAttrib> m_aTextAtrArr; + std::vector<const EECharAttrib*> m_aChrTextAtrArr; + std::vector<rtl_TextEncoding> m_aChrSetArr; + sal_Int32 m_nPara; + sal_Int32 m_nCurrentSwPos; + sal_Int32 m_nTmpSwPos; // for HasItem() + rtl_TextEncoding m_eNdChrSet; + sal_uInt16 m_nScript; + sal_uInt8 mnTyp; + + sal_Int32 SearchNext( sal_Int32 nStartPos ); + void SetCharSet(const EECharAttrib& rTextAttr, bool bStart); + + void SetItemsThatDifferFromStandard(bool bCharAttr, SfxItemSet& rSet); + + MSWord_SdrAttrIter(const MSWord_SdrAttrIter&) = delete; + MSWord_SdrAttrIter& operator=(const MSWord_SdrAttrIter&) = delete; +public: + MSWord_SdrAttrIter( MSWordExportBase& rWr, const EditTextObject& rEditObj, + sal_uInt8 nType ); + void NextPara( sal_Int32 nPar ); + void OutParaAttr(bool bCharAttr, const std::set<sal_uInt16>* pWhichsToIgnore = nullptr); + void OutEEField(const SfxPoolItem& rHt); + + bool IsTextAttr(sal_Int32 nSwPos); + + void NextPos() { if ( m_nCurrentSwPos < SAL_MAX_INT32 ) m_nCurrentSwPos = SearchNext( m_nCurrentSwPos + 1 ); } + + void OutAttr( sal_Int32 nSwPos ); + virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const override; + virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const override; + sal_Int32 WhereNext() const { return m_nCurrentSwPos; } + rtl_TextEncoding GetNextCharSet() const; + rtl_TextEncoding GetNodeCharSet() const { return m_eNdChrSet; } +}; + +// class SwWW8AttrIter is a helper for constructing the Fkp.chpx. +// Only character attributes are considered; paragraph attributes do not need this treatment. +// The paragraph and text attributes of the Writer are passed, and +// Where() returns the next position where the attributes change. +// IsTextAtr() tells if, at the position returned by Where(), there is +// an attribute without end and with \xff in the text. +// Using OutAttr(), the attributes on the passed SwPos are returned. +class SwWW8AttrIter : public MSWordAttrIter +{ +private: + const SwTextNode& m_rNode; + + sw::util::CharRuns maCharRuns; + sw::util::CharRuns::const_iterator maCharRunIter; + + rtl_TextEncoding meChrSet; + sal_uInt16 mnScript; + bool mbCharIsRTL; + + const SwRangeRedline* m_pCurRedline; + sal_Int32 m_nCurrentSwPos; + SwRedlineTable::size_type m_nCurRedlinePos; + + bool mbParaIsRTL; + + const SwFormatDrop &mrSwFormatDrop; + + ww8::Frames maFlyFrames; // #i2916# + ww8::FrameIter maFlyIter; + + sal_Int32 SearchNext( sal_Int32 nStartPos ); + + void OutSwFormatRefMark(const SwFormatRefMark& rAttr); + + void IterToCurrent(); + + SwWW8AttrIter(const SwWW8AttrIter&) = delete; + SwWW8AttrIter& operator=(const SwWW8AttrIter&) = delete; + + void handleToggleProperty(SfxItemSet& rExportSet, const SwFormatCharFormat* pCharFormatItem, sal_uInt16 nWhich, const SfxPoolItem* pValue); +public: + SwWW8AttrIter( MSWordExportBase& rWr, const SwTextNode& rNd ); + + bool IsTextAttr( sal_Int32 nSwPos ) const; + bool IsExportableAttr(sal_Int32 nSwPos) const; + bool IncludeEndOfParaCRInRedlineProperties(sal_Int32 nPos) const; + bool IsDropCap( int nSwPos ); + bool RequiresImplicitBookmark(); + + void NextPos() { if ( m_nCurrentSwPos < SAL_MAX_INT32 ) m_nCurrentSwPos = SearchNext( m_nCurrentSwPos + 1 ); } + + void OutAttr(sal_Int32 nSwPos, bool bWriteCombinedChars); + virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const override; + virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const override; + int OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos); + const SwRedlineData* GetParagraphLevelRedline( ); + const SwRedlineData* GetRunLevelRedline( sal_Int32 nPos ); + FlyProcessingState OutFlys(sal_Int32 nSwPos); + bool HasFlysAt(sal_Int32 nSwPos) const; + + sal_Int32 WhereNext() const { return m_nCurrentSwPos; } + sal_uInt16 GetScript() const { return mnScript; } + bool IsParaRTL() const { return mbParaIsRTL; } + rtl_TextEncoding GetCharSet() const { return meChrSet; } + OUString GetSnippet(const OUString &rStr, sal_Int32 nCurrentPos, + sal_Int32 nLen) const; + const SwFormatDrop& GetSwFormatDrop() const { return mrSwFormatDrop; } + + bool IsWatermarkFrame(); + bool IsAnchorLinkedToThisNode( SwNodeOffset nNodePos ); + + void SplitRun( sal_Int32 nSplitEndPos ); + + const SwTextNode& GetNode() const { return m_rNode; } +}; + +/// Class to collect and output the styles table. +class MSWordStyles +{ + MSWordExportBase& m_rExport; + sal_uInt16 m_aHeadingParagraphStyles[MAXLEVEL]; + std::vector<SwFormat*> m_aFormatA; ///< Slot <-> Character and paragraph style array (0 for list styles). + sal_uInt16 m_nUsedSlots; + bool m_bListStyles; ///< If list styles are requested to be exported as well. + std::map<sal_uInt16, const SwNumRule*> m_aNumRules; ///< Slot <-> List style map. + + /// We need to build style id's for DOCX export; ideally we should roundtrip that, but this is good enough. + std::vector<OString> m_aStyleIds; + + /// Create the style table, called from the constructor. + void BuildStylesTable(); + + /// Based on pFormatA, fill in m_aStyleIds with unique, MS-like names. + void BuildStyleIds(); + + /// Get slot number during building the style table. + sal_uInt16 BuildGetSlot( const SwFormat& rFormat ); + sal_uInt16 BuildGetSlot( const SwNumRule& /*rNumRule*/ ) { return m_nUsedSlots++;} + + /// Return information about one style. + void GetStyleData( SwFormat* pFormat, bool& bFormatColl, sal_uInt16& nBase, sal_uInt16& nNext, sal_uInt16& nLink ); + + /// Outputs attributes of one style. + void WriteProperties( const SwFormat* pFormat, bool bPap, sal_uInt16 nPos, bool bInsDefCharSiz ); + + static sal_uInt16 GetWWId( const SwFormat& rFormat ); + + void SetStyleDefaults( const SwFormat& rFormat, bool bPap ); + + /// Outputs one style - called (in a loop) from OutputStylesTable(). + void OutputStyle( SwFormat* pFormat, sal_uInt16 nPos ); + void OutputStyle( const SwNumRule* pNumRule, sal_uInt16 nPos ); + + MSWordStyles( const MSWordStyles& ) = delete; + MSWordStyles& operator=( const MSWordStyles& ) = delete; + +public: + MSWordStyles( MSWordExportBase& rExport, bool bListStyles = false ); + ~MSWordStyles(); + + /// Output the styles table. + void OutputStylesTable(); + + /// Get id of the style (rFormat). + sal_uInt16 GetSlot( const SwFormat* pFormat ) const; + + /// create style id using only ASCII characters of the style name + static OString CreateStyleId(const OUString &rName); + + /// Get styleId of the nId-th style (nId is its position in pFormatA). + OString const & GetStyleId(sal_uInt16 nId) const; + + const SwFormat* GetSwFormat(sal_uInt16 nId) const { return m_aFormatA[nId]; } + /// Get numbering rule of the nId-th style + const SwNumRule* GetSwNumRule(sal_uInt16 nId) const; + sal_uInt16 GetHeadingParagraphStyleId(sal_uInt16 nLevel) const { return m_aHeadingParagraphStyles[ nLevel ]; } +}; + +#define MSWORD_MAX_STYLES_LIMIT 4091 + +sal_Int16 GetWordFirstLineOffset(const SwNumFormat &rFormat); +// A bit of a bag on the side for now +OUString FieldString(ww::eField eIndex); +OUString BookmarkToWord(std::u16string_view rBookmark, bool* pIsMove = nullptr, bool* pIsFrom = nullptr); + +class WW8SHDLong +{ + sal_uInt32 m_cvFore; + sal_uInt32 m_cvBack; + +public: + WW8SHDLong() : m_cvFore(0), m_cvBack(0) {} + + void Write(WW8Export & rExport); + void setCvFore(sal_uInt32 cvFore) { m_cvFore = cvFore; } + void setCvBack(sal_uInt32 cvBack) { m_cvBack = cvBack; } +}; + +#endif // INCLUDED_SW_SOURCE_FILTER_WW8_WRTWW8_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |