1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/embed/Aspects.hpp>
23 #include <hintids.hxx>
25 #include <officecfg/Office/Common.hxx>
26 #include <o3tl/any.hxx>
27 #include <com/sun/star/drawing/XShape.hpp>
28 #include <vcl/svapp.hxx>
29 #include <sot/storage.hxx>
30 #include <svl/itemiter.hxx>
31 #include <svl/stritem.hxx>
32 #include <svl/whiter.hxx>
33 #include <svx/svdobj.hxx>
34 #include <svx/svdotext.hxx>
35 #include <svx/svdpage.hxx>
36 #include <editeng/colritem.hxx>
37 #include <editeng/outlobj.hxx>
38 #include <editeng/editobj.hxx>
39 #include <editeng/brushitem.hxx>
40 #include <editeng/boxitem.hxx>
41 #include <editeng/lrspitem.hxx>
42 #include <editeng/ulspitem.hxx>
43 #include <editeng/fontitem.hxx>
44 #include <editeng/frmdiritem.hxx>
45 #include <editeng/flditem.hxx>
46 #include <editeng/shaditem.hxx>
47 #include <editeng/eeitem.hxx>
48 #include <editeng/formatbreakitem.hxx>
49 #include <svx/svdouno.hxx>
50 #include <svx/svdview.hxx>
51 #include <fmtcnct.hxx>
52 #include <fmtanchr.hxx>
53 #include <fmtsrnd.hxx>
54 #include <fmtornt.hxx>
55 #include <fmtfsize.hxx>
56 #include <fmtfollowtextflow.hxx>
58 #include <fmtcntnt.hxx>
59 #include <ndindex.hxx>
61 #include <drawdoc.hxx>
62 #include <IDocumentSettingAccess.hxx>
63 #include <IDocumentDrawModelAccess.hxx>
69 #include <pagedesc.hxx>
70 #include <poolfmt.hxx>
72 #include <breakit.hxx>
73 #include <com/sun/star/i18n/XBreakIterator.hpp>
74 #include <com/sun/star/lang/XServiceInfo.hpp>
75 #include "attributeoutputbase.hxx"
76 #include "writerhelper.hxx"
77 #include "writerwordglue.hxx"
81 #include "WW8FFData.hxx"
82 #include <com/sun/star/beans/XPropertySet.hpp>
83 #include <com/sun/star/form/XFormComponent.hpp>
84 #include <IDocumentStylePoolAccess.hxx>
85 #include <oox/ole/olehelper.hxx>
87 #include <frameformats.hxx>
88 #include <sfx2/sfxsids.hrc>
89 #include <o3tl/enumrange.hxx>
90 #include <o3tl/enumarray.hxx>
91 #include <sfx2/docfile.hxx>
92 #include <tools/UnitConversion.hxx>
96 using ::editeng::SvxBorderLine
;
97 using namespace com::sun::star
;
98 using namespace sw::util
;
99 using namespace sw::types
;
100 using ::com::sun::star::beans::XPropertySet
;
101 using ::com::sun::star::drawing::XShape
;
103 bool SwBasicEscherEx::IsRelUrl() const
105 bool bRelUrl
= false;
106 SfxMedium
* pMedium
= mrWrt
.GetWriter().GetMedia();
108 bRelUrl
= pMedium
->IsRemote()
109 ? officecfg::Office::Common::Save::URL::Internet::get()
110 : officecfg::Office::Common::Save::URL::FileSystem::get();
114 OUString
SwBasicEscherEx::GetBasePath() const
117 SfxMedium
* pMedium
= mrWrt
.GetWriter().GetMedia();
120 const SfxItemSet
* pPItemSet
= pMedium
->GetItemSet();
123 const SfxStringItem
* pPItem
= pPItemSet
->GetItem( SID_FILE_NAME
);
125 sDocUrl
= pPItem
->GetValue();
129 return sDocUrl
.copy(0, sDocUrl
.lastIndexOf('/') + 1);
132 OUString
SwBasicEscherEx::BuildFileName(sal_uInt16
& rnLevel
, bool& rbRel
, const OUString
& rUrl
)
134 OUString
aDosName( INetURLObject( rUrl
).getFSysPath( FSysStyle::Dos
) );
140 // try to convert to relative file name
141 OUString
aTmpName( aDosName
);
142 aDosName
= INetURLObject::GetRelURL( GetBasePath(), rUrl
,
143 INetURLObject::EncodeMechanism::WasEncoded
, INetURLObject::DecodeMechanism::WithCharset
);
145 if (aDosName
.startsWith(INET_FILE_SCHEME
))
147 // not converted to rel -> back to old, return absolute flag
151 else if (aDosName
.startsWith("./"))
153 aDosName
= aDosName
.copy(2);
157 while (aDosName
.startsWith("../"))
160 aDosName
= aDosName
.copy(3);
167 void SwBasicEscherEx::WriteHyperlinkWithinFly( SvMemoryStream
& rStrm
, const SwFormatURL
* pINetFormatArg
)
169 if ( !pINetFormatArg
) return;
171 const sal_uInt8 aGuidStdLink
[ 16 ] ={
172 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
173 const sal_uInt8 aGuidUrlMoniker
[ 16 ] = {
174 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
176 const sal_uInt8 aGuidFileMoniker
[ 16 ] = {
177 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
178 const sal_uInt8 aGuidFileTail
[] = {
179 0xFF, 0xFF, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00,
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
183 //const sal_uInt18 WW8_ID_HLINK = 0x01B8;
184 constexpr sal_uInt32 WW8_HLINK_BODY
= 0x00000001; /// Contains file link or URL.
185 constexpr sal_uInt32 WW8_HLINK_ABS
= 0x00000002; /// Absolute path.
186 //const sal_uInt32 WW8_HLINK_DESCR = 0x00000014; /// Description.
187 constexpr sal_uInt32 WW8_HLINK_MARK
= 0x00000008; /// Text mark.
188 constexpr sal_uInt32 WW8_HLINK_FRAME
= 0x00000080; /// Target frame.
189 //const sal_uInt32 WW8_HLINK_UNC = 0x00000100; /// UNC path.
190 SvMemoryStream tmpStrm
;
191 OUString tmpTextMark
;
193 OUString rUrl
= pINetFormatArg
->GetURL();
194 OUString rTarFrame
= pINetFormatArg
->GetTargetFrameName();
195 sal_uInt32 nFlags
= 0;
197 INetURLObject
aUrlObj( rUrl
);
198 const INetProtocol eProtocol
= aUrlObj
.GetProtocol();
201 if (!rTarFrame
.isEmpty())
203 SwWW8Writer::WriteLong(tmpStrm
, rTarFrame
.getLength()+1);
204 SwWW8Writer::WriteString16(tmpStrm
, rTarFrame
, false);
206 tmpStrm
.WriteUInt16( 0 );
208 nFlags
|= WW8_HLINK_FRAME
;
212 if (eProtocol
== INetProtocol::File
|| (eProtocol
== INetProtocol::NotValid
&& rUrl
[0] != '#'))
216 OUString
aFileName( BuildFileName( nLevel
, bRel
, rUrl
));
219 nFlags
|= WW8_HLINK_ABS
;
221 nFlags
|= WW8_HLINK_BODY
;
223 tmpStrm
.WriteBytes(aGuidFileMoniker
, sizeof(aGuidFileMoniker
));
224 tmpStrm
.WriteUInt16( nLevel
);
225 SwWW8Writer::WriteLong(tmpStrm
, aFileName
.getLength()+1);
226 SwWW8Writer::WriteString8( tmpStrm
, aFileName
, true, RTL_TEXTENCODING_MS_1252
);
227 tmpStrm
.WriteBytes(aGuidFileTail
, sizeof(aGuidFileTail
));
230 SwWW8Writer::WriteLong(tmpStrm
, 2*aFileName
.getLength()+6);
231 SwWW8Writer::WriteLong(tmpStrm
, 2*aFileName
.getLength());
232 tmpStrm
.WriteUInt16( 0x0003 );
233 SwWW8Writer::WriteString16(tmpStrm
, aFileName
, false);
235 else if( eProtocol
!= INetProtocol::NotValid
)
237 tmpStrm
.WriteBytes(aGuidUrlMoniker
, sizeof(aGuidUrlMoniker
));
238 SwWW8Writer::WriteLong(tmpStrm
, 2*(rUrl
.getLength()+1));
240 SwWW8Writer::WriteString16(tmpStrm
, rUrl
, true);
241 nFlags
|= WW8_HLINK_BODY
| WW8_HLINK_ABS
;
243 else if (rUrl
[0] == '#' )
245 OUString
aTextMark(rUrl
.copy( 1 ));
246 aTextMark
= aTextMark
.replaceFirst(".", "!");
247 tmpTextMark
= aTextMark
;
250 if (tmpTextMark
.isEmpty() && aUrlObj
.HasMark())
252 tmpTextMark
= aUrlObj
.GetMark();
255 if (!tmpTextMark
.isEmpty())
257 SwWW8Writer::WriteLong(tmpStrm
, tmpTextMark
.getLength()+1);
258 SwWW8Writer::WriteString16(tmpStrm
, tmpTextMark
, true);
260 nFlags
|= WW8_HLINK_MARK
;
263 rStrm
.WriteBytes(aGuidStdLink
, 16);
264 rStrm
.WriteUInt32( 2 )
265 .WriteUInt32( nFlags
);
266 tmpStrm
.Seek( STREAM_SEEK_TO_BEGIN
);
267 sal_uInt32
const nLen
= tmpStrm
.remainingSize();
270 std::unique_ptr
<sal_uInt8
[]> pBuffer( new sal_uInt8
[ nLen
] );
271 tmpStrm
.ReadBytes(pBuffer
.get(), nLen
);
272 rStrm
.WriteBytes(pBuffer
.get(), nLen
);
275 void SwBasicEscherEx::PreWriteHyperlinkWithinFly(const SwFrameFormat
& rFormat
,EscherPropertyContainer
& rPropOpt
)
277 const SwAttrSet
& rAttrSet
= rFormat
.GetAttrSet();
278 const SwFormatURL
* pINetFormat
= rAttrSet
.GetItemIfSet(RES_URL
);
279 if (!pINetFormat
|| pINetFormat
->GetURL().isEmpty())
282 SvMemoryStream aStrm
;
283 WriteHyperlinkWithinFly( aStrm
, pINetFormat
);
284 rPropOpt
.AddOpt(ESCHER_Prop_pihlShape
, true, 0, aStrm
);
286 OUString aNamestr
= pINetFormat
->GetName();
287 if (!aNamestr
.isEmpty())
289 rPropOpt
.AddOpt(ESCHER_Prop_wzName
, aNamestr
);
291 if(rPropOpt
.GetOpt( ESCHER_Prop_fPrint
, nValue
))
294 rPropOpt
.AddOpt(ESCHER_Prop_fPrint
, nValue
);
297 rPropOpt
.AddOpt(ESCHER_Prop_fPrint
, 0x03080008 );
302 /// Get the Z ordering number for a DrawObj in a WW8Export.
303 /// @param rWrt The containing WW8Export.
304 /// @param pObj pointer to the drawing object.
305 /// @returns The ordering number.
306 sal_uLong
lcl_getSdrOrderNumber(const WW8Export
& rWrt
, DrawObj
const *pObj
)
308 return rWrt
.GetSdrOrdNum(pObj
->maContent
.GetFrameFormat());
311 /// A function object to act as a predicate comparing the ordering numbers
312 /// of two drawing objects in a WW8Export.
313 class CompareDrawObjs
316 const WW8Export
& m_rWrt
;
319 explicit CompareDrawObjs(const WW8Export
& rWrt
) : m_rWrt(rWrt
) {};
320 bool operator()(DrawObj
const *a
, DrawObj
const *b
) const
322 sal_uLong aSort
= lcl_getSdrOrderNumber(m_rWrt
, a
);
323 sal_uLong bSort
= lcl_getSdrOrderNumber(m_rWrt
, b
);
324 return aSort
< bSort
;
328 /// Make a z-order sorted copy of a collection of DrawObj objects.
329 /// @param rWrt The containing WW8Export.
330 /// @param rSrcArr The source array.
331 /// @param rDstArr The destination array.
332 void lcl_makeZOrderArray(const WW8Export
& rWrt
,
333 std::vector
<DrawObj
> &rSrcArr
,
334 std::vector
<DrawObj
*> &rDstArr
)
337 rDstArr
.reserve(rSrcArr
.size());
338 for(DrawObj
& i
: rSrcArr
)
340 rDstArr
.push_back( &i
);
342 std::sort(rDstArr
.begin(), rDstArr
.end(), CompareDrawObjs(rWrt
));
347 // get a part fix for this type of element
348 bool WW8Export::MiserableFormFieldExportHack(const SwFrameFormat
& rFrameFormat
)
350 const SdrObject
*pObject
= rFrameFormat
.FindRealSdrObject();
351 if (!pObject
|| pObject
->GetObjInventor() != SdrInventor::FmForm
)
354 const SdrUnoObj
*pFormObj
= dynamic_cast< const SdrUnoObj
* >(pObject
);
358 uno::Reference
< awt::XControlModel
> xControlModel
=
359 pFormObj
->GetUnoControlModel();
360 uno::Reference
< lang::XServiceInfo
> xInfo(xControlModel
,
362 uno::Reference
<beans::XPropertySet
> xPropSet(xControlModel
, uno::UNO_QUERY
);
366 if (xInfo
->supportsService("com.sun.star.form.component.ComboBox"))
368 DoComboBox(xPropSet
);
375 void WW8Export::DoComboBox(uno::Reference
<beans::XPropertySet
> const & xPropSet
)
378 uno::Sequence
<OUString
> aListItems
;
379 xPropSet
->getPropertyValue("StringItemList") >>= aListItems
;
380 if (aListItems
.hasElements())
382 uno::Any aTmp
= xPropSet
->getPropertyValue("DefaultText");
383 auto pStr
= o3tl::tryAccess
<OUString
>(aTmp
);
390 uno::Any aTmp
= xPropSet
->getPropertyValue("Name");
391 auto pStr
= o3tl::tryAccess
<OUString
>(aTmp
);
398 // property "Help" does not exist and due to the no-existence an exception is thrown.
401 uno::Any aTmp
= xPropSet
->getPropertyValue("HelpText");
402 auto pStr
= o3tl::tryAccess
<OUString
>(aTmp
);
406 catch( const uno::Exception
& )
412 uno::Any aTmp
= xPropSet
->getPropertyValue("Name");
413 auto pStr
= o3tl::tryAccess
<OUString
>(aTmp
);
418 DoComboBox(sName
, sHelp
, sToolTip
, sSelected
, aListItems
);
421 void WW8Export::DoComboBox(const OUString
&rName
,
422 const OUString
&rHelp
,
423 const OUString
&rToolTip
,
424 const OUString
&rSelected
,
425 const uno::Sequence
<OUString
> &rListItems
)
427 OutputField(nullptr, ww::eFORMDROPDOWN
, FieldString(ww::eFORMDROPDOWN
),
428 FieldFlags::Start
| FieldFlags::CmdStart
);
429 // write the reference to the "picture" structure
430 sal_uInt64 nDataStt
= m_pDataStrm
->Tell();
431 m_pChpPlc
->AppendFkpEntry( Strm().Tell() );
435 static sal_uInt8 aArr1
[] =
437 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
438 0x06, 0x08, 0x01, // sprmCFData
439 0x55, 0x08, 0x01, // sprmCFSpec
440 0x02, 0x08, 0x01 // sprmCFFieldVanish
442 sal_uInt8
* pDataAdr
= aArr1
+ 2;
443 Set_UInt32( pDataAdr
, nDataStt
);
445 m_pChpPlc
->AppendFkpEntry(Strm().Tell(), sizeof(aArr1
), aArr1
);
447 OutputField(nullptr, ww::eFORMDROPDOWN
, FieldString(ww::eFORMDROPDOWN
),
450 ::sw::WW8FFData aFFData
;
453 aFFData
.setName(rName
);
454 aFFData
.setHelp(rHelp
);
455 aFFData
.setStatus(rToolTip
);
457 sal_uInt32 nListItems
= rListItems
.getLength();
459 for (sal_uInt32 i
= 0; i
< nListItems
; i
++)
461 if (i
< 0x20 && rSelected
== rListItems
[i
])
462 aFFData
.setResult(::sal::static_int_cast
<sal_uInt8
>(i
));
463 aFFData
.addListboxEntry(rListItems
[i
]);
466 aFFData
.Write(m_pDataStrm
);
469 void WW8Export::DoFormText(const SwInputField
* pField
)
471 OutputField(nullptr, ww::eFORMTEXT
, FieldString(ww::eFORMTEXT
),
472 FieldFlags::Start
| FieldFlags::CmdStart
);
473 // write the reference to the "picture" structure
474 sal_uInt64 nDataStt
= m_pDataStrm
->Tell();
475 m_pChpPlc
->AppendFkpEntry( Strm().Tell() );
478 static sal_uInt8 aArr1
[] = {
479 0x02, 0x08, 0x81, // sprmCFFieldVanish
480 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
482 0x06, 0x08, 0x01, // sprmCFData
483 0x55, 0x08, 0x01 // sprmCFSpec
485 sal_uInt8
* pDataAdr
= aArr1
+ 5;
486 Set_UInt32( pDataAdr
, nDataStt
);
488 m_pChpPlc
->AppendFkpEntry(Strm().Tell(),
489 sizeof( aArr1
), aArr1
);
491 ::sw::WW8FFData aFFData
;
494 aFFData
.setName(pField
->GetPar2());
495 aFFData
.setHelp(pField
->GetHelp());
496 aFFData
.setStatus(pField
->GetToolTip());
497 aFFData
.Write(m_pDataStrm
);
499 OutputField(nullptr, ww::eFORMTEXT
, OUString(), FieldFlags::CmdEnd
);
501 const OUString
fieldStr( pField
->ExpandField(true, nullptr) );
502 SwWW8Writer::WriteString16(Strm(), fieldStr
, false);
504 static sal_uInt8 aArr2
[] = {
505 0x55, 0x08, 0x01, // sprmCFSpec
506 0x75, 0x08, 0x01 // ???
509 pDataAdr
= aArr2
+ 2;
510 Set_UInt32( pDataAdr
, nDataStt
);
511 m_pChpPlc
->AppendFkpEntry(Strm().Tell(),
512 sizeof( aArr2
), aArr2
);
514 OutputField(nullptr, ww::eFORMTEXT
, OUString(), FieldFlags::Close
);
517 PlcDrawObj::~PlcDrawObj()
521 //It's irritating to have to change the RTL frames position into LTR ones
522 //so that word will have to place them in the right place. Doubly so that
523 //the SO drawings and writer frames have different ideas themselves as to
524 //how to be positioned when in RTL mode!
525 bool RTLGraphicsHack(SwTwips
&rLeft
, SwTwips nWidth
,
526 sal_Int16 eHoriOri
, sal_Int16 eHoriRel
, SwTwips nPageLeft
,
527 SwTwips nPageRight
, SwTwips nPageSize
)
530 if (eHoriOri
== text::HoriOrientation::NONE
)
532 if (eHoriRel
== text::RelOrientation::PAGE_FRAME
)
534 rLeft
= nPageSize
- rLeft
;
538 (eHoriRel
== text::RelOrientation::PAGE_PRINT_AREA
) ||
539 (eHoriRel
== text::RelOrientation::FRAME
) ||
540 (eHoriRel
== text::RelOrientation::PRINT_AREA
)
543 rLeft
= nPageSize
- nPageLeft
- nPageRight
- rLeft
;
552 static bool RTLDrawingsHack(SwTwips
&rLeft
,
553 sal_Int16 eHoriOri
, sal_Int16 eHoriRel
, SwTwips nPageLeft
,
554 SwTwips nPageRight
, SwTwips nPageSize
)
557 if (eHoriOri
== text::HoriOrientation::NONE
)
559 if (eHoriRel
== text::RelOrientation::PAGE_FRAME
)
561 rLeft
= nPageSize
+ rLeft
;
565 (eHoriRel
== text::RelOrientation::PAGE_PRINT_AREA
) ||
566 (eHoriRel
== text::RelOrientation::FRAME
) ||
567 (eHoriRel
== text::RelOrientation::PRINT_AREA
)
570 rLeft
= nPageSize
- nPageLeft
- nPageRight
+ rLeft
;
577 void WW8Export::MiserableRTLFrameFormatHack(SwTwips
&rLeft
, SwTwips
&rRight
,
578 const ww8::Frame
&rFrameFormat
)
580 //Require nasty bidi swap
581 if (SvxFrameDirection::Horizontal_RL_TB
!= m_rDoc
.GetTextDirection(rFrameFormat
.GetPosition()))
584 SwTwips nWidth
= rRight
- rLeft
;
585 SwTwips nPageLeft
, nPageRight
;
586 SwTwips nPageSize
= CurrentPageWidth(nPageLeft
, nPageRight
);
588 const SwFormatHoriOrient
& rHOr
= rFrameFormat
.GetFrameFormat().GetHoriOrient();
591 ww8::Frame::WriterSource eSource
= rFrameFormat
.GetWriterType();
592 if (eSource
== ww8::Frame::eDrawing
|| eSource
== ww8::Frame::eFormControl
)
594 if (RTLDrawingsHack(rLeft
, rHOr
.GetHoriOrient(),
595 rHOr
.GetRelationOrient(), nPageLeft
, nPageRight
, nPageSize
))
602 if (RTLGraphicsHack(rLeft
, nWidth
, rHOr
.GetHoriOrient(),
603 rHOr
.GetRelationOrient(), nPageLeft
, nPageRight
, nPageSize
))
609 rRight
= rLeft
+ nWidth
;
612 void PlcDrawObj::WritePlc( WW8Export
& rWrt
) const
614 if (8 > rWrt
.m_pFib
->m_nVersion
) // Cannot export drawobject in vers 7-
617 sal_uInt32 nFcStart
= rWrt
.m_pTableStrm
->Tell();
619 if (maDrawObjs
.empty())
623 WW8Fib
& rFib
= *rWrt
.m_pFib
;
624 WW8_CP nCpOffs
= GetCpOffset(rFib
);
626 for (const auto& rDrawObj
: maDrawObjs
)
627 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, rDrawObj
.mnCp
- nCpOffs
);
629 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, rFib
.m_ccpText
+ rFib
.m_ccpFootnote
+
630 rFib
.m_ccpHdr
+ rFib
.m_ccpEdn
+ rFib
.m_ccpTxbx
+ rFib
.m_ccpHdrTxbx
+ 1);
632 for (const auto& rDrawObj
: maDrawObjs
)
634 // write the fspa-struct
635 const ww8::Frame
&rFrameFormat
= rDrawObj
.maContent
;
636 const SwFrameFormat
&rFormat
= rFrameFormat
.GetFrameFormat();
637 const SdrObject
* pObj
= rFormat
.FindRealSdrObject();
639 tools::Rectangle aRect
;
640 SwFormatVertOrient rVOr
= rFormat
.GetVertOrient();
641 SwFormatHoriOrient rHOr
= rFormat
.GetHoriOrient();
642 // #i30669# - convert the positioning attributes.
643 // Most positions are converted, if layout information exists.
644 const bool bPosConverted
=
645 WinwordAnchoring::ConvertPosition( rHOr
, rVOr
, rFormat
);
648 bool bHasHeightWidthSwapped(false);
649 if (RES_FLYFRMFMT
== rFormat
.Which())
651 SwRect
aLayRect(rFormat
.FindLayoutRect(false, &aObjPos
));
652 // the Object is not visible - so get the values from
653 // the format. The Position may not be correct.
654 if( aLayRect
.IsEmpty() )
655 aRect
.SetSize( rFormat
.GetFrameSize().GetSize() );
658 // #i56090# Do not only consider the first client
659 // Note that we actually would have to find the maximum size of the
660 // frame format clients. However, this already should work in most cases.
661 const SwRect
aSizeRect(rFormat
.FindLayoutRect());
662 if ( aSizeRect
.Width() > aLayRect
.Width() )
663 aLayRect
.Width( aSizeRect
.Width() );
665 aRect
= aLayRect
.SVRect();
670 OSL_ENSURE(pObj
, "Where is the SDR-Object?");
673 aRect
= pObj
->GetLogicRect();
675 // rotating to vertical means swapping height and width as seen in SvxMSDffManager::ImportShape
676 const Degree100 nAngle
= NormAngle36000( pObj
->GetRotateAngle() );
677 const bool bAllowSwap
= pObj
->GetObjIdentifier() != SdrObjKind::Line
&& pObj
->GetObjIdentifier() != SdrObjKind::Group
;
678 if ( bAllowSwap
&& (( nAngle
> 4500_deg100
&& nAngle
<= 13500_deg100
) || ( nAngle
> 22500_deg100
&& nAngle
<= 31500_deg100
)) )
680 const tools::Long nWidth
= aRect
.getOpenWidth();
681 const tools::Long nHeight
= aRect
.getOpenHeight();
682 aRect
.setWidth( nHeight
);
683 aRect
.setHeight( nWidth
);
684 bHasHeightWidthSwapped
= true;
689 // #i30669# - use converted position, if conversion is performed.
690 // Unify position determination of Writer fly frames
691 // and drawing objects.
694 aRect
.SetPos( Point( rHOr
.GetPos(), rVOr
.GetPos() ) );
698 aRect
-= rDrawObj
.maParentPos
;
699 aObjPos
= aRect
.TopLeft();
700 if (text::VertOrientation::NONE
== rVOr
.GetVertOrient())
703 sal_Int16 eOri
= rVOr
.GetRelationOrient();
704 if (eOri
== text::RelOrientation::CHAR
|| eOri
== text::RelOrientation::TEXT_LINE
)
705 aObjPos
.setY( -rVOr
.GetPos() );
707 aObjPos
.setY( rVOr
.GetPos() );
709 if (text::HoriOrientation::NONE
== rHOr
.GetHoriOrient())
710 aObjPos
.setX( rHOr
.GetPos() );
711 aRect
.SetPos( aObjPos
);
714 sal_Int32 nThick
= rDrawObj
.mnThick
;
716 //If we are being exported as an inline hack, set
717 //corner to 0 and forget about border thickness for positioning
718 if (rFrameFormat
.IsInline())
720 aRect
.SetPos(Point(0,0));
725 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, rDrawObj
.mnShapeId
);
727 SwTwips nLeft
= aRect
.Left() + nThick
;
728 SwTwips nRight
= aRect
.Right() - nThick
;
729 SwTwips nTop
= aRect
.Top() + nThick
;
730 SwTwips nBottom
= aRect
.Bottom() - nThick
;
732 // tdf#93675, 0 below line/paragraph and/or top line/paragraph with
733 // wrap top+bottom or other wraps is affecting the line directly
734 // above the anchor line, which seems odd, but a tiny adjustment
735 // here to bring the top down convinces msoffice to wrap like us
736 if (nTop
== 0 && !rFrameFormat
.IsInline() &&
737 rVOr
.GetVertOrient() == text::VertOrientation::NONE
&&
738 rVOr
.GetRelationOrient() == text::RelOrientation::FRAME
)
743 //Nasty swap for bidi if necessary
744 rWrt
.MiserableRTLFrameFormatHack(nLeft
, nRight
, rFrameFormat
);
746 // tdf#70838. Word relates the position to the unrotated rectangle,
747 // Writer to the rotated one. Because the rotation is around center,
748 // the difference counts half.
749 if(pObj
&& pObj
->GetRotateAngle())
753 SwTwips nSnapWidth
= pObj
->GetSnapRect().getOpenWidth();
754 SwTwips nSnapHeight
= pObj
->GetSnapRect().getOpenHeight();
755 SwTwips nLogicWidth
= pObj
->GetLogicRect().getOpenWidth();
756 SwTwips nLogicHeight
= pObj
->GetLogicRect().getOpenHeight();
757 // +1 for to compensate integer arithmetic rounding errors
758 if(bHasHeightWidthSwapped
)
760 nXOff
= (nSnapWidth
- nLogicHeight
+ 1) / 2;
761 nYOff
= (nSnapHeight
- nLogicWidth
+ 1) / 2;
765 nXOff
= (nSnapWidth
- nLogicWidth
+ 1) / 2;
766 nYOff
= (nSnapHeight
- nLogicHeight
+ 1) / 2;
774 //xaLeft/yaTop/xaRight/yaBottom - rel. to anchor
775 //(most of) the border is outside the graphic is word, so
776 //change dimensions to fit
777 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, nLeft
);
778 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, nTop
);
779 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, nRight
);
780 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, nBottom
);
782 //fHdr/bx/by/wr/wrk/fRcaSimple/fBelowText/fAnchorLock
784 //If nFlags isn't 0x14 its overridden by the escher properties
785 if (RndStdIds::FLY_AT_PAGE
== rFormat
.GetAnchor().GetAnchorId())
788 nFlags
= 0x0014; // x-rel to text, y-rel to text
790 const SwFormatSurround
& rSurr
= rFormat
.GetSurround();
791 sal_uInt16 nContour
= rSurr
.IsContour() ? 0x0080 : 0x0040;
792 css::text::WrapTextMode eSurround
= rSurr
.GetSurround();
796 The inline elements being export as anchored to character inside
797 the shape field hack are required to be wrap through so as to flow
798 over the following dummy 0x01 graphic
800 if (rFrameFormat
.IsInline())
801 eSurround
= css::text::WrapTextMode_THROUGH
;
805 case css::text::WrapTextMode_NONE
:
808 case css::text::WrapTextMode_THROUGH
:
811 case css::text::WrapTextMode_PARALLEL
:
812 nFlags
|= 0x0000 | nContour
;
814 case css::text::WrapTextMode_DYNAMIC
:
815 nFlags
|= 0x0600 | nContour
;
817 case css::text::WrapTextMode_LEFT
:
818 nFlags
|= 0x0200 | nContour
;
820 case css::text::WrapTextMode_RIGHT
:
821 nFlags
|= 0x0400 | nContour
;
824 OSL_ENSURE(false, "Unsupported surround type for export");
827 if (pObj
&& (pObj
->GetLayer() == rWrt
.m_rDoc
.getIDocumentDrawModelAccess().GetHellId() ||
828 pObj
->GetLayer() == rWrt
.m_rDoc
.getIDocumentDrawModelAccess().GetInvisibleHellId()))
834 #i3958# Required to make this inline stuff work in WordXP, not
835 needed for 2003 interestingly
837 if (rFrameFormat
.IsInline())
840 SwWW8Writer::WriteShort(*rWrt
.m_pTableStrm
, nFlags
);
843 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, 0);
846 RegisterWithFib(rFib
, nFcStart
, rWrt
.m_pTableStrm
->Tell() - nFcStart
);
849 void MainTextPlcDrawObj::RegisterWithFib(WW8Fib
&rFib
, sal_uInt32 nStart
,
850 sal_uInt32 nLen
) const
852 rFib
.m_fcPlcfspaMom
= nStart
;
853 rFib
.m_lcbPlcfspaMom
= nLen
;
856 WW8_CP
MainTextPlcDrawObj::GetCpOffset(const WW8Fib
&) const
861 void HdFtPlcDrawObj::RegisterWithFib(WW8Fib
&rFib
, sal_uInt32 nStart
,
862 sal_uInt32 nLen
) const
864 rFib
.m_fcPlcfspaHdr
= nStart
;
865 rFib
.m_lcbPlcfspaHdr
= nLen
;
868 WW8_CP
HdFtPlcDrawObj::GetCpOffset(const WW8Fib
&rFib
) const
870 return rFib
.m_ccpText
+ rFib
.m_ccpFootnote
;
873 bool PlcDrawObj::Append( WW8Export
const & rWrt
, WW8_CP nCp
, const ww8::Frame
& rFormat
,
874 const Point
& rNdTopLeft
)
877 const SwFrameFormat
&rFrameFormat
= rFormat
.GetFrameFormat();
878 if (TXT_HDFT
== rWrt
.m_nTextTyp
|| TXT_MAINTEXT
== rWrt
.m_nTextTyp
)
880 if (RES_FLYFRMFMT
== rFrameFormat
.Which())
882 // check for textflyframe and if it is the first in a Chain
883 if (rFrameFormat
.GetContent().GetContentIdx())
892 DrawObj
aObj(rFormat
, nCp
, rNdTopLeft
, rWrt
.TrueFrameDirection(rFrameFormat
),
893 rWrt
.GetHdFtIndex());
894 maDrawObjs
.push_back(aObj
);
899 void DrawObj::SetShapeDetails(sal_uInt32 nId
, sal_Int32 nThick
)
905 bool WW8_WrPlcTextBoxes::WriteText( WW8Export
& rWrt
)
907 rWrt
.m_bInWriteEscher
= true;
908 WW8_CP
& rccp
=TXT_TXTBOX
== m_nTyp
? rWrt
.m_pFib
->m_ccpTxbx
: rWrt
.m_pFib
->m_ccpHdrTxbx
;
910 bool bRet
= WriteGenericText( rWrt
, m_nTyp
, rccp
);
912 WW8_CP nCP
= rWrt
.Fc2Cp( rWrt
.Strm().Tell() );
913 WW8Fib
& rFib
= *rWrt
.m_pFib
;
914 WW8_CP nMyOffset
= rFib
.m_ccpText
+ rFib
.m_ccpFootnote
+ rFib
.m_ccpHdr
+ rFib
.m_ccpAtn
916 if( TXT_TXTBOX
== m_nTyp
)
917 rWrt
.m_pFieldTextBxs
->Finish( nCP
, nMyOffset
);
919 rWrt
.m_pFieldHFTextBxs
->Finish( nCP
, nMyOffset
+ rFib
.m_ccpTxbx
);
920 rWrt
.m_bInWriteEscher
= false;
924 void WW8_WrPlcTextBoxes::Append( const SdrObject
& rObj
, sal_uInt32 nShapeId
)
926 m_aContent
.push_back( &rObj
);
927 m_aShapeIds
.push_back( nShapeId
);
928 //save NULL, if we have an actual SdrObject
929 m_aSpareFormats
.push_back(nullptr);
932 void WW8_WrPlcTextBoxes::Append( const SwFrameFormat
* pFormat
, sal_uInt32 nShapeId
)
934 //no sdr object, we insert a NULL in the aContent and save the real fmt in aSpareFormats.
935 m_aContent
.push_back( nullptr );
936 m_aShapeIds
.push_back( nShapeId
);
937 m_aSpareFormats
.push_back(pFormat
);
940 const std::vector
<sal_uInt32
>* WW8_WrPlcTextBoxes::GetShapeIdArr() const
945 sal_uInt32
WW8Export::GetSdrOrdNum( const SwFrameFormat
& rFormat
) const
948 const SdrObject
* pObj
= rFormat
.FindRealSdrObject();
950 nOrdNum
= pObj
->GetOrdNum();
953 // no Layout for this format, then recalc the ordnum
954 SwFrameFormat
* pFormat
= const_cast<SwFrameFormat
*>(&rFormat
);
955 nOrdNum
= std::distance(m_rDoc
.GetSpzFrameFormats()->begin(),
956 m_rDoc
.GetSpzFrameFormats()->find(static_cast<sw::SpzFrameFormat
*>(pFormat
)));
958 const SwDrawModel
* pModel
= m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel();
960 nOrdNum
+= pModel
->GetPage( 0 )->GetObjCount();
965 void WW8Export::AppendFlyInFlys(const ww8::Frame
& rFrameFormat
,
966 const Point
& rNdTopLeft
)
968 OSL_ENSURE(!m_pEscher
, "the EscherStream was already written!");
972 if (TXT_HDFT
== m_nTextTyp
)
973 pDrwO
= m_pHFSdrObjs
.get();
975 pDrwO
= m_pSdrObjs
.get();
977 if (rFrameFormat
.IsInline())
979 OutputField(nullptr, ww::eSHAPE
, FieldString(ww::eSHAPE
),
980 FieldFlags::Start
| FieldFlags::CmdStart
| FieldFlags::CmdEnd
);
983 WW8_CP nCP
= Fc2Cp(Strm().Tell());
984 bool bSuccess
= pDrwO
->Append(*this, nCP
, rFrameFormat
, rNdTopLeft
);
985 OSL_ENSURE(bSuccess
, "Couldn't export a graphical element!");
989 static const sal_uInt8 aSpec8
[] =
991 0x03, 0x6a, 0, 0, 0, 0, // sprmCObjLocation
992 0x55, 0x08, 1 // sprmCFSpec
994 // fSpec-Attribute true
996 // A special character is required in the text for DrawObjects,
997 // therefore a fSpec-Attribute
998 m_pChpPlc
->AppendFkpEntry( Strm().Tell() );
1000 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), sizeof( aSpec8
), aSpec8
);
1002 //Need dummy picture frame
1003 if (rFrameFormat
.IsInline())
1004 OutGrf(rFrameFormat
);
1007 if (rFrameFormat
.IsInline())
1008 OutputField(nullptr, ww::eSHAPE
, OUString(), FieldFlags::Close
);
1011 MSWord_SdrAttrIter::MSWord_SdrAttrIter( MSWordExportBase
& rWr
,
1012 const EditTextObject
& rEditObj
, sal_uInt8 nTyp
)
1013 : MSWordAttrIter( rWr
), m_pEditObj(&rEditObj
), m_pEditPool(nullptr), mnTyp(nTyp
)
1018 void MSWord_SdrAttrIter::NextPara( sal_Int32 nPar
)
1021 // Ignore change of attribute at position 0, because we expect that
1022 // the attributes are outputted at start of a paragraph anyway.
1023 m_aChrTextAtrArr
.clear();
1024 m_aChrSetArr
.clear();
1025 m_nCurrentSwPos
= m_nTmpSwPos
= 0;
1027 SfxItemSet
aSet( m_pEditObj
->GetParaAttribs( m_nPara
));
1028 m_pEditPool
= aSet
.GetPool();
1029 m_eNdChrSet
= aSet
.Get(EE_CHAR_FONTINFO
).GetCharSet();
1031 assert(g_pBreakIt
&& g_pBreakIt
->GetBreakIter().is());
1032 m_nScript
= g_pBreakIt
->GetBreakIter()->getScriptType( m_pEditObj
->GetText(m_nPara
), 0);
1034 m_pEditObj
->GetCharAttribs( m_nPara
, m_aTextAtrArr
);
1035 m_nCurrentSwPos
= SearchNext( 1 );
1038 rtl_TextEncoding
MSWord_SdrAttrIter::GetNextCharSet() const
1040 if( !m_aChrSetArr
.empty() )
1041 return m_aChrSetArr
.back();
1045 // the first parameter in SearchNext() returns if it's a TextAtr
1046 sal_Int32
MSWord_SdrAttrIter::SearchNext( sal_Int32 nStartPos
)
1048 sal_Int32 nMinPos
= SAL_MAX_INT32
;
1049 for(const auto& rTextAtr
: m_aTextAtrArr
)
1051 sal_Int32 nPos
= rTextAtr
.nStart
; // first character attribute
1052 if( nPos
>= nStartPos
&& nPos
<= nMinPos
)
1055 SetCharSet(rTextAtr
, true);
1058 nPos
= rTextAtr
.nEnd
; // last character attribute + 1
1059 if( nPos
>= nStartPos
&& nPos
< nMinPos
)
1062 SetCharSet(rTextAtr
, false);
1068 void MSWord_SdrAttrIter::SetCharSet(const EECharAttrib
& rAttr
, bool bStart
)
1070 const SfxPoolItem
& rItem
= *rAttr
.pAttr
;
1071 if( rItem
.Which() != EE_CHAR_FONTINFO
)
1078 rtl_TextEncoding eChrSet
= static_cast<const SvxFontItem
&>(rItem
).GetCharSet();
1079 m_aChrSetArr
.push_back( eChrSet
);
1080 m_aChrTextAtrArr
.push_back( &rAttr
);
1084 std::vector
<const EECharAttrib
*>::iterator it
=
1085 std::find( m_aChrTextAtrArr
.begin(), m_aChrTextAtrArr
.end(), &rAttr
);
1086 if ( it
!= m_aChrTextAtrArr
.end() )
1088 m_aChrSetArr
.erase( m_aChrSetArr
.begin() + (it
- m_aChrTextAtrArr
.begin()) );
1089 m_aChrTextAtrArr
.erase( it
);
1094 void MSWord_SdrAttrIter::OutEEField(const SfxPoolItem
& rHt
)
1096 const SvxFieldItem
&rField
= static_cast<const SvxFieldItem
&>(rHt
);
1097 const SvxFieldData
*pField
= rField
.GetField();
1098 if (auto pURL
= dynamic_cast< const SvxURLField
*>( pField
))
1100 sal_uInt8 nOldTextTyp
= m_rExport
.m_nTextTyp
;
1101 m_rExport
.m_nTextTyp
= mnTyp
;
1102 m_rExport
.AttrOutput().StartURL( pURL
->GetURL(), pURL
->GetTargetFrame() );
1104 const OUString
&rStr
= pURL
->GetRepresentation();
1105 m_rExport
.AttrOutput().RawText(rStr
, GetNodeCharSet());
1107 m_rExport
.AttrOutput().EndURL(false);
1108 m_rExport
.m_nTextTyp
= nOldTextTyp
;
1112 void MSWord_SdrAttrIter::OutAttr( sal_Int32 nSwPos
)
1114 //Collect the which ids belong to the run that we will export after
1115 //outputting the underlying paragraph attributes. We will exclude
1116 //writing these from the underlying paragraph attributes to avoid
1117 //duplicate attributes in docx export. Doesn't matter in doc
1118 //export as later props just override earlier ones.
1119 std::set
<sal_uInt16
> aUsedRunWhichs
;
1120 for(const auto& rTextAtr
: m_aTextAtrArr
)
1122 if (nSwPos
>= rTextAtr
.nStart
&& nSwPos
< rTextAtr
.nEnd
)
1124 sal_uInt16 nWhich
= rTextAtr
.pAttr
->Which();
1125 aUsedRunWhichs
.insert(nWhich
);
1128 if( nSwPos
< rTextAtr
.nStart
)
1132 OutParaAttr(true, &aUsedRunWhichs
);
1134 if (m_aTextAtrArr
.empty())
1137 const sw::BroadcastingModify
* pOldMod
= m_rExport
.m_pOutFormatNode
;
1138 m_rExport
.m_pOutFormatNode
= nullptr;
1140 const SfxItemPool
* pSrcPool
= m_pEditPool
;
1141 const SfxItemPool
& rDstPool
= m_rExport
.m_rDoc
.GetAttrPool();
1143 m_nTmpSwPos
= nSwPos
;
1144 // Did we already produce a <w:sz> element?
1145 m_rExport
.m_bFontSizeWritten
= false;
1146 for(const auto& rTextAtr
: m_aTextAtrArr
)
1148 if (nSwPos
>= rTextAtr
.nStart
&& nSwPos
< rTextAtr
.nEnd
)
1150 sal_uInt16 nWhich
= rTextAtr
.pAttr
->Which();
1151 if (nWhich
== EE_FEATURE_FIELD
)
1153 OutEEField(*(rTextAtr
.pAttr
));
1156 if (nWhich
== EE_FEATURE_TAB
)
1158 m_rExport
.WriteChar(0x9);
1161 if (nWhich
== EE_CHAR_BKGCOLOR
)
1163 Color
aColor(static_cast<const SvxColorItem
*>(rTextAtr
.pAttr
)->GetValue());
1164 m_rExport
.AttrOutput().OutputItem(SvxBrushItem(aColor
, RES_CHRATR_BACKGROUND
));
1168 const sal_uInt16 nSlotId
= pSrcPool
->GetSlotId(nWhich
);
1169 if (nSlotId
&& nWhich
!= nSlotId
)
1171 nWhich
= rDstPool
.GetWhich(nSlotId
);
1172 if (nWhich
&& nWhich
!= nSlotId
&&
1173 nWhich
< RES_UNKNOWNATR_BEGIN
&&
1174 m_rExport
.CollapseScriptsforWordOk(m_nScript
,nWhich
))
1176 // use always the SW-Which Id !
1177 std::unique_ptr
<SfxPoolItem
> pI(rTextAtr
.pAttr
->Clone());
1178 pI
->SetWhich( nWhich
);
1179 // Will this item produce a <w:sz> element?
1180 bool bFontSizeItem
= nWhich
== RES_CHRATR_FONTSIZE
|| nWhich
== RES_CHRATR_CJK_FONTSIZE
;
1181 if (!m_rExport
.m_bFontSizeWritten
|| !bFontSizeItem
)
1182 m_rExport
.AttrOutput().OutputItem( *pI
);
1184 m_rExport
.m_bFontSizeWritten
= true;
1189 if( nSwPos
< rTextAtr
.nStart
)
1192 m_rExport
.m_bFontSizeWritten
= false;
1194 m_nTmpSwPos
= 0; // HasTextItem only allowed in the above area
1195 m_rExport
.m_pOutFormatNode
= pOldMod
;
1198 bool MSWord_SdrAttrIter::IsTextAttr(sal_Int32 nSwPos
)
1200 return std::any_of(m_aTextAtrArr
.begin(), m_aTextAtrArr
.end(),
1201 [nSwPos
](const EECharAttrib
& rTextAtr
) {
1202 return (nSwPos
>= rTextAtr
.nStart
&& nSwPos
< rTextAtr
.nEnd
) &&
1203 (rTextAtr
.pAttr
->Which() == EE_FEATURE_FIELD
||
1204 rTextAtr
.pAttr
->Which() == EE_FEATURE_TAB
);
1209 // HasItem is used for the consolidation of the double attribute Underline and
1210 // WordLineMode as a TextItem. OutAttr() calls the output function, which can
1211 // query for other items at the start position of attribute via HasItem().
1212 // Only attributes with an end can be queried.
1213 // The search is done with bDeep.
1214 const SfxPoolItem
* MSWord_SdrAttrIter::HasTextItem(sal_uInt16 nWhich
) const
1216 nWhich
= sw::hack::TransformWhichBetweenPools(*m_pEditPool
,
1217 m_rExport
.m_rDoc
.GetAttrPool(), nWhich
);
1220 for (const auto& rTextAtr
: m_aTextAtrArr
)
1222 if (nWhich
== rTextAtr
.pAttr
->Which() && m_nTmpSwPos
>= rTextAtr
.nStart
&& m_nTmpSwPos
< rTextAtr
.nEnd
)
1223 return rTextAtr
.pAttr
; // Found
1224 if (m_nTmpSwPos
< rTextAtr
.nStart
)
1231 const SfxPoolItem
& MSWord_SdrAttrIter::GetItem( sal_uInt16 nWhich
) const
1233 using sw::hack::GetSetWhichFromSwDocWhich
;
1234 const SfxPoolItem
* pRet
= HasTextItem(nWhich
);
1237 SfxItemSet
aSet(m_pEditObj
->GetParaAttribs(m_nPara
));
1238 nWhich
= GetSetWhichFromSwDocWhich(aSet
, m_rExport
.m_rDoc
, nWhich
);
1239 OSL_ENSURE(nWhich
, "Impossible, catastrophic failure imminent");
1240 pRet
= &aSet
.Get(nWhich
);
1245 //Drawing shapes properties inherit from a different pool that the document
1246 //styles. On export to .doc[x] they will default to style "Normal". Here explicitly
1247 //set any items which are not already set, but differ from "Normal".
1248 void MSWord_SdrAttrIter::SetItemsThatDifferFromStandard(bool bCharAttr
, SfxItemSet
& rSet
)
1250 SwTextFormatColl
* pC
= m_rExport
.m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool
1251 (RES_POOLCOLL_STANDARD
, false);
1253 SfxWhichIter
aWhichIter(rSet
);
1254 for (sal_uInt16 nEEWhich
= aWhichIter
.FirstWhich(); nEEWhich
; nEEWhich
= aWhichIter
.NextWhich())
1256 if (SfxItemState::SET
!= aWhichIter
.GetItemState(false))
1258 sal_uInt16 nSwWhich
= sw::hack::TransformWhichBetweenPools(m_rExport
.m_rDoc
.GetAttrPool(),
1259 *m_pEditPool
, nEEWhich
);
1262 bool bWanted
= ( bCharAttr
? ( nSwWhich
>= RES_CHRATR_BEGIN
&& nSwWhich
< RES_TXTATR_END
)
1263 : ( nSwWhich
>= RES_PARATR_BEGIN
&& nSwWhich
< RES_FRMATR_END
) );
1267 const SfxPoolItem
& rDrawItem
= rSet
.Get(nEEWhich
);
1268 const SfxPoolItem
& rStandardItem
= pC
->GetFormatAttr(nSwWhich
);
1269 if (rDrawItem
!= rStandardItem
)
1270 rSet
.Put(rDrawItem
);
1275 void MSWord_SdrAttrIter::OutParaAttr(bool bCharAttr
, const std::set
<sal_uInt16
>* pWhichsToIgnore
)
1277 SfxItemSet
aSet( m_pEditObj
->GetParaAttribs( m_nPara
));
1279 SetItemsThatDifferFromStandard(bCharAttr
, aSet
);
1284 const SfxItemSet
* pOldSet
= m_rExport
.GetCurItemSet();
1285 m_rExport
.SetCurItemSet( &aSet
);
1287 SfxItemIter
aIter( aSet
);
1288 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
1290 const SfxItemPool
* pSrcPool
= m_pEditPool
,
1291 * pDstPool
= &m_rExport
.m_rDoc
.GetAttrPool();
1295 sal_uInt16 nWhich
= pItem
->Which();
1296 if (pWhichsToIgnore
&& pWhichsToIgnore
->find(nWhich
) != pWhichsToIgnore
->end())
1299 sal_uInt16 nSlotId
= pSrcPool
->GetSlotId(nWhich
);
1301 if ( nSlotId
&& nWhich
!= nSlotId
&&
1302 0 != ( nWhich
= pDstPool
->GetWhich( nSlotId
) ) &&
1303 nWhich
!= nSlotId
&&
1304 ( bCharAttr
? ( nWhich
>= RES_CHRATR_BEGIN
&& nWhich
< RES_TXTATR_END
)
1305 : ( nWhich
>= RES_PARATR_BEGIN
&& nWhich
< RES_FRMATR_END
) ) )
1307 // use always the SW-Which Id !
1308 std::unique_ptr
<SfxPoolItem
> pI(pItem
->Clone());
1309 pI
->SetWhich( nWhich
);
1310 if (m_rExport
.CollapseScriptsforWordOk(m_nScript
,nWhich
))
1311 m_rExport
.AttrOutput().OutputItem(*pI
);
1313 } while ((pItem
= aIter
.NextItem()));
1314 m_rExport
.SetCurItemSet( pOldSet
);
1317 void WW8Export::WriteSdrTextObj(const SdrTextObj
& rTextObj
, sal_uInt8 nTyp
)
1319 std::optional
<OutlinerParaObject
> pParaObj
;
1323 When the object is actively being edited, that text is not set into
1324 the objects normal text object, but lives in a separate object.
1326 if (rTextObj
.IsTextEditActive())
1328 pParaObj
= rTextObj
.CreateEditOutlinerParaObject();
1330 else if (rTextObj
.GetOutlinerParaObject())
1332 pParaObj
= *rTextObj
.GetOutlinerParaObject();
1337 WriteOutliner(*pParaObj
, nTyp
);
1341 void WW8Export::WriteOutliner(const OutlinerParaObject
& rParaObj
, sal_uInt8 nTyp
)
1343 bool bAnyWrite
= false;
1344 const EditTextObject
& rEditObj
= rParaObj
.GetTextObject();
1345 MSWord_SdrAttrIter
aAttrIter( *this, rEditObj
, nTyp
);
1347 sal_Int32 nPara
= rEditObj
.GetParagraphCount();
1349 for( sal_Int32 n
= 0; n
< nPara
; ++n
)
1352 aAttrIter
.NextPara( n
);
1354 OSL_ENSURE( m_pO
->empty(), " pO is not empty at start of line" );
1356 OUString
aStr( rEditObj
.GetText( n
));
1357 sal_Int32 nCurrentPos
= 0;
1358 const sal_Int32 nEnd
= aStr
.getLength();
1360 const SfxItemSet
& aSet(rEditObj
.GetParaAttribs(n
));
1361 bool bIsRTLPara
= false;
1362 if(const SvxFrameDirectionItem
* pItem
= aSet
.GetItemIfSet(EE_PARA_WRITINGDIR
))
1364 SvxFrameDirection nDir
= pItem
->GetValue();
1365 bIsRTLPara
= SvxFrameDirection::Horizontal_RL_TB
== nDir
;
1369 const sal_Int32 nNextAttr
= std::min(aAttrIter
.WhereNext(), nEnd
);
1371 bool bTextAtr
= aAttrIter
.IsTextAttr( nCurrentPos
);
1373 OutSwString(aStr
, nCurrentPos
, nNextAttr
- nCurrentPos
);
1375 // At the end of the line the attributes are extended over the CR.
1376 // exception: foot note at line end
1377 if( nNextAttr
== nEnd
&& !bTextAtr
)
1378 WriteCR(); // CR after it
1380 // output of character attributes
1381 aAttrIter
.OutAttr( nCurrentPos
); // nCurrentPos - 1 ??
1385 // This is necessary to make word order correct in MS Word.
1386 // In theory we should do this for complex-script runs only,
1387 // but Outliner does not split runs like Writer core did.
1388 // Fortunately, both MS Word and Writer seems to tolerate
1389 // that we turn it on for non complex-script runs.
1390 AttrOutput().OutputItem(SfxInt16Item(RES_CHRATR_BIDIRTL
, 1));
1393 m_pChpPlc
->AppendFkpEntry( Strm().Tell(),
1394 m_pO
->size(), m_pO
->data() );
1397 // exception: foot note at line end
1398 if( nNextAttr
== nEnd
&& bTextAtr
)
1399 WriteCR(); // CR after it
1400 nCurrentPos
= nNextAttr
;
1401 aAttrIter
.NextPos();
1403 while( nCurrentPos
< nEnd
);
1405 OSL_ENSURE( m_pO
->empty(), " pO is not empty at start of line" );
1407 m_pO
->push_back( bNul
); // Style # as short
1408 m_pO
->push_back( bNul
);
1410 aAttrIter
.OutParaAttr(false);
1412 sal_uInt64 nPos
= Strm().Tell();
1413 m_pPapPlc
->AppendFkpEntry( Strm().Tell(),
1414 m_pO
->size(), m_pO
->data() );
1416 m_pChpPlc
->AppendFkpEntry( nPos
);
1419 bAnyWrite
= 0 != nPara
;
1421 WriteStringAsPara( OUString() );
1424 void WinwordAnchoring::WriteData( EscherEx
& rEx
) const
1426 //Toplevel groups get their winword extra data attached, and sub elements
1428 if (rEx
.GetGroupLevel() > 1)
1431 SvStream
& rSt
= rEx
.GetStream();
1432 //The last argument denotes the number of sub properties in this atom
1433 int nSubProps
= mnGroupShapeBooleanProperties
? 1 : 0;
1437 rEx
.AddAtom(6 * nSubProps
, DFF_msofbtUDefProp
, 3, nSubProps
); // Prop id is 0xF122
1438 rSt
.WriteUInt16( 0x0390 ).WriteUInt32( 3 );
1439 rSt
.WriteUInt16( 0x0392 ).WriteUInt32( 3 );
1440 //This sub property is required to be in the dummy inline frame as
1442 rSt
.WriteUInt16( 0x053F ).WriteUInt32( nInlineHack
);
1447 rEx
.AddAtom(6 * nSubProps
, DFF_msofbtUDefProp
, 3, nSubProps
); // Prop id is 0xF122
1448 rSt
.WriteUInt16( 0x038F ).WriteUInt32( mnXAlign
);
1449 rSt
.WriteUInt16( 0x0390 ).WriteUInt32( mnXRelTo
);
1450 rSt
.WriteUInt16( 0x0391 ).WriteUInt32( mnYAlign
);
1451 rSt
.WriteUInt16( 0x0392 ).WriteUInt32( mnYRelTo
);
1453 if (mnGroupShapeBooleanProperties
)
1454 rSt
.WriteUInt16(0x03BF).WriteUInt32(mnGroupShapeBooleanProperties
);
1457 void WW8Export::CreateEscher()
1459 SfxItemState eBackSet
= m_rDoc
.GetPageDesc(0).GetMaster().
1460 GetItemState(RES_BACKGROUND
);
1461 if (m_pHFSdrObjs
->size() || m_pSdrObjs
->size() || SfxItemState::SET
== eBackSet
)
1463 OSL_ENSURE( !m_pEscher
, "Who did not deleted the pointer?" );
1464 SvMemoryStream
* pEscherStrm
= new SvMemoryStream
;
1465 pEscherStrm
->SetEndian(SvStreamEndian::LITTLE
);
1466 m_pEscher
= new SwEscherEx(pEscherStrm
, *this);
1470 void WW8Export::WriteEscher()
1474 sal_uInt64 nStart
= m_pTableStrm
->Tell();
1476 m_pEscher
->WritePictures();
1477 m_pEscher
->FinishEscher();
1479 m_pFib
->m_fcDggInfo
= nStart
;
1480 m_pFib
->m_lcbDggInfo
= m_pTableStrm
->Tell() - nStart
;
1482 m_pEscher
= nullptr;
1486 void SwEscherEx::WritePictures()
1488 if( SvStream
* pPicStrm
= static_cast< SwEscherExGlobal
& >( *mxGlobal
).GetPictureStream() )
1490 // set the blip - entries to the correct stream pos
1491 sal_Int32 nEndPos
= mrWrt
.Strm().Tell();
1492 mxGlobal
->SetNewBlipStreamOffset( nEndPos
);
1494 pPicStrm
->Seek( 0 );
1495 mrWrt
.Strm().WriteStream( *pPicStrm
);
1500 // Output- Routines for Escher Export
1502 SwEscherExGlobal::SwEscherExGlobal()
1506 SwEscherExGlobal::~SwEscherExGlobal()
1510 SvStream
* SwEscherExGlobal::ImplQueryPictureStream()
1512 // this function will be called exactly once
1513 mxPicStrm
= std::make_shared
<SvMemoryStream
>();
1514 mxPicStrm
->SetEndian(SvStreamEndian::LITTLE
);
1515 return mxPicStrm
.get();
1518 SwBasicEscherEx::SwBasicEscherEx(SvStream
* pStrm
, WW8Export
& rWW8Wrt
)
1519 : EscherEx( std::make_shared
<SwEscherExGlobal
>(), pStrm
), mrWrt(rWW8Wrt
), mpEscherStrm(pStrm
)
1524 SwBasicEscherEx::~SwBasicEscherEx()
1528 void SwBasicEscherEx::WriteFrameExtraData(const SwFrameFormat
&)
1530 AddAtom(4, ESCHER_ClientAnchor
);
1531 GetStream().WriteUInt32( 0x80000000 );
1534 void SwBasicEscherEx::WriteEmptyFlyFrame(const SwFrameFormat
& rFormat
, sal_uInt32 nShapeId
)
1536 OpenContainer(ESCHER_SpContainer
);
1537 AddShape(ESCHER_ShpInst_PictureFrame
, ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
, nShapeId
);
1538 // store anchor attribute
1539 WriteFrameExtraData(rFormat
);
1541 AddAtom(6, DFF_msofbtUDefProp
, 3, 1); //Prop id is 0xF122
1542 GetStream().WriteUInt16( 0x053F ).WriteUInt32( nInlineHack
);
1544 CloseContainer(); // ESCHER_SpContainer
1547 static ShapeFlag
AddMirrorFlags(ShapeFlag nFlags
, const SwMirrorGrf
&rMirror
)
1549 switch (rMirror
.GetValue())
1552 case MirrorGraph::Dont
:
1554 case MirrorGraph::Vertical
:
1555 nFlags
|= ShapeFlag::FlipH
;
1557 case MirrorGraph::Horizontal
:
1558 nFlags
|= ShapeFlag::FlipV
;
1560 case MirrorGraph::Both
:
1561 nFlags
|= ShapeFlag::FlipH
| ShapeFlag::FlipV
;
1567 //For i120928,this function is added to export graphic of bullet
1568 void SwBasicEscherEx::WriteGrfBullet(const Graphic
& rGrf
)
1570 OpenContainer( ESCHER_SpContainer
);
1571 AddShape(ESCHER_ShpInst_PictureFrame
, ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
, 0x401);
1572 EscherPropertyContainer aPropOpt
;
1573 GraphicObject
aGraphicObject( rGrf
);
1574 OString aUniqueId
= aGraphicObject
.GetUniqueID();
1575 if ( !aUniqueId
.isEmpty() )
1577 sal_uInt32 nBlibId
= mxGlobal
->GetBlibID( *(mxGlobal
->QueryPictureStream()), aGraphicObject
);
1579 aPropOpt
.AddOpt(ESCHER_Prop_pib
, nBlibId
, true);
1581 aPropOpt
.AddOpt( ESCHER_Prop_pibFlags
, ESCHER_BlipFlagDefault
);
1582 aPropOpt
.AddOpt( ESCHER_Prop_dyTextTop
, DrawModelToEmu(0));
1583 aPropOpt
.AddOpt( ESCHER_Prop_dyTextBottom
, DrawModelToEmu(0));
1584 aPropOpt
.AddOpt( ESCHER_Prop_dxTextLeft
, DrawModelToEmu(0));
1585 aPropOpt
.AddOpt( ESCHER_Prop_dxTextRight
, DrawModelToEmu(0));
1586 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x80000 );
1587 aPropOpt
.AddOpt( ESCHER_Prop_dyTextTop
, 0 );
1588 aPropOpt
.AddOpt( ESCHER_Prop_dyTextBottom
, 0 );
1589 aPropOpt
.AddOpt( ESCHER_Prop_dxTextLeft
, 0 );
1590 aPropOpt
.AddOpt( ESCHER_Prop_dxTextRight
, 0 );
1591 const Color
aTmpColor( COL_WHITE
);
1592 std::shared_ptr
<SvxBrushItem
> aBrush(std::make_shared
<SvxBrushItem
>(aTmpColor
, RES_BACKGROUND
));
1593 const SvxBrushItem
* pRet
= mrWrt
.GetCurrentPageBgBrush();
1594 if (pRet
&& (pRet
->GetGraphic() ||( pRet
->GetColor() != COL_TRANSPARENT
)))
1595 aBrush
.reset(pRet
->Clone());
1596 WriteBrushAttr(*aBrush
, aPropOpt
);
1598 aPropOpt
.AddOpt( ESCHER_Prop_pictureActive
, 0 );
1599 aPropOpt
.Commit( GetStream() );
1600 AddAtom(4, ESCHER_ClientAnchor
);
1601 GetStream().WriteUInt32( 0x80000000 );
1605 sal_Int32
SwBasicEscherEx::WriteGrfFlyFrame(const SwFrameFormat
& rFormat
, sal_uInt32 nShapeId
)
1607 sal_Int32 nBorderThick
=0;
1608 SwNoTextNode
*pNd
= GetNoTextNodeFromSwFrameFormat(rFormat
);
1609 SwGrfNode
*pGrfNd
= pNd
? pNd
->GetGrfNode() : nullptr;
1610 OSL_ENSURE(pGrfNd
, "No SwGrfNode ?, suspicious");
1612 return nBorderThick
;
1614 OpenContainer( ESCHER_SpContainer
);
1616 const SwMirrorGrf
&rMirror
= pGrfNd
->GetSwAttrSet().GetMirrorGrf();
1617 AddShape(ESCHER_ShpInst_PictureFrame
,
1618 AddMirrorFlags(ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
, rMirror
),
1621 EscherPropertyContainer aPropOpt
;
1623 sal_uInt32 nFlags
= ESCHER_BlipFlagDefault
;
1625 if (pGrfNd
->IsLinkedFile())
1628 pGrfNd
->GetFileFilterNms( &sURL
, nullptr );
1631 SwWW8Writer::InsAsString16( aBuf
, sURL
);
1632 SwWW8Writer::InsUInt16( aBuf
, 0 );
1634 aPropOpt
.AddOpt(ESCHER_Prop_pibName
, true, aBuf
.size(), aBuf
);
1635 nFlags
= ESCHER_BlipFlagLinkToFile
| ESCHER_BlipFlagURL
|
1636 ESCHER_BlipFlagDoNotSave
;
1640 const Graphic
& aGraphic(pGrfNd
->GetGrf());
1641 GraphicObject
aGraphicObject( aGraphic
);
1642 OString aUniqueId
= aGraphicObject
.GetUniqueID();
1644 if (!aUniqueId
.isEmpty())
1646 sal_uInt32 nBlibId
= mxGlobal
->GetBlibID( *QueryPictureStream(), aGraphicObject
);
1648 aPropOpt
.AddOpt(ESCHER_Prop_pib
, nBlibId
, true);
1652 aPropOpt
.AddOpt( ESCHER_Prop_pibFlags
, nFlags
);
1653 nBorderThick
= WriteFlyFrameAttr(rFormat
,mso_sptPictureFrame
,aPropOpt
);
1654 WriteGrfAttr(*pGrfNd
, rFormat
, aPropOpt
);
1656 aPropOpt
.Commit( GetStream() );
1658 // store anchor attribute
1659 WriteFrameExtraData( rFormat
);
1661 CloseContainer(); // ESCHER_SpContainer
1662 return nBorderThick
;
1665 void SwBasicEscherEx::WriteGrfAttr(const SwNoTextNode
& rNd
, const SwFrameFormat
& rFormat
,
1666 EscherPropertyContainer
& rPropOpt
)
1668 GraphicDrawMode nMode
= GraphicDrawMode::Standard
;
1669 sal_Int32 nContrast
= 0;
1670 sal_Int16 nBrightness
= 0;
1672 if (const SfxInt16Item
* pItem
= rNd
.GetSwAttrSet().GetItemIfSet(RES_GRFATR_CONTRAST
))
1674 nContrast
= pItem
->GetValue();
1677 if (const SfxInt16Item
* pItem
= rNd
.GetSwAttrSet().GetItemIfSet(RES_GRFATR_LUMINANCE
))
1679 nBrightness
= pItem
->GetValue();
1682 if (const SfxEnumItemInterface
* pItem
= rNd
.GetSwAttrSet().GetItemIfSet(RES_GRFATR_DRAWMODE
))
1684 nMode
= static_cast<GraphicDrawMode
>(pItem
->GetEnumValue());
1685 if (nMode
== GraphicDrawMode::Watermark
)
1688 There is no real watermark mode in word, we must use standard
1689 mode and modify our ones by 70% extra brightness and 70% less
1690 contrast. This means that unmodified default OOo watermark
1691 will turn back into watermark, and modified OOo watermark will
1692 change into a close visual representation in standardmode
1695 if (nBrightness
> 100)
1698 if (nContrast
< -100)
1700 nMode
= GraphicDrawMode::Standard
;
1704 sal_uInt32 nPictureMode
;
1705 if (nMode
== GraphicDrawMode::Greys
)
1706 nPictureMode
= 0x40004;
1707 else if (nMode
== GraphicDrawMode::Mono
)
1708 nPictureMode
= 0x60006;
1711 rPropOpt
.AddOpt( ESCHER_Prop_pictureActive
, nPictureMode
);
1716 if (nContrast
== 100)
1717 nContrast
= 0x10000;
1718 else if (nContrast
< 100)
1720 nContrast
*= 0x10000;
1723 else if (nContrast
< 200)
1724 nContrast
= (100 * 0x10000) / (200-nContrast
);
1726 nContrast
= 0x7fffffff;
1727 rPropOpt
.AddOpt( ESCHER_Prop_pictureContrast
, nContrast
);
1730 if (nBrightness
!= 0)
1731 rPropOpt
.AddOpt( ESCHER_Prop_pictureBrightness
, nBrightness
* 327 );
1733 sal_Int32 nCropL
= 0;
1734 sal_Int32 nCropR
= 0;
1735 sal_Int32 nCropT
= 0;
1736 sal_Int32 nCropB
= 0;
1737 if (const SwCropGrf
* pCropItem
= rNd
.GetSwAttrSet().GetItemIfSet(RES_GRFATR_CROPGRF
))
1739 nCropL
+= pCropItem
->GetLeft();
1740 nCropR
+= pCropItem
->GetRight();
1741 nCropT
+= pCropItem
->GetTop();
1742 nCropB
+= pCropItem
->GetBottom();
1745 // simulate border padding as a negative crop.
1746 if (const SvxBoxItem
* pBoxItem
= rFormat
.GetItemIfSet(RES_BOX
, false))
1748 nCropL
-= pBoxItem
->GetDistance( SvxBoxItemLine::LEFT
);
1749 nCropR
-= pBoxItem
->GetDistance( SvxBoxItemLine::RIGHT
);
1750 nCropT
-= pBoxItem
->GetDistance( SvxBoxItemLine::TOP
);
1751 nCropB
-= pBoxItem
->GetDistance( SvxBoxItemLine::BOTTOM
);
1754 const Size
aSz( rNd
.GetTwipSize() );
1756 rPropOpt
.AddOpt( ESCHER_Prop_cropFromLeft
, ToFract16( nCropL
, aSz
.Width()) );
1758 rPropOpt
.AddOpt( ESCHER_Prop_cropFromRight
, ToFract16( nCropR
, aSz
.Width()));
1760 rPropOpt
.AddOpt( ESCHER_Prop_cropFromTop
, ToFract16( nCropT
, aSz
.Height()));
1762 rPropOpt
.AddOpt( ESCHER_Prop_cropFromBottom
, ToFract16( nCropB
, aSz
.Height()));
1765 void SwBasicEscherEx::SetPicId(const SdrObject
&, sal_uInt32
,
1766 EscherPropertyContainer
&)
1770 void SwEscherEx::SetPicId(const SdrObject
&rSdrObj
, sal_uInt32 nShapeId
,
1771 EscherPropertyContainer
&rPropOpt
)
1773 m_pTextBxs
->Append(rSdrObj
, nShapeId
);
1774 sal_uInt32 nPicId
= m_pTextBxs
->Count();
1776 rPropOpt
.AddOpt( ESCHER_Prop_pictureId
, nPicId
);
1779 sal_Int32
SwBasicEscherEx::WriteOLEFlyFrame(const SwFrameFormat
& rFormat
, sal_uInt32 nShapeId
)
1781 sal_Int32 nBorderThick
= 0;
1782 if (const SdrObject
* pSdrObj
= rFormat
.FindRealSdrObject())
1784 SwNodeIndex
aIdx(*rFormat
.GetContent().GetContentIdx(), 1);
1785 SwOLENode
& rOLENd
= *aIdx
.GetNode().GetOLENode();
1786 sal_Int64 nAspect
= rOLENd
.GetAspect();
1788 uno::Reference
< embed::XEmbeddedObject
> xObj(rOLENd
.GetOLEObj().GetOleRef());
1790 // the rectangle is used to transport the size of the object
1791 // the left, top corner is set to ( 0, 0 ) by default constructor,
1792 // if the width and height are set correctly bRectIsSet should be set to true
1793 awt::Rectangle aRect
;
1794 bool bRectIsSet
= false;
1796 // TODO/LATER: should the icon size be stored in case of iconified object?
1797 if ( xObj
.is() && nAspect
!= embed::Aspects::MSOLE_ICON
)
1801 awt::Size aSize
= xObj
->getVisualAreaSize( nAspect
);
1802 aRect
.Width
= aSize
.Width
;
1803 aRect
.Height
= aSize
.Height
;
1806 catch( const uno::Exception
& )
1812 Export floating ole2 .doc ver 8+ wmf ole2 previews as emf previews
1813 instead ==> allows unicode text to be preserved
1815 #ifdef OLE_PREVIEW_AS_EMF
1816 const Graphic
* pGraphic
= rOLENd
.GetGraphic();
1818 OpenContainer(ESCHER_SpContainer
);
1820 EscherPropertyContainer aPropOpt
;
1821 const SwMirrorGrf
&rMirror
= rOLENd
.GetSwAttrSet().GetMirrorGrf();
1822 WriteOLEPicture(aPropOpt
,
1823 AddMirrorFlags(ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
| ShapeFlag::OLEShape
, rMirror
),
1824 pGraphic
? *pGraphic
: Graphic(), *pSdrObj
, nShapeId
, bRectIsSet
? &aRect
: nullptr );
1826 nBorderThick
= WriteFlyFrameAttr(rFormat
, mso_sptPictureFrame
, aPropOpt
);
1827 WriteGrfAttr(rOLENd
, rFormat
, aPropOpt
);
1828 aPropOpt
.Commit(GetStream());
1830 // store anchor attribute
1831 WriteFrameExtraData( rFormat
);
1833 CloseContainer(); // ESCHER_SpContainer
1835 return nBorderThick
;
1838 void SwBasicEscherEx::WriteBrushAttr(const SvxBrushItem
&rBrush
,
1839 EscherPropertyContainer
& rPropOpt
)
1841 bool bSetOpacity
= false;
1842 sal_uInt32 nOpaque
= 0;
1843 if (const GraphicObject
*pGraphicObject
= rBrush
.GetGraphicObject())
1845 OString aUniqueId
= pGraphicObject
->GetUniqueID();
1846 if (!aUniqueId
.isEmpty())
1848 sal_uInt32 nBlibId
= mxGlobal
->GetBlibID(*QueryPictureStream(), *pGraphicObject
);
1850 rPropOpt
.AddOpt(ESCHER_Prop_fillBlip
,nBlibId
,true);
1853 nOpaque
= 255 - pGraphicObject
->GetAttr().GetAlpha();
1857 rPropOpt
.AddOpt( ESCHER_Prop_fillType
, ESCHER_FillPicture
);
1858 rPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x140014 );
1859 rPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, 0 );
1863 sal_uInt32 nFillColor
= GetColor(rBrush
.GetColor());
1864 rPropOpt
.AddOpt( ESCHER_Prop_fillColor
, nFillColor
);
1865 rPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, nFillColor
^ 0xffffff );
1866 rPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100010 );
1868 nOpaque
= 255 - rBrush
.GetColor().GetAlpha();
1875 nOpaque
= (nOpaque
* 100) / 0xFE;
1876 nOpaque
= ((100 - nOpaque
) << 16) / 100;
1877 rPropOpt
.AddOpt(ESCHER_Prop_fillOpacity
, nOpaque
);
1881 sal_Int32
SwBasicEscherEx::WriteFlyFrameAttr(const SwFrameFormat
& rFormat
,
1882 MSO_SPT eShapeType
, EscherPropertyContainer
& rPropOpt
)
1884 sal_Int32 nLineWidth
=0;
1885 bool bFirstLine
= true;
1886 if (const SvxBoxItem
* pItem
= rFormat
.GetItemIfSet(RES_BOX
))
1888 static const o3tl::enumarray
<SvxBoxItemLine
, sal_uInt16
> aExhperProp
=
1890 sal_uInt16(ESCHER_Prop_dyTextTop
), sal_uInt16(ESCHER_Prop_dyTextBottom
),
1891 sal_uInt16(ESCHER_Prop_dxTextLeft
), sal_uInt16(ESCHER_Prop_dxTextRight
)
1893 const SvxBorderLine
* pLine
;
1895 for( SvxBoxItemLine n
: o3tl::enumrange
<SvxBoxItemLine
>() )
1897 pLine
= pItem
->GetLine( n
);
1898 if( nullptr != pLine
)
1902 sal_uInt32 nLineColor
= GetColor(pLine
->GetColor());
1903 rPropOpt
.AddOpt( ESCHER_Prop_lineColor
, nLineColor
);
1904 rPropOpt
.AddOpt( ESCHER_Prop_lineBackColor
,
1905 nLineColor
^ 0xffffff );
1907 MSO_LineStyle eStyle
;
1908 if( pLine
->isDouble() )
1911 nLineWidth
= pLine
->GetWidth();
1912 if( pLine
->GetInWidth() == pLine
->GetOutWidth() )
1913 eStyle
= mso_lineDouble
;
1914 else if( pLine
->GetInWidth() < pLine
->GetOutWidth() )
1915 eStyle
= mso_lineThickThin
;
1917 eStyle
= mso_lineThinThick
;
1922 eStyle
= mso_lineSimple
;
1923 nLineWidth
= pLine
->GetWidth();
1926 rPropOpt
.AddOpt( ESCHER_Prop_lineStyle
, eStyle
);
1927 rPropOpt
.AddOpt( ESCHER_Prop_lineWidth
,
1928 DrawModelToEmu( nLineWidth
));
1930 MSO_LineDashing eDashing
= mso_lineSolid
;
1931 switch (pLine
->GetBorderLineStyle())
1933 case SvxBorderLineStyle::DASHED
:
1934 eDashing
= mso_lineDashGEL
;
1936 case SvxBorderLineStyle::DOTTED
:
1937 eDashing
= mso_lineDotGEL
;
1939 case SvxBorderLineStyle::SOLID
:
1943 rPropOpt
.AddOpt( ESCHER_Prop_lineDashing
, eDashing
);
1944 rPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x8000E );
1946 //Use import logic to determine how much of border will go
1948 nLineWidth
= SwMSDffManager::GetEscherLineMatch(
1949 eStyle
,eShapeType
,nLineWidth
);
1952 rPropOpt
.AddOpt( aExhperProp
[ n
], DrawModelToEmu(
1953 pItem
->GetDistance( n
) ));
1956 rPropOpt
.AddOpt( aExhperProp
[ n
], DrawModelToEmu(pItem
->GetDistance( n
)) );
1961 rPropOpt
.AddOpt( ESCHER_Prop_dyTextTop
, 0 );
1962 rPropOpt
.AddOpt( ESCHER_Prop_dyTextBottom
, 0 );
1963 rPropOpt
.AddOpt( ESCHER_Prop_dxTextLeft
, 0 );
1964 rPropOpt
.AddOpt( ESCHER_Prop_dxTextRight
, 0 );
1967 if( bFirstLine
) // no valid line found
1969 rPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x80000 );
1971 const SwAttrSet
& rAttrSet
= rFormat
.GetAttrSet();
1972 if (rAttrSet
.GetItemIfSet(RES_BOX
, false))
1974 if (const SvxShadowItem
* pSI
=rAttrSet
.GetItemIfSet(RES_SHADOW
))
1976 constexpr sal_uInt32 nShadowType
= 131074; // shadow type of ms word. need to set the default value.
1978 Color nColor
= pSI
->GetColor();
1980 = o3tl::convert(pSI
->GetWidth(), o3tl::Length::twip
, o3tl::Length::emu
);
1982 = o3tl::convert(pSI
->GetWidth(), o3tl::Length::twip
, o3tl::Length::emu
);
1984 SvxShadowLocation eLocation
= pSI
->GetLocation();
1985 if( (eLocation
!=SvxShadowLocation::NONE
) && (pSI
->GetWidth()!=0) )
1989 case SvxShadowLocation::TopLeft
:
1995 case SvxShadowLocation::TopRight
:
2000 case SvxShadowLocation::BottomLeft
:
2005 case SvxShadowLocation::BottomRight
:
2011 rPropOpt
.AddOpt( DFF_Prop_shadowColor
, wwUtility::RGBToBGR(nColor
));
2012 rPropOpt
.AddOpt( DFF_Prop_shadowOffsetX
, nOffX
);
2013 rPropOpt
.AddOpt( DFF_Prop_shadowOffsetY
, nOffY
);
2014 rPropOpt
.AddOpt( DFF_Prop_fshadowObscured
, nShadowType
);
2019 // SwWW8ImplReader::Read_GrafLayer() imports these as opaque
2020 // unconditionally, so if both are true, don't export the property.
2021 const bool bIsInHeader
= sw::IsFlyFrameFormatInHeader(rFormat
);
2022 const bool bIsThrough
= rFormat
.GetSurround().GetValue() == css::text::WrapTextMode_THROUGH
;
2024 // Anything (like a transparent image) that allows text to wrap through should not force a non-transparent background,
2025 // and neither should the commonly seen backgrounds anchored in headers.
2026 if (bIsInHeader
|| bIsThrough
)
2028 std::unique_ptr
<SvxBrushItem
> aBrush(rFormat
.makeBackgroundBrushItem());
2029 WriteBrushAttr(*aBrush
, rPropOpt
);
2033 // for unknown reasons, force exporting a non-transparent background on fly frames.
2034 std::shared_ptr
<SvxBrushItem
> aBrush(mrWrt
.TrueFrameBgBrush(rFormat
));
2038 WriteBrushAttr(*aBrush
, rPropOpt
);
2042 const SdrObject
* pObj
= rFormat
.FindRealSdrObject();
2044 if( pObj
&& (pObj
->GetLayer() == GetHellLayerId() ||
2045 pObj
->GetLayer() == GetInvisibleHellId() ) && !(bIsInHeader
&& bIsThrough
))
2047 rPropOpt
.AddOpt( ESCHER_Prop_fPrint
, 0x200020 );
2050 PreWriteHyperlinkWithinFly(rFormat
,rPropOpt
);
2055 sal_Int32
SwEscherEx::WriteFlyFrameAttr(const SwFrameFormat
& rFormat
, MSO_SPT eShapeType
,
2056 EscherPropertyContainer
& rPropOpt
)
2058 sal_Int32 nLineWidth
= SwBasicEscherEx::WriteFlyFrameAttr(rFormat
, eShapeType
,
2062 These are not in SwBasicEscherEx::WriteFlyFrameAttr because inline objs
2063 can't do it in word and it hacks it in by stretching the graphic that
2064 way, perhaps we should actually draw in this space into the graphic we
2067 if (const SvxLRSpaceItem
* pItem
= rFormat
.GetItemIfSet(RES_LR_SPACE
))
2069 rPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistLeft
,
2070 DrawModelToEmu( pItem
->GetLeft() ) );
2071 rPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistRight
,
2072 DrawModelToEmu( pItem
->GetRight() ) );
2076 rPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistLeft
, 0 );
2077 rPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistRight
, 0 );
2080 if (const SvxULSpaceItem
* pItem
= rFormat
.GetItemIfSet(RES_UL_SPACE
))
2082 rPropOpt
.AddOpt( ESCHER_Prop_dyWrapDistTop
,
2083 DrawModelToEmu( pItem
->GetUpper() ) );
2084 rPropOpt
.AddOpt( ESCHER_Prop_dyWrapDistBottom
,
2085 DrawModelToEmu( pItem
->GetLower() ) );
2088 if (rFormat
.GetSurround().IsContour())
2090 if (const SwNoTextNode
*pNd
= GetNoTextNodeFromSwFrameFormat(rFormat
))
2092 const tools::PolyPolygon
*pPolyPoly
= pNd
->HasContour();
2093 if (pPolyPoly
&& pPolyPoly
->Count())
2095 tools::Polygon aPoly
= CorrectWordWrapPolygonForExport(*pPolyPoly
, pNd
, /*bCorrectCrop=*/false);
2096 SvMemoryStream aPolyDump
;
2097 aPolyDump
.SetEndian(SvStreamEndian::LITTLE
);
2099 sal_uInt16 nLen
= aPoly
.GetSize();
2100 aPolyDump
.WriteUInt16( nLen
);
2101 aPolyDump
.WriteUInt16( nLen
);
2102 aPolyDump
.WriteUInt16( 8 );
2103 for (sal_uInt16 nI
= 0; nI
< nLen
; ++nI
)
2105 aPolyDump
.WriteUInt32( aPoly
[nI
].X() );
2106 aPolyDump
.WriteUInt32( aPoly
[nI
].Y() );
2109 rPropOpt
.AddOpt(DFF_Prop_pWrapPolygonVertices
, false, 0, aPolyDump
);
2114 PreWriteHyperlinkWithinFly(rFormat
,rPropOpt
);
2119 void SwBasicEscherEx::Init()
2121 MapUnit eMap
= MapUnit::MapTwip
;
2122 if (SwDrawModel
*pModel
= mrWrt
.m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel())
2124 // PPT works only with units of 576DPI
2125 // WW however is using twips, i.e 1440DPI.
2126 eMap
= pModel
->GetScaleUnit();
2129 // MS-DFF-Properties mostly are in EMU (English Metric Units)
2130 Fraction aFact
= conversionFract(o3tl::Length::mm100
, o3tl::Length::emu
);
2131 aFact
/= GetMapFactor(MapUnit::Map100thMM
, eMap
).X();
2132 mnEmuMul
= aFact
.GetNumerator();
2133 mnEmuDiv
= aFact
.GetDenominator();
2135 SetHellLayerId(mrWrt
.m_rDoc
.getIDocumentDrawModelAccess().GetHellId());
2138 sal_Int32
SwBasicEscherEx::ToFract16(sal_Int32 nVal
, sal_uInt32 nMax
)
2144 sal_Int32 nMSVal
= (nVal
/ 65536) * nMax
;
2145 nMSVal
+= (nVal
* 65536) / nMax
;
2148 // negative fraction does not have "-0", fractional part is always
2149 // positive: -0.4 represented as -1 + 0.6
2150 sal_Int32
const nDiv
= (nVal
/ sal_Int32(nMax
)) - 1;
2151 sal_uInt32 nMSVal
= (sal_uInt32(nDiv
) << 16) & 0xffff0000;
2152 nMSVal
+= (nVal
* 65536) / sal_Int32(nMax
) + (-nDiv
* 65536);
2159 SdrLayerID
SwBasicEscherEx::GetInvisibleHellId() const
2161 return mrWrt
.m_rDoc
.getIDocumentDrawModelAccess().GetInvisibleHellId();
2164 void SwBasicEscherEx::WritePictures()
2166 if( SvStream
* pPicStrm
= static_cast< SwEscherExGlobal
& >( *mxGlobal
).GetPictureStream() )
2168 // set the blip - entries to the correct stream pos
2169 sal_Int32 nEndPos
= pPicStrm
->Tell();
2170 mxGlobal
->WriteBlibStoreEntry(*mpEscherStrm
, 1, nEndPos
);
2173 mpEscherStrm
->WriteStream( *pPicStrm
);
2177 SwEscherEx::SwEscherEx(SvStream
* pStrm
, WW8Export
& rWW8Wrt
)
2178 : SwBasicEscherEx(pStrm
, rWW8Wrt
),
2181 m_aHostData
.SetClientData(&m_aWinwordAnchoring
);
2182 OpenContainer( ESCHER_DggContainer
);
2184 sal_uInt16 nColorCount
= 4;
2185 pStrm
->WriteUInt16( nColorCount
<< 4 ) // instance
2186 .WriteUInt16( ESCHER_SplitMenuColors
) // record type
2187 .WriteUInt32( nColorCount
* 4 ) // size
2188 .WriteUInt32( 0x08000004 )
2189 .WriteUInt32( 0x08000001 )
2190 .WriteUInt32( 0x08000002 )
2191 .WriteUInt32( 0x100000f7 );
2193 CloseContainer(); // ESCHER_DggContainer
2195 sal_uInt8 i
= 2; // for header/footer and the other
2196 PlcDrawObj
*pSdrObjs
= mrWrt
.m_pHFSdrObjs
.get();
2197 m_pTextBxs
= mrWrt
.m_pHFTextBxs
.get();
2199 // if no header/footer -> skip over
2200 if (!pSdrObjs
->size())
2203 pSdrObjs
= mrWrt
.m_pSdrObjs
.get();
2204 m_pTextBxs
= mrWrt
.m_pTextBxs
.get();
2207 for( ; i
--; pSdrObjs
= mrWrt
.m_pSdrObjs
.get(), m_pTextBxs
= mrWrt
.m_pTextBxs
.get() )
2209 // "dummy char" (or any Count ?) - why? Only Microsoft knows it.
2210 GetStream().WriteChar( i
);
2212 OpenContainer( ESCHER_DgContainer
);
2216 sal_uLong nSecondShapeId
= pSdrObjs
== mrWrt
.m_pSdrObjs
.get() ? GenerateShapeId() : 0;
2218 // write now all Writer-/DrawObjects
2219 DrawObjPointerVector aSorted
;
2220 MakeZOrderArrAndFollowIds(pSdrObjs
->GetObjArr(), aSorted
);
2222 sal_uInt32 nShapeId
=0;
2223 for (auto& pObj
: aSorted
)
2225 sal_Int32 nBorderThick
=0;
2226 OSL_ENSURE(pObj
, "impossible");
2229 const ww8::Frame
&rFrame
= pObj
->maContent
;
2230 const SwFrameFormat
& rFormat
= rFrame
.GetFrameFormat();
2232 switch (rFrame
.GetWriterType())
2234 case ww8::Frame::eTextBox
:
2235 case ww8::Frame::eOle
:
2236 case ww8::Frame::eGraphic
:
2237 nBorderThick
= WriteFlyFrame(*pObj
, nShapeId
, aSorted
);
2239 case ww8::Frame::eFormControl
:
2240 nShapeId
= GenerateShapeId();
2241 WriteOCXControl(rFormat
, nShapeId
);
2243 case ww8::Frame::eDrawing
:
2245 m_aWinwordAnchoring
.SetAnchoring(rFormat
);
2246 const SdrObject
* pSdrObj
= rFormat
.FindRealSdrObject();
2249 nShapeId
= AddSdrObject(*pSdrObj
);
2251 #if OSL_DEBUG_LEVEL > 0
2253 OSL_ENSURE( false, "Where is the SDR-Object?" );
2263 nShapeId
= AddDummyShape();
2266 pObj
->SetShapeDetails(nShapeId
, nBorderThick
);
2269 EndSdrObjectPage(); // ???? Bugfix for 74724
2271 if( nSecondShapeId
)
2273 OpenContainer( ESCHER_SpContainer
);
2275 AddShape( ESCHER_ShpInst_Rectangle
,
2276 ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
| ShapeFlag::Background
,
2279 EscherPropertyContainer aPropOpt
;
2280 const SwFrameFormat
&rFormat
= mrWrt
.m_rDoc
.GetPageDesc(0).GetMaster();
2281 if (const SvxBrushItem
* pBrush
= rFormat
.GetItemIfSet(RES_BACKGROUND
))
2283 WriteBrushAttr(*pBrush
, aPropOpt
);
2285 SvxGraphicPosition ePos
= pBrush
->GetGraphicPos();
2286 if( ePos
!= GPOS_NONE
&& ePos
!= GPOS_AREA
)
2288 /* #i56806# 0x033F parameter specifies a 32-bit field of shape boolean properties.
2289 0x10001 means fBackground and fUsefBackground flag are true thus background
2290 picture will be shown as "tiled" fill.*/
2291 aPropOpt
.AddOpt( ESCHER_Prop_fBackground
, 0x10001 );
2294 aPropOpt
.AddOpt( ESCHER_Prop_lineColor
, 0x8000001 );
2295 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x00080008 );
2296 aPropOpt
.AddOpt( ESCHER_Prop_shadowColor
, 0x8000002 );
2297 aPropOpt
.AddOpt( ESCHER_Prop_lineWidth
, 0 );
2299 aPropOpt
.Commit( *pStrm
);
2301 AddAtom( 4, ESCHER_ClientData
);
2302 GetStream().WriteInt32( 1 );
2304 CloseContainer(); // ESCHER_SpContainer
2306 CloseContainer(); // ESCHER_DgContainer
2310 SwEscherEx::~SwEscherEx()
2314 void SwEscherEx::FinishEscher()
2316 mpEscherStrm
->Seek(0);
2317 mrWrt
.m_pTableStrm
->WriteStream( *mpEscherStrm
);
2318 delete mpEscherStrm
;
2319 mpEscherStrm
= nullptr;
2325 template<typename OrientType
>
2326 void lcl_SetRelationOrient(OrientType
& rOrient
, const sw::WW8AnchorConv eConv
, const std::function
<void()>& fDefault
)
2330 case sw::WW8AnchorConv::RELTOTABLECELL
:
2332 rOrient
.SetRelationOrient(text::RelOrientation::PAGE_PRINT_AREA
);
2334 case sw::WW8AnchorConv::CONV2PG
:
2335 rOrient
.SetRelationOrient(text::RelOrientation::PAGE_FRAME
);
2337 case sw::WW8AnchorConv::CONV2COL_OR_PARA
:
2338 rOrient
.SetRelationOrient(text::RelOrientation::FRAME
);
2340 case sw::WW8AnchorConv::CONV2CHAR
:
2341 rOrient
.SetRelationOrient(text::RelOrientation::CHAR
);
2343 case sw::WW8AnchorConv::CONV2LINE
:
2344 rOrient
.SetRelationOrient(text::RelOrientation::TEXT_LINE
);
2351 /** method to perform conversion of positioning attributes with the help
2352 of corresponding layout information
2355 Because most of the Writer object positions doesn't correspond to the
2356 object positions in WW8, this method converts the positioning
2357 attributes. For this conversion the corresponding layout information
2358 is needed. If no layout information exists - e.g. no layout exists - no
2359 conversion is performed.
2360 No conversion is performed for as-character anchored objects. Whose
2361 object positions are already treated special in method <WriteData(..)>.
2364 input/output parameter - containing the current horizontal position
2365 attributes, which are converted by this method.
2368 input/output parameter - containing the current vertical position
2369 attributes, which are converted by this method.
2371 @param _rFrameFormat
2372 input parameter - frame format of the anchored object
2374 @return boolean, indicating, if a conversion has been performed.
2376 bool WinwordAnchoring::ConvertPosition( SwFormatHoriOrient
& _iorHoriOri
,
2377 SwFormatVertOrient
& _iorVertOri
,
2378 const SwFrameFormat
& _rFrameFormat
)
2380 const RndStdIds eAnchor
= _rFrameFormat
.GetAnchor().GetAnchorId();
2382 if ( (RndStdIds::FLY_AS_CHAR
== eAnchor
) || (RndStdIds::FLY_AT_FLY
== eAnchor
) )
2384 // no conversion for as-character or at frame anchored objects
2388 // determine value of attribute 'Follow text flow', because positions aligned
2389 // at page areas have to be converted, if it's set.
2390 const bool bFollowTextFlow
= _rFrameFormat
.GetFollowTextFlow().GetValue();
2392 // check, if horizontal and vertical position have to be converted due to
2393 // the fact, that the object is anchored at a paragraph, which has a "column
2394 // break before" attribute
2395 bool bConvDueToAnchoredAtColBreakPara( false );
2396 if ( ( (eAnchor
== RndStdIds::FLY_AT_PARA
) || (eAnchor
== RndStdIds::FLY_AT_CHAR
) ) &&
2397 _rFrameFormat
.GetAnchor().GetAnchorNode() &&
2398 _rFrameFormat
.GetAnchor().GetAnchorNode()->IsTextNode() )
2400 SwTextNode
& rAnchorTextNode
=
2401 dynamic_cast<SwTextNode
&>(*_rFrameFormat
.GetAnchor().GetAnchorNode());
2402 const SvxFormatBreakItem
& rBreak
= rAnchorTextNode
.GetAttr(RES_BREAK
);
2403 if (rBreak
.GetBreak() == SvxBreak::ColumnBefore
)
2405 bConvDueToAnchoredAtColBreakPara
= true;
2409 sw::WW8AnchorConv
eHoriConv(sw::WW8AnchorConv::NO_CONV
);
2410 sw::WW8AnchorConv
eVertConv(sw::WW8AnchorConv::NO_CONV
);
2411 // convert horizontal position, if needed
2414 // determine, if conversion has to be performed due to the position orientation
2415 bool bConvDueToOrientation( false );
2417 const sal_Int16 eHOri
= _iorHoriOri
.GetHoriOrient();
2418 bConvDueToOrientation
= eHOri
== text::HoriOrientation::LEFT
|| eHOri
== text::HoriOrientation::RIGHT
||
2419 eHOri
== text::HoriOrientation::INSIDE
|| eHOri
== text::HoriOrientation::OUTSIDE
||
2420 ( eHOri
!= text::HoriOrientation::CENTER
&& _iorHoriOri
.IsPosToggle() );
2423 // determine conversion type due to the position relation
2424 if ( bConvDueToAnchoredAtColBreakPara
)
2426 eHoriConv
= sw::WW8AnchorConv::CONV2PG
;
2428 else if ( _iorHoriOri
.IsPosToggle()
2429 && _iorHoriOri
.GetHoriOrient() == text::HoriOrientation::RIGHT
)
2431 eHoriConv
= sw::WW8AnchorConv::NO_CONV
;
2432 _iorHoriOri
.SetHoriOrient( text::HoriOrientation::OUTSIDE
);
2436 switch ( _iorHoriOri
.GetRelationOrient() )
2438 case text::RelOrientation::PAGE_FRAME
:
2439 case text::RelOrientation::PAGE_PRINT_AREA
:
2441 if ( bConvDueToOrientation
|| bFollowTextFlow
)
2442 eHoriConv
= sw::WW8AnchorConv::CONV2PG
;
2445 case text::RelOrientation::PAGE_LEFT
:
2446 case text::RelOrientation::PAGE_RIGHT
:
2448 // relation not supported by WW8. Thus, conversion always needed.
2449 eHoriConv
= sw::WW8AnchorConv::CONV2PG
;
2452 case text::RelOrientation::FRAME
:
2454 if ( bConvDueToOrientation
)
2455 eHoriConv
= sw::WW8AnchorConv::CONV2COL_OR_PARA
;
2458 case text::RelOrientation::PRINT_AREA
:
2459 case text::RelOrientation::FRAME_LEFT
:
2460 case text::RelOrientation::FRAME_RIGHT
:
2462 // relation not supported by WW8. Thus, conversion always needed.
2463 eHoriConv
= sw::WW8AnchorConv::CONV2COL_OR_PARA
;
2466 case text::RelOrientation::CHAR
:
2468 if ( bConvDueToOrientation
)
2469 eHoriConv
= sw::WW8AnchorConv::CONV2CHAR
;
2473 OSL_FAIL( "<WinwordAnchoring::ConvertPosition(..)> - unknown horizontal relation" );
2478 // convert vertical position, if needed
2481 // determine, if conversion has to be performed due to the position orientation
2482 bool bConvDueToOrientation( false );
2484 const sal_Int16 eVOri
= _iorVertOri
.GetVertOrient();
2485 bConvDueToOrientation
= ( eVOri
== text::VertOrientation::TOP
||
2486 eVOri
== text::VertOrientation::BOTTOM
||
2487 eVOri
== text::VertOrientation::CHAR_TOP
||
2488 eVOri
== text::VertOrientation::CHAR_BOTTOM
||
2489 eVOri
== text::VertOrientation::CHAR_CENTER
||
2490 eVOri
== text::VertOrientation::LINE_TOP
||
2491 eVOri
== text::VertOrientation::LINE_BOTTOM
||
2492 eVOri
== text::VertOrientation::LINE_CENTER
);
2495 // determine conversion type due to the position relation
2496 if ( bConvDueToAnchoredAtColBreakPara
)
2498 eVertConv
= sw::WW8AnchorConv::CONV2PG
;
2502 switch ( _iorVertOri
.GetRelationOrient() )
2504 case text::RelOrientation::PAGE_FRAME
:
2505 case text::RelOrientation::PAGE_PRINT_AREA
:
2507 if ( bConvDueToOrientation
|| bFollowTextFlow
)
2508 eVertConv
= sw::WW8AnchorConv::CONV2PG
;
2511 case text::RelOrientation::FRAME
:
2513 if ( bConvDueToOrientation
||
2514 _iorVertOri
.GetVertOrient() == text::VertOrientation::CENTER
)
2516 eVertConv
= sw::WW8AnchorConv::CONV2COL_OR_PARA
;
2520 case text::RelOrientation::PRINT_AREA
:
2522 // relation not supported by WW8. Thus, conversion always needed.
2523 eVertConv
= sw::WW8AnchorConv::CONV2COL_OR_PARA
;
2526 case text::RelOrientation::CHAR
:
2528 // relation not supported by WW8. Thus, conversion always needed.
2529 eVertConv
= sw::WW8AnchorConv::CONV2COL_OR_PARA
;
2532 case text::RelOrientation::TEXT_LINE
:
2534 if ( bConvDueToOrientation
||
2535 _iorVertOri
.GetVertOrient() == text::VertOrientation::NONE
)
2537 eVertConv
= sw::WW8AnchorConv::CONV2LINE
;
2541 case text::RelOrientation::PAGE_LEFT
:
2542 case text::RelOrientation::PAGE_RIGHT
:
2543 case text::RelOrientation::FRAME_LEFT
:
2544 case text::RelOrientation::FRAME_RIGHT
:
2546 OSL_FAIL( "<WinwordAnchoring::ConvertPosition(..)> - unknown vertical relation" );
2551 if (eVertConv
!= sw::WW8AnchorConv::NO_CONV
|| eHoriConv
!= sw::WW8AnchorConv::NO_CONV
)
2553 sw::WW8AnchorConvResult
aResult(eHoriConv
, eVertConv
);
2554 _rFrameFormat
.CallSwClientNotify(sw::WW8AnchorConvHint(aResult
));
2555 if(!aResult
.m_bConverted
)
2557 if (eHoriConv
!= sw::WW8AnchorConv::NO_CONV
)
2559 lcl_SetRelationOrient(_iorHoriOri
, eHoriConv
, [&_iorHoriOri
]() {_iorHoriOri
.SetHoriOrient(text::HoriOrientation::NONE
);} );
2560 _iorHoriOri
.SetPos(aResult
.m_aPos
.X());
2562 if (eVertConv
!= sw::WW8AnchorConv::NO_CONV
)
2564 lcl_SetRelationOrient(_iorVertOri
, eVertConv
, [&_iorVertOri
]() {_iorVertOri
.SetVertOrient(text::VertOrientation::NONE
);} );
2565 _iorVertOri
.SetPos(aResult
.m_aPos
.Y());
2572 void WinwordAnchoring::SetAnchoring(const SwFrameFormat
& rFormat
)
2574 const RndStdIds eAnchor
= rFormat
.GetAnchor().GetAnchorId();
2575 mbInline
= (eAnchor
== RndStdIds::FLY_AS_CHAR
);
2577 mnGroupShapeBooleanProperties
= 0;
2578 if (!rFormat
.GetFollowTextFlow().GetValue())
2580 // bit32: fUseLayoutInCell, bit16: fLayoutInCell
2581 mnGroupShapeBooleanProperties
|= 0x80000000;
2584 SwFormatHoriOrient rHoriOri
= rFormat
.GetHoriOrient();
2585 SwFormatVertOrient rVertOri
= rFormat
.GetVertOrient();
2587 // #i30669# - convert the positioning attributes.
2588 // Most positions are converted, if layout information exists.
2589 const bool bPosConverted
= ConvertPosition( rHoriOri
, rVertOri
, rFormat
);
2591 const sal_Int16 eHOri
= rHoriOri
.GetHoriOrient();
2592 const sal_Int16 eVOri
= rVertOri
.GetVertOrient(); // #i22673#
2594 const sal_Int16 eHRel
= rHoriOri
.GetRelationOrient();
2595 const sal_Int16 eVRel
= rVertOri
.GetRelationOrient();
2597 // horizontal Adjustment
2601 case text::HoriOrientation::NONE
:
2604 case text::HoriOrientation::LEFT
:
2607 case text::HoriOrientation::CENTER
:
2610 case text::HoriOrientation::RIGHT
:
2613 case text::HoriOrientation::INSIDE
:
2616 case text::HoriOrientation::OUTSIDE
:
2621 // vertical Adjustment
2623 // When adjustment is vertically relative to line or to char
2624 // bottom becomes top and vice versa
2625 const bool bVertSwap
= !bPosConverted
&&
2626 ( (eVRel
== text::RelOrientation::CHAR
) ||
2627 (eVRel
== text::RelOrientation::TEXT_LINE
) );
2631 case text::VertOrientation::NONE
:
2634 case text::VertOrientation::TOP
:
2635 case text::VertOrientation::LINE_TOP
:
2636 case text::VertOrientation::CHAR_TOP
:
2637 mnYAlign
= bVertSwap
? 3 : 1;
2639 case text::VertOrientation::CENTER
:
2640 case text::VertOrientation::LINE_CENTER
:
2643 case text::VertOrientation::BOTTOM
:
2644 case text::VertOrientation::LINE_BOTTOM
:
2645 case text::VertOrientation::CHAR_BOTTOM
:
2646 mnYAlign
= bVertSwap
? 1 : 3;
2650 // Adjustment is horizontally relative to...
2653 case text::RelOrientation::PAGE_PRINT_AREA
:
2656 case text::RelOrientation::PAGE_FRAME
:
2657 case text::RelOrientation::PAGE_LEFT
: //:-(
2658 case text::RelOrientation::PAGE_RIGHT
: //:-(
2661 case text::RelOrientation::FRAME
:
2662 case text::RelOrientation::FRAME_LEFT
: //:-(
2663 case text::RelOrientation::FRAME_RIGHT
: //:-(
2664 if (eAnchor
== RndStdIds::FLY_AT_PAGE
)
2669 case text::RelOrientation::PRINT_AREA
:
2670 if (eAnchor
== RndStdIds::FLY_AT_PAGE
)
2675 case text::RelOrientation::CHAR
:
2678 case text::RelOrientation::TEXT_LINE
:
2682 // Adjustment is vertically relative to...
2685 case text::RelOrientation::PAGE_PRINT_AREA
:
2688 case text::RelOrientation::PAGE_FRAME
:
2691 case text::RelOrientation::PRINT_AREA
:
2692 if (eAnchor
== RndStdIds::FLY_AT_PAGE
)
2697 case text::RelOrientation::FRAME
:
2698 if (eAnchor
== RndStdIds::FLY_AT_PAGE
)
2703 case text::RelOrientation::CHAR
:
2704 case text::RelOrientation::TEXT_LINE
: // #i22673# - vertical alignment at top of line
2705 case text::RelOrientation::PAGE_LEFT
: //nonsense
2706 case text::RelOrientation::PAGE_RIGHT
: //nonsense
2707 case text::RelOrientation::FRAME_LEFT
: //nonsense
2708 case text::RelOrientation::FRAME_RIGHT
: //nonsense
2714 void SwEscherEx::WriteFrameExtraData( const SwFrameFormat
& rFormat
)
2716 m_aWinwordAnchoring
.SetAnchoring(rFormat
);
2717 m_aWinwordAnchoring
.WriteData(*this);
2719 AddAtom(4, ESCHER_ClientAnchor
);
2720 GetStream().WriteInt32( 0 );
2722 AddAtom(4, ESCHER_ClientData
);
2723 GetStream().WriteInt32( 1 );
2726 sal_Int32
SwEscherEx::WriteFlyFrame(const DrawObj
&rObj
, sal_uInt32
&rShapeId
,
2727 DrawObjPointerVector
&rPVec
)
2729 const SwFrameFormat
&rFormat
= rObj
.maContent
.GetFrameFormat();
2731 // check for textflyframe and if it is the first in a Chain
2732 sal_Int32 nBorderThick
= 0;
2733 const SwNodeIndex
* pNdIdx
= rFormat
.GetContent().GetContentIdx();
2736 SwNodeIndex
aIdx( *pNdIdx
, 1 );
2737 switch( aIdx
.GetNode().GetNodeType() )
2739 case SwNodeType::Grf
:
2740 rShapeId
= GenerateShapeId();
2741 nBorderThick
= WriteGrfFlyFrame( rFormat
, rShapeId
);
2743 case SwNodeType::Ole
:
2744 rShapeId
= GenerateShapeId();
2745 nBorderThick
= WriteOLEFlyFrame( rFormat
, rShapeId
);
2748 if (const SdrObject
* pObj
= rFormat
.FindRealSdrObject())
2750 // check for the first in a Chain
2752 sal_uInt16 nOff
= 0;
2753 const SwFrameFormat
* pFormat
= &rFormat
, *pPrev
;
2754 while( nullptr != ( pPrev
= pFormat
->GetChain().GetPrev() ))
2760 rShapeId
= GetFlyShapeId(rFormat
, rObj
.mnHdFtIndex
, rPVec
);
2763 nTextId
= m_pTextBxs
->GetPos( pObj
);
2764 if( USHRT_MAX
== nTextId
)
2766 m_pTextBxs
->Append( *pObj
, rShapeId
);
2767 nTextId
= m_pTextBxs
->Count();
2774 const SdrObject
* pPrevObj
= pFormat
->FindRealSdrObject();
2775 nTextId
= m_pTextBxs
->GetPos( pPrevObj
);
2776 if( USHRT_MAX
== nTextId
)
2778 sal_uInt32 nPrevShapeId
=
2779 GetFlyShapeId(*pFormat
, rObj
.mnHdFtIndex
, rPVec
);
2780 m_pTextBxs
->Append( *pPrevObj
, nPrevShapeId
);
2781 nTextId
= m_pTextBxs
->Count();
2789 nBorderThick
= WriteTextFlyFrame(rObj
, rShapeId
, nTextId
, rPVec
);
2792 //In browse mode the sdr object doesn't always exist. For example, the
2793 //object is in the hidden header/footer. We save the fmt directly
2794 //in such cases; we copy most of the logic from the block above
2795 const bool bBrowseMode
= rFormat
.getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE
);
2796 if( bBrowseMode
&& rFormat
.GetDoc())
2798 if( !rFormat
.GetChain().GetPrev() )//obj in header/footer?
2800 rShapeId
= GetFlyShapeId(rFormat
, rObj
.mnHdFtIndex
, rPVec
);
2801 m_pTextBxs
->Append( &rFormat
, rShapeId
);
2802 sal_uInt32 nTextId
= m_pTextBxs
->Count();
2805 nBorderThick
= WriteTextFlyFrame(rObj
, rShapeId
, nTextId
, rPVec
);
2811 return nBorderThick
;
2814 static sal_uInt16
FindPos(const SwFrameFormat
&rFormat
, unsigned int nHdFtIndex
,
2815 DrawObjPointerVector
&rPVec
)
2817 auto aIter
= std::find_if(rPVec
.begin(), rPVec
.end(),
2818 [&rFormat
, nHdFtIndex
](const DrawObj
* pObj
) {
2819 OSL_ENSURE(pObj
, "Impossible");
2821 nHdFtIndex
== pObj
->mnHdFtIndex
&&
2822 &rFormat
== (&pObj
->maContent
.GetFrameFormat());
2824 if (aIter
!= rPVec
.end())
2825 return static_cast< sal_uInt16
>(aIter
- rPVec
.begin());
2829 sal_Int32
SwEscherEx::WriteTextFlyFrame(const DrawObj
&rObj
, sal_uInt32 nShapeId
,
2830 sal_uInt32 nTextBox
, DrawObjPointerVector
&rPVec
)
2832 const SwFrameFormat
&rFormat
= rObj
.maContent
.GetFrameFormat();
2833 SvxFrameDirection nDirection
= rObj
.mnDirection
;
2835 sal_Int32 nBorderThick
=0;
2836 OpenContainer( ESCHER_SpContainer
);
2838 AddShape( ESCHER_ShpInst_TextBox
, ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
, nShapeId
);
2839 EscherPropertyContainer aPropOpt
;
2840 aPropOpt
.AddOpt(ESCHER_Prop_lTxid
, nTextBox
);
2841 if (const SwFrameFormat
*pNext
= rFormat
.GetChain().GetNext())
2843 sal_uInt16 nPos
= FindPos(*pNext
, rObj
.mnHdFtIndex
, rPVec
);
2844 if (USHRT_MAX
!= nPos
&& m_aFollowShpIds
[nPos
])
2845 aPropOpt
.AddOpt(ESCHER_Prop_hspNext
, m_aFollowShpIds
[nPos
]);
2847 nBorderThick
= WriteFlyFrameAttr( rFormat
, mso_sptTextBox
, aPropOpt
);
2854 OSL_ENSURE(false, "unknown direction type");
2856 case SvxFrameDirection::Horizontal_LR_TB
:
2857 nFlow
=mso_txflHorzN
;
2859 case SvxFrameDirection::Horizontal_RL_TB
:
2860 nFlow
=mso_txflHorzN
;
2862 case SvxFrameDirection::Vertical_LR_TB
: //not really possible in word
2863 case SvxFrameDirection::Vertical_RL_TB
:
2864 nFlow
=mso_txflTtoBA
;
2866 case SvxFrameDirection::Vertical_LR_BT
:
2867 nFlow
= mso_txflBtoT
;
2870 aPropOpt
.AddOpt( ESCHER_Prop_txflTextFlow
, nFlow
);
2872 aPropOpt
.Commit( GetStream() );
2874 // store anchor attribute
2875 WriteFrameExtraData( rFormat
);
2877 AddAtom( 4, ESCHER_ClientTextbox
); GetStream().WriteUInt32( nTextBox
);
2879 CloseContainer(); // ESCHER_SpContainer
2880 return nBorderThick
;
2883 void SwBasicEscherEx::WriteOLEPicture(EscherPropertyContainer
&rPropOpt
,
2884 ShapeFlag nShapeFlags
, const Graphic
&rGraphic
, const SdrObject
&rObj
,
2885 sal_uInt32 nShapeId
, const awt::Rectangle
* pVisArea
)
2887 //nShapeFlags == 0xA00 + flips and ole active
2888 AddShape(ESCHER_ShpInst_PictureFrame
, nShapeFlags
, nShapeId
);
2890 GraphicObject
aGraphicObject(rGraphic
);
2891 OString aId
= aGraphicObject
.GetUniqueID();
2894 // SJ: the third parameter (pVisArea) should be set...
2895 sal_uInt32 nBlibId
= mxGlobal
->GetBlibID( *QueryPictureStream(), aGraphicObject
, pVisArea
);
2897 rPropOpt
.AddOpt(ESCHER_Prop_pib
, nBlibId
, true);
2900 SetPicId(rObj
, nShapeId
, rPropOpt
);
2901 rPropOpt
.AddOpt( ESCHER_Prop_pictureActive
, 0x10000 );
2904 void SwEscherEx::WriteOCXControl( const SwFrameFormat
& rFormat
, sal_uInt32 nShapeId
)
2906 const SdrObject
* pSdrObj
= rFormat
.FindRealSdrObject();
2910 OpenContainer( ESCHER_SpContainer
);
2912 SwDrawModel
*pModel
= mrWrt
.m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel();
2913 OutputDevice
*pDevice
= Application::GetDefaultDevice();
2914 OSL_ENSURE(pModel
&& pDevice
, "no model or device");
2916 // #i71538# use complete SdrViews
2917 // SdrExchangeView aExchange(pModel, pDevice);
2918 SdrView
aExchange(*pModel
, pDevice
);
2919 const Graphic
aGraphic(SdrExchangeView::GetObjGraphic(*pSdrObj
));
2920 EscherPropertyContainer aPropOpt
;
2921 WriteOLEPicture(aPropOpt
,
2922 ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
| ShapeFlag::OLEShape
, aGraphic
,
2923 *pSdrObj
, nShapeId
, nullptr );
2925 WriteFlyFrameAttr( rFormat
, mso_sptPictureFrame
, aPropOpt
);
2926 aPropOpt
.Commit( GetStream() );
2928 // store anchor attribute
2929 WriteFrameExtraData( rFormat
);
2931 CloseContainer(); // ESCHER_SpContainer
2935 void SwEscherEx::MakeZOrderArrAndFollowIds(
2936 std::vector
<DrawObj
>& rSrcArr
, DrawObjPointerVector
&rDstArr
)
2938 ::lcl_makeZOrderArray(mrWrt
, rSrcArr
, rDstArr
);
2940 //Now set up the follow IDs
2941 m_aFollowShpIds
.clear();
2943 for (DrawObj
* p
: rDstArr
)
2945 const SwFrameFormat
&rFormat
= p
->maContent
.GetFrameFormat();
2946 bool bNeedsShapeId
= false;
2948 if (RES_FLYFRMFMT
== rFormat
.Which())
2950 const SwFormatChain
&rChain
= rFormat
.GetChain();
2951 if (rChain
.GetPrev() || rChain
.GetNext())
2952 bNeedsShapeId
= true;
2955 sal_uLong nShapeId
= bNeedsShapeId
? GenerateShapeId() : 0;
2957 m_aFollowShpIds
.push_back(nShapeId
);
2961 sal_uInt32
SwEscherEx::GetFlyShapeId(const SwFrameFormat
& rFormat
,
2962 unsigned int nHdFtIndex
, DrawObjPointerVector
&rpVec
)
2964 sal_uInt16 nPos
= FindPos(rFormat
, nHdFtIndex
, rpVec
);
2965 sal_uInt32 nShapeId
;
2966 if (USHRT_MAX
!= nPos
)
2968 nShapeId
= m_aFollowShpIds
[nPos
];
2971 nShapeId
= GenerateShapeId();
2972 m_aFollowShpIds
[ nPos
] = nShapeId
;
2976 nShapeId
= GenerateShapeId();
2980 sal_uInt32
SwEscherEx::QueryTextID(
2981 const uno::Reference
< drawing::XShape
>& xXShapeRef
, sal_uInt32 nShapeId
)
2984 if (SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xXShapeRef
))
2986 m_pTextBxs
->Append( *pObj
, nShapeId
);
2987 nId
= m_pTextBxs
->Count();
2993 SwMSConvertControls::SwMSConvertControls( SfxObjectShell
const *pDSh
, SwPaM
*pP
) : oox
2994 ::ole::MSConvertOCXControls( pDSh
? pDSh
->GetModel() : nullptr ), m_pPaM( pP
), mnObjectId(0)
2999 // in transitioning away old filter for ole/ocx controls, ReadOCXStream has been made pure virtual in
3000 // filter/source/msocximex.cxx, so... we need an implementation here
3001 bool SwMSConvertControls::ReadOCXStream( tools::SvRef
<SotStorage
> const & rSrc1
,
3002 css::uno::Reference
< css::drawing::XShape
> *pShapeRef
,
3003 bool bFloatingCtrl
)
3005 uno::Reference
< form::XFormComponent
> xFComp
;
3006 bool bRes
= oox::ole::MSConvertOCXControls::ReadOCXStorage( rSrc1
, xFComp
);
3007 if ( bRes
&& xFComp
.is() )
3009 css::awt::Size aSz
; // not used in import
3010 bRes
= InsertControl( xFComp
, aSz
,pShapeRef
,bFloatingCtrl
);
3015 void SwMSConvertControls::ExportControl(WW8Export
&rWW8Wrt
, const SdrUnoObj
& rFormObj
)
3017 const uno::Reference
< awt::XControlModel
>& xControlModel
=
3018 rFormObj
.GetUnoControlModel();
3020 //Why oh lord do we use so many different units ?
3021 //I think I painted myself into a little bit of a
3022 //corner by trying to use the uno interface for
3024 tools::Rectangle aRect
= rFormObj
.GetLogicRect();
3025 aRect
.SetPos(Point(0,0));
3027 aSize
.Width
= convertTwipToMm100(aRect
.Right());
3028 aSize
.Height
= convertTwipToMm100(aRect
.Bottom());
3030 //Open the ObjectPool
3031 tools::SvRef
<SotStorage
> xObjPool
= rWW8Wrt
.GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool
);
3033 //Create a destination storage for the microsoft control
3034 sal_uInt32 nObjId
= ++mnObjectId
;
3035 OUString sStorageName
= "_" + OUString::number( static_cast<sal_Int64
>( nObjId
));
3036 tools::SvRef
<SotStorage
> xOleStg
= xObjPool
->OpenSotStorage(sStorageName
);
3042 if (!WriteOCXStream( mxModel
, xOleStg
,xControlModel
,aSize
,sUName
))
3045 sal_uInt8 aSpecOLE
[] =
3047 0x03, 0x6a, 0xFF, 0xFF, 0xFF, 0xFF, // sprmCPicLocation
3048 0x0a, 0x08, 1, // sprmCFOLE2
3049 0x55, 0x08, 1, // sprmCFSpec
3050 0x56, 0x08, 1 // sprmCFObj
3052 //Set the obj id into the sprmCPicLocation
3053 sal_uInt8
*pData
= aSpecOLE
+2;
3054 Set_UInt32(pData
,nObjId
);
3056 OUString sField
= FieldString(ww::eCONTROL
) + "Forms." + sUName
+ ".1 \\s ";
3058 rWW8Wrt
.OutputField(nullptr, ww::eCONTROL
, sField
,
3059 FieldFlags::Start
|FieldFlags::CmdStart
|FieldFlags::CmdEnd
);
3061 rWW8Wrt
.m_pChpPlc
->AppendFkpEntry(rWW8Wrt
.Strm().Tell(),sizeof(aSpecOLE
),
3063 rWW8Wrt
.WriteChar( 0x1 );
3064 rWW8Wrt
.OutputField(nullptr, ww::eCONTROL
, OUString(), FieldFlags::End
| FieldFlags::Close
);
3067 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */