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 .
20 #include <comphelper/string.hxx>
21 #include <svl/urihelper.hxx>
22 #include <hintids.hxx>
23 #include <osl/endian.h>
24 #include <sal/log.hxx>
25 #include <editeng/lrspitem.hxx>
26 #include <svx/xfillit0.hxx>
27 #include <svx/xlineit0.hxx>
28 #include <svx/xlnclit.hxx>
29 #include <svx/xlnwtit.hxx>
30 #include <svx/xlndsit.hxx>
31 #include <svx/xlnstit.hxx>
32 #include <svx/xlnedit.hxx>
33 #include <svx/xlnstwit.hxx>
34 #include <svx/xlnedwit.hxx>
35 #include <svx/xlnstcit.hxx>
36 #include <svx/xlnedcit.hxx>
37 #include <svx/xflclit.hxx>
38 #include <svx/xbtmpit.hxx>
39 #include <svx/svdmodel.hxx>
40 #include <svx/svdocapt.hxx>
41 #include <svx/sxctitm.hxx>
42 #include <svx/sdggaitm.hxx>
43 #include <svx/sdgluitm.hxx>
44 #include <svx/sdgmoitm.hxx>
45 #include <svx/sdmetitm.hxx>
46 #include <svx/sdooitm.hxx>
47 #include <svx/sdshitm.hxx>
48 #include <svx/sdsxyitm.hxx>
49 #include <svx/sdtagitm.hxx>
50 #include <svx/sdtditm.hxx>
51 #include <svx/sdtfsitm.hxx>
52 #include <editeng/editeng.hxx>
53 #include <svx/svdpage.hxx>
54 #include <svx/svdopath.hxx>
55 #include <svx/svdocirc.hxx>
56 #include <editeng/outlobj.hxx>
57 #include <svx/svdogrp.hxx>
58 #include <svx/svdograf.hxx>
59 #include <svx/svdoole2.hxx>
60 #include <editeng/ulspitem.hxx>
61 #include <editeng/brushitem.hxx>
62 #include <editeng/opaqitem.hxx>
63 #include <editeng/shaditem.hxx>
64 #include <editeng/boxitem.hxx>
65 #include <editeng/outliner.hxx>
66 #include <editeng/frmdiritem.hxx>
67 #include <svx/xfltrit.hxx>
68 #include <filter/msfilter/msdffimp.hxx>
70 #include <fmtornt.hxx>
71 #include <fmtcntnt.hxx>
73 #include <fmtanchr.hxx>
76 #include <drawdoc.hxx>
77 #include <IDocumentDrawModelAccess.hxx>
79 #include <dcontact.hxx>
82 #include "ww8struc.hxx"
83 #include "ww8scan.hxx"
85 #include "ww8par2.hxx"
86 #include "ww8graf.hxx"
87 #include <fmtinfmt.hxx>
88 #include <editeng/eeitem.hxx>
89 #include <editeng/flditem.hxx>
90 #include <fmtfollowtextflow.hxx>
91 #include "writerhelper.hxx"
92 #include "writerwordglue.hxx"
93 #include <basegfx/point/b2dpoint.hxx>
94 #include <basegfx/polygon/b2dpolygon.hxx>
95 #include <editeng/editobj.hxx>
98 #include <o3tl/enumrange.hxx>
99 #include <o3tl/safeint.hxx>
101 #include <filter/msfilter/escherex.hxx>
102 #include "sprmids.hxx"
104 using ::editeng::SvxBorderLine
;
105 using namespace ::com::sun::star
;
106 using namespace sw::types
;
107 using namespace sw::util
;
110 static Color
WW8TransCol(SVBT32 nWC
)
112 #if 1 // 1 = use predefined color, 0 = ignore
114 // color table to convert RGB values to pre-defined colors
115 // (to make the writer UI show the right color names)
116 // the table is split in base 3, the greys are missing as
117 // they don't fit into that system (4 values: bw, wb, 2 * grey)
118 static const Color eColA
[] = { // B G R B G R B G R
119 COL_BLACK
, COL_RED
, COL_LIGHTRED
, // 0 0 0, 0 0 1, 0 0 2
120 COL_GREEN
, COL_BROWN
, COL_BLACK
, // 0 1 0, 0 1 1, 0 1 2
121 COL_LIGHTGREEN
, COL_BLACK
, COL_YELLOW
, // 0 2 0, 0 2 1, 0 2 2
122 COL_BLUE
, COL_MAGENTA
, COL_BLACK
, // 1 0 0, 1 0 1, 1 0 2
123 COL_CYAN
, COL_LIGHTGRAY
, COL_BLACK
, // 1 1 0, 1 1 1, 1 1 2
124 COL_BLACK
, COL_BLACK
, COL_BLACK
, // 1 2 0, 1 2 1, 1 2 2
125 COL_LIGHTBLUE
, COL_BLACK
, COL_LIGHTMAGENTA
, // 2 0 0, 2 0 1, 2 0 2
126 COL_BLACK
, COL_BLACK
, COL_BLACK
, // 2 1 0, 2 1 1, 2 1 2
127 COL_LIGHTCYAN
, COL_BLACK
, COL_WHITE
}; // 2 2 0, 2 2 1, 2 2 2
129 // In nWC[3] is a byte that's not described in the WW documentation.
130 // Its meaning appears to be the following: For 0, it's a normal color
131 // whose RGB values are in nWC[0..2]. If nWC[3] is 0x1, 0x7d or 0x83,
132 // it's a grey value whose black portion is given in 0.5% in nWC[0].
133 // I guess that BIT(0) in nWC[3] is relevant for distinguishing RGB/Grey.
135 if( !( nWC
[3] & 0x1 ) && // not special (grey)
136 ( ( nWC
[0] == 0 || nWC
[0]== 0x80 || nWC
[0] == 0xff ) // R
137 && ( nWC
[1] == 0 || nWC
[1]== 0x80 || nWC
[1] == 0xff ) // G
138 && ( nWC
[2] == 0 || nWC
[2]== 0x80 || nWC
[2] == 0xff ) ) ){// B
139 int nIdx
= 0; // and now: Idx-calculation in base 3
140 for (int i
= 2; i
>= 0; i
--)
144 nIdx
+= ((nWC
[i
] == 0xff) ? 2 : 1);
146 if (eColA
[nIdx
] != COL_BLACK
)
147 return eColA
[nIdx
]; // default color
153 // Special color gray
154 sal_uInt8 u
= static_cast<sal_uInt8
>( static_cast<sal_uLong
>( 200 - nWC
[0] ) * 256 / 200 );
155 return Color(u
, u
, u
);
159 return Color(nWC
[0], nWC
[1], nWC
[2]);
162 void wwFrameNamer::SetUniqueGraphName(SwFrameFormat
*pFrameFormat
, const OUString
&rFixed
)
164 if (mbIsDisabled
|| rFixed
.isEmpty())
167 pFrameFormat
->SetName(msSeed
+OUString::number(++mnImportedGraphicsCount
) + ": " + rFixed
);
170 // ReadGrafStart reads object data and if necessary creates an anchor
171 bool SwWW8ImplReader::ReadGrafStart(void* pData
, short nDataSiz
,
172 WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
174 if (SVBT16ToUInt16(pHd
->cb
) < sizeof(WW8_DPHEAD
) + nDataSiz
)
176 OSL_ENSURE( false, "+graphic element: too short?" );
177 m_pStrm
->SeekRel(SVBT16ToUInt16(pHd
->cb
) - sizeof(WW8_DPHEAD
));
181 bool bCouldRead
= checkRead(*m_pStrm
, pData
, nDataSiz
);
182 OSL_ENSURE(bCouldRead
, "Short Graphic header");
186 SwFormatAnchor
aAnchor( RndStdIds::FLY_AT_CHAR
);
187 aAnchor
.SetAnchor( m_pPaM
->GetPoint() );
190 m_nDrawXOfs2
= m_nDrawXOfs
;
191 m_nDrawYOfs2
= m_nDrawYOfs
;
196 // SetStdAttr() sets standard attributes
197 static void SetStdAttr( SfxItemSet
& rSet
, WW8_DP_LINETYPE
& rL
,
198 WW8_DP_SHADOW
const & rSh
)
200 if( SVBT16ToUInt16( rL
.lnps
) == 5 ){ // invisible
201 rSet
.Put( XLineStyleItem( drawing::LineStyle_NONE
) );
203 Color
aCol( WW8TransCol( rL
.lnpc
) ); // line color
204 rSet
.Put( XLineColorItem( OUString(), aCol
) );
205 rSet
.Put( XLineWidthItem( SVBT16ToUInt16( rL
.lnpw
) ) );
207 if( SVBT16ToUInt16( rL
.lnps
) >= 1
208 && SVBT16ToUInt16(rL
.lnps
) <= 4 ){ // line style
209 rSet
.Put( XLineStyleItem( drawing::LineStyle_DASH
) );
210 sal_Int16 nLen
= SVBT16ToUInt16( rL
.lnpw
);
211 XDash
aD( css::drawing::DashStyle_RECT
, 1, 2 * nLen
, 1, 5 * nLen
, 5 * nLen
);
212 switch( SVBT16ToUInt16( rL
.lnps
) ){
213 case 1: aD
.SetDots( 0 ); // Dash
214 aD
.SetDashLen( 6 * nLen
);
215 aD
.SetDistance( 4 * nLen
);
217 case 2: aD
.SetDashes( 0 ); break; // Dot
218 case 3: break; // Dash Dot
219 case 4: aD
.SetDots( 2 ); break; // Dash Dot Dot
221 rSet
.Put( XLineDashItem( OUString(), aD
) );
223 rSet
.Put( XLineStyleItem( drawing::LineStyle_SOLID
) ); // needed for TextBox
226 if( SVBT16ToUInt16( rSh
.shdwpi
) ){ // shadow
227 rSet
.Put(makeSdrShadowItem(true));
228 rSet
.Put( makeSdrShadowXDistItem( SVBT16ToUInt16( rSh
.xaOffset
) ) );
229 rSet
.Put( makeSdrShadowYDistItem( SVBT16ToUInt16( rSh
.yaOffset
) ) );
233 // SetFill() sets fill attributes such as fore- and background color and
234 // pattern by reducing to a color
235 // SetFill() doesn't yet set a pattern, because Sdr can't easily do that
236 // and the Sdr hatching (XDash) isn't finished yet.
237 // Instead, a mixed color will be picked that's between the selected ones.
238 static void SetFill( SfxItemSet
& rSet
, WW8_DP_FILL
& rFill
)
240 static const sal_uInt8 nPatA
[] =
242 0, 0, 5, 10, 20, 25, 30, 40, 50, 60, 70, 75, 80,
243 90, 50, 50, 50, 50, 50, 50, 33, 33, 33, 33, 33, 33
245 sal_uInt16 nPat
= SVBT16ToUInt16(rFill
.flpp
);
247 if (nPat
== 0) // transparent
248 rSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
251 rSet
.Put(XFillStyleItem(drawing::FillStyle_SOLID
)); // necessary for textbox
252 if (nPat
<= 1 || (SAL_N_ELEMENTS(nPatA
) <= nPat
))
254 // Solid background or unknown
255 rSet
.Put(XFillColorItem(OUString(), WW8TransCol(rFill
.dlpcBg
)));
258 { // Brush -> color mix
259 Color
aB( WW8TransCol( rFill
.dlpcBg
) );
260 Color
aF( WW8TransCol( rFill
.dlpcFg
) );
261 aB
.SetRed( static_cast<sal_uInt8
>( ( static_cast<sal_uLong
>(aF
.GetRed()) * nPatA
[nPat
]
262 + static_cast<sal_uLong
>(aB
.GetRed()) * ( 100 - nPatA
[nPat
] ) ) / 100 ) );
263 aB
.SetGreen( static_cast<sal_uInt8
>( ( static_cast<sal_uLong
>(aF
.GetGreen()) * nPatA
[nPat
]
264 + static_cast<sal_uLong
>(aB
.GetGreen()) * ( 100 - nPatA
[nPat
] ) ) / 100 ) );
265 aB
.SetBlue( static_cast<sal_uInt8
>( ( static_cast<sal_uLong
>(aF
.GetBlue()) * nPatA
[nPat
]
266 + static_cast<sal_uLong
>(aB
.GetBlue()) * ( 100 - nPatA
[nPat
] ) ) / 100 ) );
267 rSet
.Put( XFillColorItem( OUString(), aB
) );
272 static void SetLineEndAttr( SfxItemSet
& rSet
, WW8_DP_LINEEND
const & rLe
,
273 WW8_DP_LINETYPE
const & rLt
)
275 sal_uInt16 aSB
= SVBT16ToUInt16( rLe
.aStartBits
);
278 ::basegfx::B2DPolygon aPolygon
;
279 aPolygon
.append(::basegfx::B2DPoint(0.0, 330.0));
280 aPolygon
.append(::basegfx::B2DPoint(100.0, 0.0));
281 aPolygon
.append(::basegfx::B2DPoint(200.0, 330.0));
282 aPolygon
.setClosed(true);
283 rSet
.Put( XLineEndItem( OUString(), ::basegfx::B2DPolyPolygon(aPolygon
) ) );
284 sal_uInt16 nSiz
= SVBT16ToUInt16( rLt
.lnpw
)
285 * ( ( aSB
>> 2 & 0x3 ) + ( aSB
>> 4 & 0x3 ) );
286 if( nSiz
< 220 ) nSiz
= 220;
287 rSet
.Put(XLineEndWidthItem(nSiz
));
288 rSet
.Put(XLineEndCenterItem(false));
291 sal_uInt16 aEB
= SVBT16ToUInt16( rLe
.aEndBits
);
292 if( !(aEB
& 0x3) ) return;
294 ::basegfx::B2DPolygon aPolygon
;
295 aPolygon
.append(::basegfx::B2DPoint(0.0, 330.0));
296 aPolygon
.append(::basegfx::B2DPoint(100.0, 0.0));
297 aPolygon
.append(::basegfx::B2DPoint(200.0, 330.0));
298 aPolygon
.setClosed(true);
299 rSet
.Put( XLineStartItem( OUString(), ::basegfx::B2DPolyPolygon(aPolygon
) ) );
300 sal_uInt16 nSiz
= SVBT16ToUInt16( rLt
.lnpw
)
301 * ( ( aEB
>> 2 & 0x3 ) + ( aEB
>> 4 & 0x3 ) );
302 if( nSiz
< 220 ) nSiz
= 220;
303 rSet
.Put(XLineStartWidthItem(nSiz
));
304 rSet
.Put(XLineStartCenterItem(false));
307 // start of routines for the different objects
308 SdrObject
* SwWW8ImplReader::ReadLine(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
312 if( !ReadGrafStart( static_cast<void*>(&aLine
), sizeof( aLine
), pHd
, rSet
) )
320 rP0
.setX( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
)) + m_nDrawXOfs2
);
321 rP0
.setY( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
)) + m_nDrawYOfs2
);
323 rP0
.AdjustX(static_cast<sal_Int16
>(SVBT16ToUInt16( aLine
.xaStart
)) );
324 rP0
.AdjustY(static_cast<sal_Int16
>(SVBT16ToUInt16( aLine
.yaStart
)) );
325 rP1
.AdjustX(static_cast<sal_Int16
>(SVBT16ToUInt16( aLine
.xaEnd
)) );
326 rP1
.AdjustY(static_cast<sal_Int16
>(SVBT16ToUInt16( aLine
.yaEnd
)) );
329 ::basegfx::B2DPolygon aPolygon
;
330 aPolygon
.append(::basegfx::B2DPoint(aP
[0].X(), aP
[0].Y()));
331 aPolygon
.append(::basegfx::B2DPoint(aP
[1].X(), aP
[1].Y()));
332 SdrObject
* pObj
= new SdrPathObj(
335 ::basegfx::B2DPolyPolygon(aPolygon
));
337 SetStdAttr( rSet
, aLine
.aLnt
, aLine
.aShd
);
338 SetLineEndAttr( rSet
, aLine
.aEpp
, aLine
.aLnt
);
343 SdrObject
* SwWW8ImplReader::ReadRect(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
347 if( !ReadGrafStart( static_cast<void*>(&aRect
), sizeof( aRect
), pHd
, rSet
) )
350 Point
aP0( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
)) + m_nDrawXOfs2
,
351 static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
)) + m_nDrawYOfs2
);
353 aP1
.AdjustX(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dxa
)) );
354 aP1
.AdjustY(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dya
)) );
356 SdrObject
* pObj
= new SdrRectObj(
358 tools::Rectangle(aP0
, aP1
));
360 SetStdAttr( rSet
, aRect
.aLnt
, aRect
.aShd
);
361 SetFill( rSet
, aRect
.aFill
);
366 SdrObject
* SwWW8ImplReader::ReadEllipse(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
368 WW8_DP_ELLIPSE aEllipse
;
370 if( !ReadGrafStart( static_cast<void*>(&aEllipse
), sizeof( aEllipse
), pHd
, rSet
) )
373 Point
aP0( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
)) + m_nDrawXOfs2
,
374 static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
)) + m_nDrawYOfs2
);
376 aP1
.AdjustX(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dxa
)) );
377 aP1
.AdjustY(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dya
)) );
379 SdrObject
* pObj
= new SdrCircObj(
382 tools::Rectangle(aP0
, aP1
));
384 SetStdAttr( rSet
, aEllipse
.aLnt
, aEllipse
.aShd
);
385 SetFill( rSet
, aEllipse
.aFill
);
390 SdrObject
* SwWW8ImplReader::ReadArc(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
394 if( !ReadGrafStart( static_cast<void*>(&aArc
), sizeof( aArc
), pHd
, rSet
) )
397 Point
aP0( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
)) + m_nDrawXOfs2
,
398 static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
)) + m_nDrawYOfs2
);
400 aP1
.AdjustX(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dxa
)) * 2 );
401 aP1
.AdjustY(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dya
)) * 2 );
403 short nA
[] = { 2, 3, 1, 0 };
404 short nW
= nA
[ ( ( aArc
.fLeft
& 1 ) << 1 ) + ( aArc
.fUp
& 1 ) ];
406 aP0
.AdjustY( -static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dya
)) );
407 aP1
.AdjustY( -static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dya
)) );
410 aP0
.AdjustX( -static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dxa
)) );
411 aP1
.AdjustX( -static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dxa
)) );
414 SdrObject
* pObj
= new SdrCircObj(
416 SdrCircKind::Section
,
417 tools::Rectangle(aP0
, aP1
),
419 ( ( nW
+ 1 ) & 3 ) * 9000);
421 SetStdAttr( rSet
, aArc
.aLnt
, aArc
.aShd
);
422 SetFill( rSet
, aArc
.aFill
);
427 SdrObject
* SwWW8ImplReader::ReadPolyLine(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
429 WW8_DP_POLYLINE aPoly
;
431 if( !ReadGrafStart( static_cast<void*>(&aPoly
), sizeof( aPoly
), pHd
, rSet
) )
434 sal_uInt16 nCount
= SVBT16ToUInt16( aPoly
.aBits1
) >> 1 & 0x7fff;
435 std::unique_ptr
<SVBT16
[]> xP(new SVBT16
[nCount
* 2]);
437 bool bCouldRead
= checkRead(*m_pStrm
, xP
.get(), nCount
* 4); // read points
438 OSL_ENSURE(bCouldRead
, "Short PolyLine header");
442 tools::Polygon
aP( nCount
);
444 for (sal_uInt16 i
=0; i
<nCount
; ++i
)
446 aPt
.setX( SVBT16ToUInt16( xP
[i
<< 1] ) + m_nDrawXOfs2
447 + static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
)) );
448 aPt
.setY( SVBT16ToUInt16( xP
[( i
<< 1 ) + 1] ) + m_nDrawYOfs2
449 + static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
)) );
454 SdrObject
* pObj
= new SdrPathObj(
456 (SVBT16ToUInt16(aPoly
.aBits1
) & 0x1) ? OBJ_POLY
: OBJ_PLIN
,
457 ::basegfx::B2DPolyPolygon(aP
.getB2DPolygon()));
459 SetStdAttr( rSet
, aPoly
.aLnt
, aPoly
.aShd
);
460 SetFill( rSet
, aPoly
.aFill
);
465 static ESelection
GetESelection(EditEngine
const &rDrawEditEngine
, tools::Long nCpStart
, tools::Long nCpEnd
)
467 sal_Int32 nPCnt
= rDrawEditEngine
.GetParagraphCount();
471 && (nCpStart
>= rDrawEditEngine
.GetTextLen( nSP
) + 1) )
473 nCpStart
-= rDrawEditEngine
.GetTextLen( nSP
) + 1;
476 // at the end, switch to the new line only 1 character later as
477 // otherwise line attributes reach one line too far
479 && (nCpEnd
> rDrawEditEngine
.GetTextLen( nEP
) + 1) )
481 nCpEnd
-= rDrawEditEngine
.GetTextLen( nEP
) + 1;
484 return ESelection( nSP
, nCpStart
, nEP
, nCpEnd
);
487 // InsertTxbxStyAttrs() sets style attributes into the passed ItemSet.
488 // SW styles are used since import-WW-styles are already destroyed.
489 // SW styles are examined in depth first search order (with parent styles)
490 // for the attributes given in aSrcTab. They're cloned, and the clones'
491 // Which-IDs are changed according to the aDstTab table so that the
492 // EditEngine will not ignore them.
493 // Both Paragraph and character attributes are stuffed into the ItemSet.
494 void SwWW8ImplReader::InsertTxbxStyAttrs( SfxItemSet
& rS
, sal_uInt16 nColl
)
496 SwWW8StyInf
* pStyInf
= GetStyle(nColl
);
497 if( !(pStyInf
!= nullptr && pStyInf
->m_pFormat
&& pStyInf
->m_bColl
) )
500 const SfxPoolItem
* pItem
;
501 for( sal_uInt16 i
= POOLATTR_BEGIN
; i
< POOLATTR_END
; i
++ )
503 // If we are set in the source and not set in the destination
505 if ( SfxItemState::SET
== pStyInf
->m_pFormat
->GetItemState(
508 SfxItemPool
*pEditPool
= rS
.GetPool();
509 sal_uInt16 nWhich
= i
;
510 sal_uInt16 nSlotId
= m_rDoc
.GetAttrPool().GetSlotId(nWhich
);
512 nSlotId
&& nWhich
!= nSlotId
&&
513 0 != (nWhich
= pEditPool
->GetWhich(nSlotId
)) &&
515 ( SfxItemState::SET
!= rS
.GetItemState(nWhich
, false) )
518 rS
.Put( pItem
->CloneSetWhich(nWhich
) );
525 static void lcl_StripFields(OUString
&rString
, WW8_CP
&rNewStartCp
)
527 sal_Int32 nStartPos
= 0;
530 nStartPos
= rString
.indexOf(0x13, nStartPos
);
534 const sal_Unicode cStops
[] = {0x14, 0x15, 0};
535 const sal_Int32 nStopPos
= comphelper::string::indexOfAny(rString
, cStops
, nStartPos
);
538 rNewStartCp
+= rString
.getLength()-nStartPos
;
539 rString
= rString
.copy(0, nStartPos
);
543 const bool was0x14
= rString
[nStopPos
]==0x14;
544 rString
= rString
.replaceAt(nStartPos
, nStopPos
+1-nStartPos
, "");
545 rNewStartCp
+= nStopPos
-nStartPos
;
550 nStartPos
= rString
.indexOf(0x15, nStartPos
);
553 rString
= rString
.replaceAt(nStartPos
, 1, "");
564 tools::Long mnStartPos
; // 0x13
565 tools::Long mnEndPos
; // 0x15
567 explicit Chunk(tools::Long nStart
, const OUString
&rURL
)
568 : msURL(rURL
), mnStartPos(nStart
), mnEndPos(0) {}
570 void SetEndPos(tools::Long nEnd
) { mnEndPos
= nEnd
; }
571 tools::Long
GetStartPos() const {return mnStartPos
;}
572 tools::Long
GetEndPos() const {return mnEndPos
;}
573 const OUString
&GetURL() const {return msURL
;}
574 void Adjust(sal_Int32 nAdjust
)
581 bool IsValidSel(const EditEngine
& rEngine
, const ESelection
& rSel
)
583 const auto nParaCount
= rEngine
.GetParagraphCount();
584 if (rSel
.nStartPara
< nParaCount
&& rSel
.nEndPara
< nParaCount
)
585 return rSel
.nStartPos
>= 0 && rSel
.nEndPos
>= 0;
590 // InsertAttrsAsDrawingAttrs() sets attributes between StartCp and EndCp.
591 // Style attributes are set as hard, paragraph and character attributes.
592 void SwWW8ImplReader::InsertAttrsAsDrawingAttrs(WW8_CP nStartCp
, WW8_CP nEndCp
,
593 ManTypes eType
, bool bONLYnPicLocFc
)
596 Save and create new plcxman for this drawing object, of the type that
597 will include the para end mark inside a paragraph property range, as
598 drawing boxes have real paragraph marks as part of their text, while
599 normal writer has separate nodes for each paragraph and so has no actual
600 paragraph mark as part of the paragraph text.
602 WW8ReaderSave
aSave(this);
603 m_xPlcxMan
= std::make_shared
<WW8PLCFMan
>(m_xSBase
.get(), eType
, nStartCp
, true);
605 WW8_CP nStart
= m_xPlcxMan
->Where();
606 WW8_CP nNext
, nStartReplace
=0;
608 bool bDoingSymbol
= false;
609 sal_Unicode cReplaceSymbol
= m_cSymbol
;
611 std::unique_ptr
<SfxItemSet
> pS(new SfxItemSet(m_pDrawEditEngine
->GetEmptyItemSet()));
612 WW8PLCFManResult aRes
;
614 std::deque
<Chunk
> aChunks
;
616 // Here store stack location
617 size_t nCurrentCount
= m_xCtrlStck
->size();
618 while (nStart
< nEndCp
)
620 // nStart is the beginning of the attributes for this range, and
621 // may be before the text itself. So watch out for that
622 WW8_CP nTextStart
= nStart
;
623 if (nTextStart
< nStartCp
)
624 nTextStart
= nStartCp
;
626 // get position of next SPRM
627 bool bStartAttr
= m_xPlcxMan
->Get(&aRes
);
628 m_nCurrentColl
= m_xPlcxMan
->GetColl();
633 if ( (68 == aRes
.nSprmId
) || (0x6A03 == aRes
.nSprmId
) )
635 Read_PicLoc(aRes
.nSprmId
, aRes
.pMemPos
+
636 m_xSprmParser
->DistanceToData(aRes
.nSprmId
), 4);
637 // Ok, that's what we were looking for. Now let's get
642 else if ((eFTN
> aRes
.nSprmId
) || (0x0800 <= aRes
.nSprmId
))
644 // Here place them onto our usual stack and we will pop them
645 // off and convert them later
648 ImportSprm(aRes
.pMemPos
, aRes
.nMemLen
, aRes
.nSprmId
);
649 if (!bDoingSymbol
&& m_bSymbol
)
652 nStartReplace
= nTextStart
;
653 cReplaceSymbol
= m_cSymbol
;
658 EndSprm( aRes
.nSprmId
);
659 if (!m_bSymbol
&& bDoingSymbol
)
661 bDoingSymbol
= false;
662 OUStringBuffer sTemp
;
663 comphelper::string::padToLength(sTemp
,
664 nTextStart
- nStartReplace
, cReplaceSymbol
);
665 m_pDrawEditEngine
->QuickInsertText(sTemp
.makeStringAndClear(),
666 GetESelection(*m_pDrawEditEngine
, nStartReplace
- nStartCp
,
667 nTextStart
- nStartCp
) );
671 else if (aRes
.nSprmId
== eFLD
)
675 size_t nCount
= m_xCtrlStck
->size();
676 if (m_aFieldStack
.empty() && Read_Field(&aRes
))
679 for (size_t nI
= m_xCtrlStck
->size(); nI
> nCount
; --nI
)
681 const SfxPoolItem
*pItem
= ((*m_xCtrlStck
)[nI
-1]).pAttr
.get();
682 sal_uInt16 nWhich
= pItem
->Which();
683 if (nWhich
== RES_TXTATR_INETFMT
)
685 const SwFormatINetFormat
*pURL
=
686 static_cast<const SwFormatINetFormat
*>(pItem
);
687 sURL
= pURL
->GetValue();
689 m_xCtrlStck
->DeleteAndDestroy(nI
-1);
691 aChunks
.emplace_back(nStart
, sURL
);
696 if (!m_aFieldStack
.empty() && End_Field() && !aChunks
.empty())
697 aChunks
.back().SetEndPos(nStart
+1);
702 m_xPlcxMan
->advance();
703 nNext
= m_xPlcxMan
->Where();
705 const WW8_CP nEnd
= ( nNext
< nEndCp
) ? nNext
: nEndCp
;
706 if (!bONLYnPicLocFc
&& nNext
!= nStart
&& nEnd
>= nStartCp
)
708 SfxItemPool
*pEditPool
= pS
->GetPool();
710 // Here read current properties and convert them into pS
711 // and put those attrs into the draw box if they can be converted
712 // to draw attributes
713 if (m_xCtrlStck
->size() - nCurrentCount
)
715 for (size_t i
= nCurrentCount
; i
< m_xCtrlStck
->size(); ++i
)
717 const SfxPoolItem
*pItem
= ((*m_xCtrlStck
)[i
]).pAttr
.get();
718 sal_uInt16 nWhich
= pItem
->Which();
719 if( nWhich
< RES_FLTRATTR_BEGIN
||
720 nWhich
>= RES_FLTRATTR_END
)
722 sal_uInt16 nSlotId
= m_rDoc
.GetAttrPool().GetSlotId(nWhich
);
724 nSlotId
&& nWhich
!= nSlotId
&&
725 0 != (nWhich
= pEditPool
->GetWhich(nSlotId
)) &&
729 pS
->Put( pItem
->CloneSetWhich(nWhich
) );
734 // Fill in the remainder from the style
735 InsertTxbxStyAttrs(*pS
, m_nCurrentColl
);
739 m_pDrawEditEngine
->QuickSetAttribs( *pS
,
740 GetESelection(*m_pDrawEditEngine
, nTextStart
- nStartCp
, nEnd
- nStartCp
) );
741 pS
.reset( new SfxItemSet(m_pDrawEditEngine
->GetEmptyItemSet()) );
748 // pop off as far as recorded location just in case there were some left
750 for (size_t nI
= m_xCtrlStck
->size(); nI
> nCurrentCount
; --nI
)
751 m_xCtrlStck
->DeleteAndDestroy(nI
-1);
753 auto aEnd
= aChunks
.end();
754 for (auto aIter
= aChunks
.begin(); aIter
!= aEnd
; ++aIter
)
756 ESelection
aSel(GetESelection(*m_pDrawEditEngine
, aIter
->GetStartPos()-nStartCp
,
757 aIter
->GetEndPos()-nStartCp
));
758 if (!IsValidSel(*m_pDrawEditEngine
, aSel
))
760 OUString
aString(m_pDrawEditEngine
->GetText(aSel
));
761 const sal_Int32 nOrigLen
= aString
.getLength();
763 lcl_StripFields(aString
, nDummy
);
766 if (!aIter
->GetURL().isEmpty())
768 SvxURLField
aURL(aIter
->GetURL(), aString
, SvxURLFormat::AppDefault
);
769 m_pDrawEditEngine
->QuickInsertField(SvxFieldItem(aURL
, EE_FEATURE_FIELD
), aSel
);
770 nChanged
= nOrigLen
- 1;
774 m_pDrawEditEngine
->QuickInsertText(aString
, aSel
);
775 nChanged
= nOrigLen
- aString
.getLength();
777 for (auto aIter2
= aIter
+1; aIter2
!= aEnd
; ++aIter2
)
778 aIter2
->Adjust(nChanged
);
782 Don't worry about the new pPlcxMan, the restore removes it when
783 replacing the current one with the old one.
788 bool SwWW8ImplReader::GetTxbxTextSttEndCp(WW8_CP
& rStartCp
, WW8_CP
& rEndCp
,
789 sal_uInt16 nTxBxS
, sal_uInt16 nSequence
)
791 // grab the TextBox-PLCF quickly
792 WW8PLCFspecial
* pT
= m_xPlcxMan
? m_xPlcxMan
->GetTxbx() : nullptr;
795 OSL_ENSURE( false, "+where's the text graphic (1)?" );
799 // if applicable first find the right TextBox-Story
800 bool bCheckTextBoxStory
= ( nTxBxS
&& pT
->GetIMax() >= nTxBxS
);
801 if( bCheckTextBoxStory
)
802 pT
->SetIdx( nTxBxS
-1 );
804 // then determine start and end
806 if (!pT
->Get(rStartCp
, pT0
) || rStartCp
< 0)
808 OSL_ENSURE( false, "+where's the text graphic (2)?" );
812 if( bCheckTextBoxStory
)
814 bool bReusable
= (0 != SVBT16ToUInt16( static_cast<WW8_TXBXS
*>(pT0
)->fReusable
));
818 if( !pT
->Get( rStartCp
, pT0
) )
820 OSL_ENSURE( false, "+where's the text graphic (2a)?" );
823 bReusable
= (0 != SVBT16ToUInt16( static_cast<WW8_TXBXS
*>(pT0
)->fReusable
));
827 if (!pT
->Get(rEndCp
, pT0
) || rEndCp
< 0)
829 OSL_ENSURE( false, "+where's the text graphic (3)?" );
833 // find the right page in the break table (if necessary)
834 if( bCheckTextBoxStory
)
836 // special case: entire chain should be determined - done!
837 if( USHRT_MAX
> nSequence
)
839 tools::Long nMinStartCp
= rStartCp
;
840 tools::Long nMaxEndCp
= rEndCp
;
841 // quickly grab the TextBox-Break-Descriptor-PLCF
842 pT
= m_xPlcxMan
->GetTxbxBkd();
843 if (!pT
) // It can occur on occasion, Caolan
846 // find first entry for this TextBox story
847 if( !pT
->SeekPos( rStartCp
) )
849 OSL_ENSURE( false, "+where's the text graphic (4)" );
852 // if needed skip the appropriate number of entries
853 for (sal_uInt16 iSequence
= 0; iSequence
< nSequence
; ++iSequence
)
855 // and determine actual start and end
856 if( (!pT
->Get( rStartCp
, pT0
))
857 || ( nMinStartCp
> rStartCp
) )
859 OSL_ENSURE( false, "+where's the text graphic (5)?" );
862 if( rStartCp
>= nMaxEndCp
)
863 rEndCp
= rStartCp
; // not an error: empty string
867 if ( (!pT
->Get(rEndCp
, pT0
)) || (nMaxEndCp
< rEndCp
-1) )
869 OSL_ENSURE( false, "+where's the text graphic (6)?" );
883 // TxbxText() grabs the text from the WW file and returns that along with
884 // the StartCp and the corrected (by -2, or -1 for version 8) EndCp.
885 sal_Int32
SwWW8ImplReader::GetRangeAsDrawingString(OUString
& rString
, tools::Long nStartCp
, tools::Long nEndCp
, ManTypes eType
)
888 m_xWwFib
->GetBaseCp(eType
, &nOffset
); //TODO: check return value
890 OSL_ENSURE(nStartCp
<= nEndCp
, "+where's the graphic text (7)?");
891 if (nStartCp
== nEndCp
)
892 rString
.clear(); // empty string: entirely possible
893 else if (nStartCp
< nEndCp
)
895 // read the text: can be split into multiple pieces
896 const sal_Int32 nLen
= m_xSBase
->WW8ReadString(*m_pStrm
, rString
,
897 nStartCp
+ nOffset
, nEndCp
- nStartCp
, GetCurrentCharSet());
898 OSL_ENSURE(nLen
, "+where's the text graphic (8)?");
901 if( rString
[nLen
-1]==0x0d )
902 rString
= rString
.copy(0, nLen
-1);
904 rString
= rString
.replace( 0xb, 0xa );
911 //EditEngine::InsertText will replace dos lines resulting in a shorter
912 //string than is passed in, so inserting attributes based on the original
913 //string len can fail. So here replace the dos line ends similar to
914 //how EditEngine does it, but preserve the length and replace the extra
915 //chars with placeholders, record the position of the placeholders and
916 //remove those extra chars after attributes have been inserted
917 static std::vector
<sal_Int32
> replaceDosLineEndsButPreserveLength(OUString
&rIn
)
919 OUStringBuffer
aNewData(rIn
);
920 std::vector
<sal_Int32
> aDosLineEndDummies
;
922 sal_Int32 nStrLen
= rIn
.getLength();
925 // \r or \n causes linebreak
926 if (rIn
[i
] == '\r' || rIn
[i
] == '\n')
928 // skip char if \r\n or \n\r
929 if ( (i
+1) < nStrLen
&& ((rIn
[i
+1] == '\r') || (rIn
[i
+1] == '\n')) &&
930 (rIn
[i
] != rIn
[i
+1]) )
933 aDosLineEndDummies
.push_back(i
);
939 rIn
= aNewData
.makeStringAndClear();
940 return aDosLineEndDummies
;
943 static void removePositions(EditEngine
&rDrawEditEngine
, const std::vector
<sal_Int32
>& rDosLineEndDummies
)
945 for (auto aIter
= rDosLineEndDummies
.rbegin(); aIter
!= rDosLineEndDummies
.rend(); ++aIter
)
947 sal_Int32
nCharPos(*aIter
);
948 rDrawEditEngine
.QuickDelete(GetESelection(rDrawEditEngine
, nCharPos
, nCharPos
+1));
952 std::unique_ptr
<OutlinerParaObject
> SwWW8ImplReader::ImportAsOutliner(OUString
&rString
, WW8_CP nStartCp
, WW8_CP nEndCp
, ManTypes eType
)
954 std::unique_ptr
<OutlinerParaObject
> pRet
;
956 sal_Int32 nLen
= GetRangeAsDrawingString(rString
, nStartCp
, nEndCp
, eType
);
959 if (!m_pDrawEditEngine
)
961 m_pDrawEditEngine
.reset(new EditEngine(nullptr));
964 //replace dos line endings with editeng ones, replace any extra chars with
965 //placeholders to keep the inserted string len in sync with the attribute cps
966 //and record in aDosLineEnds the superfluous positions
967 OUString
sEEString(rString
);
968 std::vector
<sal_Int32
> aDosLineEnds(replaceDosLineEndsButPreserveLength(sEEString
));
969 m_pDrawEditEngine
->SetText(sEEString
);
970 InsertAttrsAsDrawingAttrs(nStartCp
, nStartCp
+nLen
, eType
);
971 //remove any superfluous placeholders of replaceDosLineEndsButPreserveLength
972 //after attributes have been inserted
973 removePositions(*m_pDrawEditEngine
, aDosLineEnds
);
975 // Annotations typically begin with a (useless) 0x5
976 if ((eType
== MAN_AND
) && m_pDrawEditEngine
->GetTextLen())
978 ESelection
aFirstChar(0, 0, 0, 1);
979 if (m_pDrawEditEngine
->GetText( aFirstChar
) == "\x05")
980 m_pDrawEditEngine
->QuickDelete(aFirstChar
);
983 std::unique_ptr
<EditTextObject
> pTemporaryText
= m_pDrawEditEngine
->CreateTextObject();
984 pRet
.reset( new OutlinerParaObject( std::move(pTemporaryText
) ) );
985 pRet
->SetOutlinerMode( OutlinerMode::TextObject
);
987 m_pDrawEditEngine
->SetText( OUString() );
988 m_pDrawEditEngine
->SetParaAttribs(0, m_pDrawEditEngine
->GetEmptyItemSet());
990 // Strip out fields, leaving the result
992 lcl_StripFields(rString
, nDummy
);
993 // Strip out word's special characters for the simple string
994 rString
= rString
.replaceAll("\x01", "");
995 rString
= rString
.replaceAll("\x05", "");
996 rString
= rString
.replaceAll("\x08", "");
997 rString
= rString
.replaceAll("\007\007", "\007\012");
998 rString
= rString
.replace(0x7, ' ');
1004 // InsertTxbxText() adds the Text and the Attributes for TextBoxes and CaptionBoxes
1005 void SwWW8ImplReader::InsertTxbxText(SdrTextObj
* pTextObj
,
1006 Size
const * pObjSiz
, sal_uInt16 nTxBxS
, sal_uInt16 nSequence
, tools::Long nPosCp
,
1007 SwFrameFormat
const * pOldFlyFormat
, bool bMakeSdrGrafObj
, bool& rbEraseTextObj
,
1008 bool* pbTestTxbxContainsText
, tools::Long
* pnStartCp
, tools::Long
* pnEndCp
,
1009 bool* pbContainsGraphics
, SvxMSDffImportRec
const * pRecord
)
1011 SwFrameFormat
* pFlyFormat
= nullptr;
1012 sal_uLong nOld
= m_pStrm
->Tell();
1014 ManTypes eType
= m_xPlcxMan
->GetManType() == MAN_HDFT
? MAN_TXBX_HDFT
: MAN_TXBX
;
1016 rbEraseTextObj
= false;
1019 WW8_CP nStartCp
, nEndCp
;
1020 bool bContainsGraphics
= false;
1021 bool bTextWasRead
= GetTxbxTextSttEndCp(nStartCp
, nEndCp
, nTxBxS
, nSequence
) &&
1022 GetRangeAsDrawingString(aString
, nStartCp
, nEndCp
, eType
) > 0;
1024 if (!m_pDrawEditEngine
)
1026 m_pDrawEditEngine
.reset(new EditEngine(nullptr));
1029 m_pDrawEditEngine
->SetPaperSize( *pObjSiz
);
1031 const OUString
aOrigString(aString
);
1034 WW8_CP nNewStartCp
= nStartCp
;
1035 lcl_StripFields(aString
, nNewStartCp
);
1037 if (aString
.getLength()!=1)
1039 bContainsGraphics
= aString
.indexOf(0x1)<0 || aString
.indexOf(0x8)<0;
1041 else // May be a single graphic or object
1044 switch( aString
[0] )
1047 if (!pbTestTxbxContainsText
)
1049 WW8ReaderSave
aSave(this, nNewStartCp
-1);
1050 bool bOldEmbeddObj
= m_bEmbeddObj
;
1051 // bEmbeddObj Ordinarily would have been set by field
1052 // parse, but this is impossible here so...
1053 m_bEmbeddObj
= true;
1055 // 1st look for OLE- or Graph-Indicator Sprms
1056 WW8PLCFx_Cp_FKP
* pChp
= m_xPlcxMan
->GetChpPLCF();
1058 pChp
->GetSprms( &aDesc
);
1059 WW8SprmIter
aSprmIter(aDesc
.pMemPos
, aDesc
.nSprmsLen
, *m_xSprmParser
);
1061 for( int nLoop
= 0; nLoop
< 2; ++nLoop
)
1063 while (aSprmIter
.GetSprms())
1065 const sal_uInt8
*const pParams(aSprmIter
.GetCurrentParams());
1066 if (nullptr == pParams
)
1068 sal_uInt16 nCurrentId
= aSprmIter
.GetCurrentId();
1069 switch( nCurrentId
)
1075 Read_Obj(nCurrentId
, pParams
, 1);
1077 case 68: // Read_Pic()
1079 case NS_sprm::LN_CObjLocation
:
1080 Read_PicLoc(nCurrentId
, pParams
, 1);
1083 aSprmIter
.advance();
1088 pChp
->GetPCDSprms( aDesc
);
1089 aSprmIter
.SetSprms( aDesc
.pMemPos
,
1093 aSave
.Restore(this);
1094 m_bEmbeddObj
=bOldEmbeddObj
;
1096 // then import either an OLE of a Graphic
1099 if( bMakeSdrGrafObj
&& pTextObj
&&
1100 pTextObj
->getParentSdrObjectFromSdrObject() )
1102 // use SdrOleObj/SdrGrafObj instead of
1103 // SdrTextObj in this Group
1106 SdrObject
* pNew
= ImportOleBase(aGraph
);
1110 pNew
= new SdrGrafObj(*m_pDrawModel
);
1111 static_cast<SdrGrafObj
*>(pNew
)->SetGraphic(aGraph
);
1116 pNew
->SetLogicRect( pTextObj
->GetCurrentBoundRect() );
1117 pNew
->SetLayer( pTextObj
->GetLayer() );
1119 pTextObj
->getParentSdrObjectFromSdrObject()->GetSubList()->
1120 ReplaceObject(pNew
, pTextObj
->GetOrdNum());
1123 pFlyFormat
= ImportOle();
1128 InsertAttrsAsDrawingAttrs(nNewStartCp
, nNewStartCp
+1,
1130 pFlyFormat
= ImportGraf(bMakeSdrGrafObj
? pTextObj
: nullptr,
1136 if ( (!pbTestTxbxContainsText
) && (!m_bObj
) )
1137 pFlyFormat
= Read_GrafLayer( nPosCp
);
1146 if( pFlyFormat
&& pRecord
)
1148 SfxItemSet
aFlySet( m_rDoc
.GetAttrPool(),
1149 svl::Items
<RES_FRMATR_BEGIN
, RES_FRMATR_END
-1, XATTR_START
, XATTR_END
>{} );
1151 tools::Rectangle
aInnerDist( pRecord
->nDxTextLeft
,
1152 pRecord
->nDyTextTop
,
1153 pRecord
->nDxTextRight
,
1154 pRecord
->nDyTextBottom
);
1155 MatchSdrItemsIntoFlySet( pTextObj
,
1157 pRecord
->eLineStyle
,
1158 pRecord
->eLineDashing
,
1159 pRecord
->eShapeType
,
1162 pFlyFormat
->SetFormatAttr( aFlySet
);
1164 MapWrapIntoFlyFormat(pRecord
, pFlyFormat
);
1167 rbEraseTextObj
= (nullptr != pFlyFormat
);
1173 *pnStartCp
= nStartCp
;
1177 if( pbTestTxbxContainsText
)
1178 *pbTestTxbxContainsText
= bTextWasRead
&& ! rbEraseTextObj
;
1179 else if( !rbEraseTextObj
)
1183 m_pDrawEditEngine
->SetText(aOrigString
);
1184 InsertAttrsAsDrawingAttrs(nStartCp
, nEndCp
, eType
);
1187 bool bVertical
= pTextObj
->IsVerticalWriting();
1188 std::unique_ptr
<OutlinerParaObject
> pOp(new OutlinerParaObject(m_pDrawEditEngine
->CreateTextObject()));
1189 pOp
->SetOutlinerMode( OutlinerMode::TextObject
);
1190 pOp
->SetVertical( bVertical
);
1191 pTextObj
->NbcSetOutlinerParaObject( std::move(pOp
) );
1192 pTextObj
->SetVerticalWriting(bVertical
);
1194 // For the next TextBox also remove the old paragraph attributes
1195 // and styles, otherwise the next box will start with the wrong
1197 // Course of action: delete text = reduce to one paragraph
1198 // and on this one delete the paragraph attributes
1200 m_pDrawEditEngine
->SetText( OUString() );
1201 m_pDrawEditEngine
->SetParaAttribs(0, m_pDrawEditEngine
->GetEmptyItemSet());
1204 m_pStrm
->Seek( nOld
);
1205 if (pbContainsGraphics
)
1206 *pbContainsGraphics
= bContainsGraphics
;
1209 bool SwWW8ImplReader::TxbxChainContainsRealText(sal_uInt16 nTxBxS
, tools::Long
& rStartCp
,
1210 tools::Long
& rEndCp
)
1212 bool bErase
, bContainsText
;
1213 InsertTxbxText( nullptr,nullptr,nTxBxS
,USHRT_MAX
,0,nullptr,false, bErase
, &bContainsText
,
1214 &rStartCp
, &rEndCp
);
1215 return bContainsText
;
1218 // TextBoxes only for Ver67 !!
1219 SdrObject
* SwWW8ImplReader::ReadTextBox(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
1222 WW8_DP_TXTBOX aTextB
;
1224 if( !ReadGrafStart( static_cast<void*>(&aTextB
), sizeof( aTextB
), pHd
, rSet
) )
1227 Point
aP0( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
)) + m_nDrawXOfs2
,
1228 static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
)) + m_nDrawYOfs2
);
1230 aP1
.AdjustX(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dxa
)) );
1231 aP1
.AdjustY(static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dya
)) );
1233 SdrRectObj
* pObj
= new SdrRectObj(
1236 tools::Rectangle(aP0
, aP1
));
1238 pObj
->NbcSetSnapRect(tools::Rectangle(aP0
, aP1
));
1239 Size
aSize( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dxa
)) ,
1240 static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->dya
)) );
1242 tools::Long nStartCpFly
,nEndCpFly
;
1243 bool bContainsGraphics
;
1244 InsertTxbxText(pObj
, &aSize
, 0, 0, 0, nullptr, false,
1245 bDummy
,nullptr,&nStartCpFly
,&nEndCpFly
,&bContainsGraphics
);
1247 SetStdAttr( rSet
, aTextB
.aLnt
, aTextB
.aShd
);
1248 SetFill( rSet
, aTextB
.aFill
);
1250 rSet
.Put( SdrTextFitToSizeTypeItem( drawing::TextFitToSizeType_NONE
) );
1251 rSet
.Put( makeSdrTextAutoGrowWidthItem(false));
1252 rSet
.Put( makeSdrTextAutoGrowHeightItem(false));
1253 rSet
.Put( makeSdrTextLeftDistItem( MIN_BORDER_DIST
*2 ) );
1254 rSet
.Put( makeSdrTextRightDistItem( MIN_BORDER_DIST
*2 ) );
1255 rSet
.Put( makeSdrTextUpperDistItem( MIN_BORDER_DIST
) );
1256 rSet
.Put( makeSdrTextLowerDistItem( MIN_BORDER_DIST
) );
1261 SdrObject
* SwWW8ImplReader::ReadCaptionBox(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
1263 static const SdrCaptionType aCaptA
[] = { SdrCaptionType::Type1
, SdrCaptionType::Type2
,
1264 SdrCaptionType::Type3
, SdrCaptionType::Type4
};
1266 WW8_DP_CALLOUT_TXTBOX aCallB
;
1268 if( !ReadGrafStart( static_cast<void*>(&aCallB
), sizeof( aCallB
), pHd
, rSet
) )
1271 sal_uInt16 nCount
= SVBT16ToUInt16( aCallB
.dpPolyLine
.aBits1
) >> 1 & 0x7fff;
1274 SAL_WARN("sw.ww8", "Short CaptionBox header");
1278 std::unique_ptr
<SVBT16
[]> xP(new SVBT16
[nCount
* 2]);
1280 bool bCouldRead
= checkRead(*m_pStrm
, xP
.get(), nCount
* 4); // read points
1283 SAL_WARN("sw.ww8", "Short CaptionBox header");
1287 sal_uInt8 nTyp
= static_cast<sal_uInt8
>(nCount
) - 1;
1288 if( nTyp
== 1 && SVBT16ToUInt16( xP
[0] ) == SVBT16ToUInt16( xP
[2] ) )
1291 Point
aP0( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
)) +
1292 static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadTxbx
.xa
)) + m_nDrawXOfs2
,
1293 static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
))
1294 + static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadTxbx
.ya
)) + m_nDrawYOfs2
);
1296 aP1
.AdjustX(static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadTxbx
.dxa
)) );
1297 aP1
.AdjustY(static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadTxbx
.dya
)) );
1298 Point
aP2( static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
))
1299 + static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadPolyLine
.xa
))
1300 + m_nDrawXOfs2
+ static_cast<sal_Int16
>(SVBT16ToUInt16( xP
[0] )),
1301 static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
))
1302 + static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadPolyLine
.ya
))
1303 + m_nDrawYOfs2
+ static_cast<sal_Int16
>(SVBT16ToUInt16( xP
[1] )) );
1306 SdrCaptionObj
* pObj
= new SdrCaptionObj(
1308 tools::Rectangle(aP0
, aP1
),
1311 pObj
->NbcSetSnapRect(tools::Rectangle(aP0
, aP1
));
1312 Size
aSize( static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadTxbx
.dxa
)),
1313 static_cast<sal_Int16
>(SVBT16ToUInt16( aCallB
.dpheadTxbx
.dya
)) );
1314 bool bEraseThisObject
;
1316 InsertTxbxText(pObj
, &aSize
, 0, 0, 0, nullptr, false, bEraseThisObject
);
1318 if( SVBT16ToUInt16( aCallB
.dptxbx
.aLnt
.lnps
) != 5 ) // Is border visible ?
1319 SetStdAttr( rSet
, aCallB
.dptxbx
.aLnt
, aCallB
.dptxbx
.aShd
);
1320 else // no -> take lines
1321 SetStdAttr( rSet
, aCallB
.dpPolyLine
.aLnt
, aCallB
.dptxbx
.aShd
);
1322 SetFill( rSet
, aCallB
.dptxbx
.aFill
);
1323 rSet
.Put(SdrCaptionTypeItem(aCaptA
[nTyp
% SAL_N_ELEMENTS(aCaptA
)]));
1328 SdrObject
*SwWW8ImplReader::ReadGroup(WW8_DPHEAD
const * pHd
, SfxAllItemSet
&rSet
)
1332 if( !ReadGrafStart( static_cast<void*>(&nGrouped
), sizeof( nGrouped
), pHd
, rSet
) )
1335 #ifdef OSL_BIGENDIAN
1336 nGrouped
= (sal_Int16
)OSL_SWAPWORD( nGrouped
);
1339 m_nDrawXOfs
= m_nDrawXOfs
+ static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
));
1340 m_nDrawYOfs
= m_nDrawYOfs
+ static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
));
1342 SdrObject
* pObj
= new SdrObjGroup(*m_pDrawModel
);
1344 short nLeft
= static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->cb
)) - sizeof( WW8_DPHEAD
);
1345 for (int i
= 0; i
< nGrouped
&& nLeft
>= static_cast<short>(sizeof(WW8_DPHEAD
)); ++i
)
1347 SfxAllItemSet
aSet(m_pDrawModel
->GetItemPool());
1348 if (SdrObject
*pObject
= ReadGrafPrimitive(nLeft
, aSet
))
1350 // first add and then set ItemSet
1351 SdrObjList
*pSubGroup
= pObj
->GetSubList();
1352 OSL_ENSURE(pSubGroup
, "Why no sublist available?");
1354 pSubGroup
->InsertObject(pObject
, 0);
1355 pObject
->SetMergedItemSetAndBroadcast(aSet
);
1359 m_nDrawXOfs
= m_nDrawXOfs
- static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->xa
));
1360 m_nDrawYOfs
= m_nDrawYOfs
- static_cast<sal_Int16
>(SVBT16ToUInt16( pHd
->ya
));
1365 SdrObject
* SwWW8ImplReader::ReadGrafPrimitive(short& rLeft
, SfxAllItemSet
&rSet
)
1367 // This whole archaic word 6 graphic import can probably be refactored
1368 // into an object hierarchy with a little effort.
1369 SdrObject
*pRet
=nullptr;
1370 WW8_DPHEAD aHd
; // Read Draw-Primitive-Header
1371 bool bCouldRead
= checkRead(*m_pStrm
, &aHd
, sizeof(WW8_DPHEAD
)) &&
1372 SVBT16ToUInt16(aHd
.cb
) >= sizeof(WW8_DPHEAD
);
1373 OSL_ENSURE(bCouldRead
, "Graphic Primitive header short read" );
1380 if( rLeft
>= SVBT16ToUInt16(aHd
.cb
) ) // precautions
1382 rSet
.Put(SwFormatSurround(css::text::WrapTextMode_THROUGH
));
1383 switch (SVBT16ToUInt16(aHd
.dpk
) & 0xff )
1386 pRet
= ReadGroup(&aHd
, rSet
);
1389 pRet
= ReadLine(&aHd
, rSet
);
1392 pRet
= ReadTextBox(&aHd
, rSet
);
1395 pRet
= ReadRect(&aHd
, rSet
);
1398 pRet
= ReadEllipse(&aHd
, rSet
);
1401 pRet
= ReadArc(&aHd
, rSet
);
1404 pRet
= ReadPolyLine(&aHd
, rSet
);
1407 pRet
= ReadCaptionBox(&aHd
, rSet
);
1410 m_pStrm
->SeekRel(SVBT16ToUInt16(aHd
.cb
) - sizeof(WW8_DPHEAD
));
1416 OSL_ENSURE( false, "+Grafik-Overlap" );
1418 rLeft
= rLeft
- SVBT16ToUInt16( aHd
.cb
);
1422 void SwWW8ImplReader::ReadGrafLayer1( WW8PLCFspecial
* pPF
, tools::Long nGrafAnchorCp
)
1424 pPF
->SeekPos( nGrafAnchorCp
);
1427 if( !pPF
->Get( nStartFc
, pF0
) )
1429 OSL_ENSURE( false, "+Where is the graphic (2) ?" );
1432 WW8_FDOA
* pF
= static_cast<WW8_FDOA
*>(pF0
);
1433 if( !SVBT32ToUInt32( pF
->fc
) )
1435 OSL_ENSURE( false, "+Where is the graphic (3) ?" );
1439 bool bCouldSeek
= checkSeek(*m_pStrm
, SVBT32ToUInt32(pF
->fc
));
1440 OSL_ENSURE(bCouldSeek
, "Invalid graphic offset");
1446 bool bCouldRead
= checkRead(*m_pStrm
, &aDo
, sizeof(WW8_DO
));
1447 OSL_ENSURE(bCouldRead
, "Short graphic header");
1451 short nLeft
= SVBT16ToUInt16( aDo
.cb
) - sizeof( WW8_DO
);
1452 while (nLeft
> static_cast<short>(sizeof(WW8_DPHEAD
)))
1454 SfxAllItemSet
aSet( m_pDrawModel
->GetItemPool() );
1455 if (SdrObject
*pObject
= ReadGrafPrimitive(nLeft
, aSet
))
1457 m_xWWZOrder
->InsertDrawingObject(pObject
, SVBT16ToUInt16(aDo
.dhgt
));
1459 tools::Rectangle
aRect(pObject
->GetSnapRect());
1461 const sal_uInt32 nCntRelTo
= 3;
1463 // Adjustment is horizontally relative to...
1464 static const sal_Int16 aHoriRelOriTab
[nCntRelTo
] =
1466 text::RelOrientation::PAGE_PRINT_AREA
, // 0 is page textarea margin
1467 text::RelOrientation::PAGE_FRAME
, // 1 is page margin
1468 text::RelOrientation::FRAME
, // 2 is relative to paragraph
1471 // Adjustment is vertically relative to...
1472 static const sal_Int16 aVertRelOriTab
[nCntRelTo
] =
1474 text::RelOrientation::PAGE_PRINT_AREA
, // 0 is page textarea margin
1475 text::RelOrientation::PAGE_FRAME
, // 1 is page margin
1476 text::RelOrientation::FRAME
, // 2 is relative to paragraph
1479 const int nXAlign
= aDo
.bx
< nCntRelTo
? aDo
.bx
: 0;
1480 const int nYAlign
= aDo
.by
< nCntRelTo
? aDo
.by
: 0;
1482 aSet
.Put(SwFormatHoriOrient(aRect
.Left(), text::HoriOrientation::NONE
,
1483 aHoriRelOriTab
[ nXAlign
]));
1484 aSet
.Put(SwFormatVertOrient(aRect
.Top(), text::VertOrientation::NONE
,
1485 aVertRelOriTab
[ nYAlign
]));
1487 SwFrameFormat
*pFrame
= m_rDoc
.getIDocumentContentOperations().InsertDrawObj( *m_pPaM
, *pObject
, aSet
);
1488 pObject
->SetMergedItemSet(aSet
);
1490 if (SwDrawFrameFormat
*pDrawFrame
= dynamic_cast<SwDrawFrameFormat
*>(pFrame
))
1492 pDrawFrame
->PosAttrSet();
1495 AddAutoAnchor(pFrame
);
1500 sal_Int32
SwMSDffManager::GetEscherLineMatch(MSO_LineStyle eStyle
,
1501 MSO_SPT eShapeType
, sal_Int32
&rThick
)
1503 sal_Int32 nOutsideThick
= 0;
1505 Note: In contrast to the regular WinWord table and frame border width,
1506 where the overall border width has to be calculated from the width of *one*
1507 line, the data from ESCHER already contains the overall width [twips]!
1509 The WinWord default is 15 tw. We take for this our 20 tw line.
1510 (0.75 pt and 1.0 pt looking more similar on hardcopy than 0.75 pt and our
1511 0.05 pt hairline.) The hairline we only set by WinWord width up to max.
1516 case mso_lineTriple
:
1517 case mso_lineSimple
:
1518 nOutsideThick
= eShapeType
!= mso_sptTextBox
? rThick
: rThick
/2;
1520 case mso_lineDouble
:
1521 if (eShapeType
== mso_sptTextBox
)
1523 nOutsideThick
= rThick
/6;
1524 rThick
= rThick
*2/3;
1527 nOutsideThick
= rThick
*2/3;
1529 case mso_lineThickThin
:
1530 if (eShapeType
== mso_sptTextBox
)
1532 nOutsideThick
= rThick
*3/10;
1533 rThick
= rThick
*4/5;
1536 nOutsideThick
= rThick
*4/5;
1538 case mso_lineThinThick
:
1540 if (eShapeType
== mso_sptTextBox
)
1542 nOutsideThick
= rThick
/10;
1543 rThick
= rThick
*3/5;
1546 nOutsideThick
= rThick
*3/5;
1552 return nOutsideThick
;
1555 // Returns the thickness of the line outside the frame, the logic of
1556 // words positioning of borders around floating objects is that of a
1558 sal_Int32
SwWW8ImplReader::MatchSdrBoxIntoFlyBoxItem(const Color
& rLineColor
,
1559 MSO_LineStyle eLineStyle
, MSO_LineDashing eDashing
, MSO_SPT eShapeType
, sal_Int32
&rLineThick
,
1562 sal_Int32 nOutsideThick
= 0;
1564 return nOutsideThick
;
1566 SvxBorderLineStyle nIdx
= SvxBorderLineStyle::NONE
;
1568 sal_Int32 nLineThick
=rLineThick
;
1569 nOutsideThick
= SwMSDffManager::GetEscherLineMatch(eLineStyle
,
1570 eShapeType
, rLineThick
);
1573 Note: In contrast to the regular WinWord table and frame border width,
1574 where the overall border width has to be calculated from the width of *one*
1575 line, the data from ESCHER already contains the overall width [twips]!
1577 The WinWord default is 15 tw. We take for this our 20 tw line.
1578 (0.75 pt and 1.0 pt looking more similar on hardcopy than 0.75 pt and our
1579 0.05 pt hairline.) The hairline we only set by WinWord width up to max.
1582 switch( +eLineStyle
)
1584 // first the single lines
1585 case mso_lineSimple
:
1586 nIdx
= SvxBorderLineStyle::SOLID
;
1588 // second the double lines
1589 case mso_lineDouble
:
1590 nIdx
= SvxBorderLineStyle::DOUBLE
;
1592 case mso_lineThickThin
:
1593 nIdx
= SvxBorderLineStyle::THICKTHIN_SMALLGAP
;
1595 case mso_lineThinThick
:
1596 nIdx
= SvxBorderLineStyle::THINTHICK_SMALLGAP
;
1598 // We have no triple border, use double instead.
1599 case mso_lineTriple
:
1600 nIdx
= SvxBorderLineStyle::DOUBLE
;
1602 // no line style is set
1603 case MSO_LineStyle(USHRT_MAX
):
1605 // erroneously not implemented line style is set
1607 OSL_ENSURE(false, "eLineStyle is not (yet) implemented!");
1613 case mso_lineDashGEL
:
1614 nIdx
= SvxBorderLineStyle::DASHED
;
1616 case mso_lineDotGEL
:
1617 nIdx
= SvxBorderLineStyle::DOTTED
;
1623 if (SvxBorderLineStyle::NONE
!= nIdx
)
1625 SvxBorderLine aLine
;
1626 aLine
.SetColor( rLineColor
);
1628 aLine
.SetWidth( nLineThick
); // No conversion here, nLineThick is already in twips
1629 aLine
.SetBorderLineStyle(nIdx
);
1631 for(SvxBoxItemLine nLine
: o3tl::enumrange
<SvxBoxItemLine
>())
1633 // aLine is cloned by SetLine
1634 rBox
.SetLine(&aLine
, nLine
);
1638 return nOutsideThick
;
1641 #define WW8ITEMVALUE(ItemSet,Id,Cast) ItemSet.GetItem<Cast>(Id)->GetValue()
1643 void SwWW8ImplReader::MatchSdrItemsIntoFlySet( SdrObject
const * pSdrObj
,
1644 SfxItemSet
& rFlySet
, MSO_LineStyle eLineStyle
, MSO_LineDashing eDashing
, MSO_SPT eShapeType
,
1645 tools::Rectangle
& rInnerDist
)
1648 attributes to be set on the frame
1649 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1650 SwFormatFrameSize if not set, set here
1651 SvxLRSpaceItem set here
1652 SvxULSpaceItem set here
1653 SvxOpaqueItem (Currently not possible for frames! khz 10.2.1999)
1654 SwFormatSurround already set
1655 SwFormatVertOrient already set
1656 SwFormatHoriOrient already set
1657 SwFormatAnchor already set
1659 SvxBrushItem set here
1660 SvxShadowItem set here
1663 // 1. GraphicObject of documents?
1666 const SfxItemSet
& rOldSet
= pSdrObj
->GetMergedItemSet();
1668 // some Items can be taken over directly
1669 static sal_uInt16
const aDirectMatch
[]
1671 RES_LR_SPACE
, // outer spacing left/right: SvxLRSpaceItem
1672 RES_UL_SPACE
// outer spacing top/bottom: SvxULSpaceItem
1674 const SfxPoolItem
* pPoolItem
;
1675 for(sal_uInt16 i
: aDirectMatch
)
1676 if( SfxItemState::SET
== rOldSet
.GetItemState(i
, false, &pPoolItem
) )
1678 rFlySet
.Put( *pPoolItem
);
1681 // take new XATTR items directly. Skip old RES_BACKGROUND if new FILLSTYLE taken.
1682 bool bSkipResBackground
= false;
1683 SfxItemPool
* pPool
= rFlySet
.GetPool();
1686 for ( sal_uInt16 i
= XATTR_START
; i
< XATTR_END
; ++i
)
1688 // Not all Fly types support XATTRs - skip unsupported attributes
1689 SfxItemPool
* pAttrPool
= pPool
->GetMasterPool();
1690 while ( pAttrPool
&& !pAttrPool
->IsInRange(i
) )
1691 pAttrPool
= pAttrPool
->GetSecondaryPool();
1695 if ( SfxItemState::SET
== rOldSet
.GetItemState(i
, false, &pPoolItem
) )
1697 rFlySet
.Put( *pPoolItem
);
1698 if ( i
== XATTR_FILLSTYLE
)
1700 const drawing::FillStyle eFill
= static_cast<const XFillStyleItem
*>(pPoolItem
)->GetValue();
1701 // Transparency forced in certain situations when fillstyle is none - use old logic for that case still
1702 // which is especially needed for export purposes (tdf112618).
1703 if ( eFill
!= drawing::FillStyle_NONE
)
1704 bSkipResBackground
= true;
1710 // now calculate the borders and build the box: The unit is needed for the
1712 SvxBoxItem
aBox(sw::util::ItemGet
<SvxBoxItem
>(rFlySet
, RES_BOX
));
1713 // dashed or solid becomes solid
1714 // WW-default: 0.75 pt = 15 twips
1715 sal_Int32 nLineThick
= 15, nOutside
=0;
1717 // check if LineStyle is *really* set!
1718 const SfxPoolItem
* pItem
;
1720 SfxItemState eState
= rOldSet
.GetItemState(XATTR_LINESTYLE
,true,&pItem
);
1721 if( eState
== SfxItemState::SET
)
1723 // Now, that we know there is a line style we will make use the
1724 // parameter given to us when calling the method... :-)
1725 const Color aLineColor
= rOldSet
.Get(XATTR_LINECOLOR
).GetColorValue();
1726 nLineThick
= WW8ITEMVALUE(rOldSet
, XATTR_LINEWIDTH
, XLineWidthItem
);
1729 nLineThick
= 1; // for Writer, zero is "no border", so set a minimal value
1731 nOutside
= MatchSdrBoxIntoFlyBoxItem(aLineColor
, eLineStyle
,
1732 eDashing
, eShapeType
, nLineThick
, aBox
);
1735 rInnerDist
.AdjustLeft(nLineThick
);
1736 rInnerDist
.AdjustTop(nLineThick
);
1737 rInnerDist
.AdjustRight(nLineThick
);
1738 rInnerDist
.AdjustBottom(nLineThick
);
1740 rInnerDist
.AdjustLeft( -(aBox
.CalcLineWidth( SvxBoxItemLine::LEFT
)) );
1741 rInnerDist
.AdjustTop( -(aBox
.CalcLineWidth( SvxBoxItemLine::TOP
)) );
1742 rInnerDist
.AdjustRight( -(aBox
.CalcLineWidth( SvxBoxItemLine::RIGHT
)) );
1743 rInnerDist
.AdjustBottom( -(aBox
.CalcLineWidth( SvxBoxItemLine::BOTTOM
)) );
1745 // set distances from box's border to text contained within the box
1746 if( 0 < rInnerDist
.Left() )
1747 aBox
.SetDistance( static_cast<sal_uInt16
>(rInnerDist
.Left()), SvxBoxItemLine::LEFT
);
1748 if( 0 < rInnerDist
.Top() )
1749 aBox
.SetDistance( static_cast<sal_uInt16
>(rInnerDist
.Top()), SvxBoxItemLine::TOP
);
1750 if( 0 < rInnerDist
.Right() )
1751 aBox
.SetDistance( static_cast<sal_uInt16
>(rInnerDist
.Right()), SvxBoxItemLine::RIGHT
);
1752 if( 0 < rInnerDist
.Bottom() )
1753 aBox
.SetDistance( static_cast<sal_uInt16
>(rInnerDist
.Bottom()), SvxBoxItemLine::BOTTOM
);
1755 bool bFixSize
= !(WW8ITEMVALUE(rOldSet
, SDRATTR_TEXT_AUTOGROWHEIGHT
,
1758 // Size: SwFormatFrameSize
1759 if( SfxItemState::SET
!= rFlySet
.GetItemState(RES_FRM_SIZE
, false) )
1761 const tools::Rectangle
& rSnapRect
= pSdrObj
->GetSnapRect();
1762 // if necessary adapt width and position of the framework: The
1763 // recorded interior is to remain equally large despite thick edges.
1764 rFlySet
.Put( SwFormatFrameSize(bFixSize
? SwFrameSize::Fixed
: SwFrameSize::Variable
,
1765 rSnapRect
.GetWidth() + 2*nOutside
,
1766 rSnapRect
.GetHeight() + 2*nOutside
) );
1768 else // If a size is set, adjust it to consider border thickness
1770 SwFormatFrameSize aSize
= rFlySet
.Get(RES_FRM_SIZE
);
1772 SwFormatFrameSize
aNewSize(bFixSize
? SwFrameSize::Fixed
: SwFrameSize::Variable
,
1773 aSize
.GetWidth() + 2*nOutside
,
1774 aSize
.GetHeight() + 2*nOutside
);
1775 aNewSize
.SetWidthSizeType(aSize
.GetWidthSizeType());
1776 rFlySet
.Put( aNewSize
);
1779 // Sadly word puts escher borders outside the graphic, but orients the
1780 // graphic in relation to the top left inside the border. We don't
1783 SwFormatHoriOrient aHori
= rFlySet
.Get(RES_HORI_ORIENT
);
1784 aHori
.SetPos(MakeSafePositioningValue(aHori
.GetPos()-nOutside
));
1787 SwFormatVertOrient aVert
= rFlySet
.Get(RES_VERT_ORIENT
);
1788 aVert
.SetPos(aVert
.GetPos()-nOutside
);
1792 // now set the border
1793 rFlySet
.Put( aBox
);
1795 // shadow of the box: SvxShadowItem
1796 if( WW8ITEMVALUE(rOldSet
, SDRATTR_SHADOW
, SdrOnOffItem
) )
1798 SvxShadowItem
aShadow( RES_SHADOW
);
1800 const Color aShdColor
= rOldSet
.Get(SDRATTR_SHADOWCOLOR
).GetColorValue();
1801 const sal_Int32 nShdDistX
= WW8ITEMVALUE(rOldSet
, SDRATTR_SHADOWXDIST
,
1803 const sal_Int32 nShdDistY
= WW8ITEMVALUE(rOldSet
, SDRATTR_SHADOWYDIST
,
1806 aShadow
.SetColor( aShdColor
);
1808 aShadow
.SetWidth(writer_cast
<sal_uInt16
>((std::abs( nShdDistX
) +
1809 std::abs( nShdDistY
)) / 2 ));
1811 SvxShadowLocation eShdPosi
;
1812 if( 0 <= nShdDistX
)
1814 if( 0 <= nShdDistY
)
1815 eShdPosi
= SvxShadowLocation::BottomRight
;
1817 eShdPosi
= SvxShadowLocation::TopRight
;
1821 if( 0 <= nShdDistY
)
1822 eShdPosi
= SvxShadowLocation::BottomLeft
;
1824 eShdPosi
= SvxShadowLocation::TopLeft
;
1826 aShadow
.SetLocation( eShdPosi
);
1828 rFlySet
.Put( aShadow
);
1830 SvxBrushItem
aBrushItem(COL_WHITE
, RES_BACKGROUND
);
1831 bool bBrushItemOk
= false;
1832 sal_uInt8 nTrans
= 0;
1834 // Separate transparency
1835 eState
= rOldSet
.GetItemState(XATTR_FILLTRANSPARENCE
, true, &pItem
);
1836 if (!bSkipResBackground
&& eState
== SfxItemState::SET
)
1838 sal_uInt16 nRes
= WW8ITEMVALUE(rOldSet
, XATTR_FILLTRANSPARENCE
,
1839 XFillTransparenceItem
);
1840 nTrans
= sal_uInt8((nRes
* 0xFE) / 100);
1841 aBrushItem
.GetColor().SetTransparency(nTrans
);
1842 bBrushItemOk
= true;
1845 // Background: SvxBrushItem
1846 eState
= rOldSet
.GetItemState(XATTR_FILLSTYLE
, true, &pItem
);
1847 if (!bSkipResBackground
&& eState
== SfxItemState::SET
)
1849 const drawing::FillStyle eFill
= static_cast<const XFillStyleItem
*>(pItem
)->GetValue();
1854 case drawing::FillStyle_NONE
:
1855 // Writer graphics don't have it yet
1856 if (eShapeType
!= mso_sptPictureFrame
)
1858 aBrushItem
.GetColor().SetTransparency(0xFE);
1859 bBrushItemOk
= true;
1862 case drawing::FillStyle_SOLID
:
1863 case drawing::FillStyle_GRADIENT
:
1865 const Color aColor
=
1866 rOldSet
.Get(XATTR_FILLCOLOR
).GetColorValue();
1867 aBrushItem
.SetColor(aColor
);
1869 if (bBrushItemOk
) // has trans
1870 aBrushItem
.GetColor().SetTransparency(nTrans
);
1872 bBrushItemOk
= true;
1875 case drawing::FillStyle_HATCH
:
1877 case drawing::FillStyle_BITMAP
:
1879 GraphicObject
aGrfObj(rOldSet
.Get(XATTR_FILLBITMAP
).GetGraphicObject());
1880 const bool bTile(WW8ITEMVALUE(rOldSet
, XATTR_FILLBMP_TILE
, SfxBoolItem
));
1882 if(bBrushItemOk
) // has trans
1884 GraphicAttr
aAttr(aGrfObj
.GetAttr());
1886 aAttr
.SetTransparency(nTrans
);
1887 aGrfObj
.SetAttr(aAttr
);
1890 aBrushItem
.SetGraphicObject(aGrfObj
);
1891 aBrushItem
.SetGraphicPos(bTile
? GPOS_TILED
: GPOS_AREA
);
1892 bBrushItemOk
= true;
1899 rFlySet
.Put(aBrushItem
);
1902 void SwWW8ImplReader::AdjustLRWrapForWordMargins(
1903 const SvxMSDffImportRec
&rRecord
, SvxLRSpaceItem
&rLR
)
1905 sal_uInt32 nXRelTo
= SvxMSDffImportRec::RELTO_DEFAULT
;
1906 if ( rRecord
.nXRelTo
)
1908 nXRelTo
= *rRecord
.nXRelTo
;
1911 // Left adjustments - if horizontally aligned to left of
1912 // margin or column then remove the left wrapping
1913 if (rRecord
.nXAlign
== 1)
1915 if ((nXRelTo
== 0) || (nXRelTo
== 2))
1916 rLR
.SetLeft(sal_uInt16(0));
1919 // Right adjustments - if horizontally aligned to right of
1920 // margin or column then remove the right wrapping
1921 if (rRecord
.nXAlign
== 3)
1923 if ((nXRelTo
== 0) || (nXRelTo
== 2))
1924 rLR
.SetRight(sal_uInt16(0));
1927 // Inside margin, remove left wrapping
1928 if ((rRecord
.nXAlign
== 4) && (nXRelTo
== 0))
1930 rLR
.SetLeft(sal_uInt16(0));
1933 // Outside margin, remove left wrapping
1934 if ((rRecord
.nXAlign
== 5) && (nXRelTo
== 0))
1936 rLR
.SetRight(sal_uInt16(0));
1940 void SwWW8ImplReader::AdjustULWrapForWordMargins(
1941 const SvxMSDffImportRec
&rRecord
, SvxULSpaceItem
&rUL
)
1943 sal_uInt32 nYRelTo
= SvxMSDffImportRec::RELTO_DEFAULT
;
1944 if ( rRecord
.nYRelTo
)
1946 nYRelTo
= *rRecord
.nYRelTo
;
1949 // Top adjustment - remove upper wrapping if aligned to page
1950 // printable area or to page
1951 if (rRecord
.nYAlign
== 1)
1953 if ((nYRelTo
== 0) || (nYRelTo
== 1))
1954 rUL
.SetUpper(sal_uInt16(0));
1957 // Bottom adjustment - remove bottom wrapping if aligned to page or
1958 // printable area or to page
1959 if (rRecord
.nYAlign
== 3)
1961 if ((nYRelTo
== 0) || (nYRelTo
== 1))
1962 rUL
.SetLower(sal_uInt16(0));
1965 // Remove top margin if aligned vertically inside margin
1966 if ((rRecord
.nYAlign
== 4) && (nYRelTo
== 0))
1967 rUL
.SetUpper(sal_uInt16(0));
1970 void SwWW8ImplReader::MapWrapIntoFlyFormat(SvxMSDffImportRec
const * pRecord
,
1971 SwFrameFormat
* pFlyFormat
)
1973 if (!pRecord
|| !pFlyFormat
)
1976 if (pRecord
->nDxWrapDistLeft
|| pRecord
->nDxWrapDistRight
)
1978 SvxLRSpaceItem
aLR(writer_cast
<sal_uInt16
>(pRecord
->nDxWrapDistLeft
),
1979 writer_cast
<sal_uInt16
>(pRecord
->nDxWrapDistRight
), 0, 0, RES_LR_SPACE
);
1980 AdjustLRWrapForWordMargins(*pRecord
, aLR
);
1981 pFlyFormat
->SetFormatAttr(aLR
);
1983 if (pRecord
->nDyWrapDistTop
|| pRecord
->nDyWrapDistBottom
)
1985 SvxULSpaceItem
aUL(writer_cast
<sal_uInt16
>(pRecord
->nDyWrapDistTop
),
1986 writer_cast
<sal_uInt16
>(pRecord
->nDyWrapDistBottom
), RES_UL_SPACE
);
1987 AdjustULWrapForWordMargins(*pRecord
, aUL
);
1988 pFlyFormat
->SetFormatAttr(aUL
);
1991 // If we are contoured and have a custom polygon...
1992 if (pRecord
->pWrapPolygon
&& pFlyFormat
->GetSurround().IsContour())
1994 if (SwNoTextNode
*pNd
= GetNoTextNodeFromSwFrameFormat(*pFlyFormat
))
1998 Gather round children and hear of a tale that will raise the
1999 hairs on the back of your neck this dark halloween night.
2001 There is a polygon in word that describes the wrapping around
2004 Here are some sample values for the simplest case of a square
2005 around some solid coloured graphics
2007 X Y Pixel size of graphic
2008 TopLeft -54 21600 400x400
2009 Bottom Right 0 21546
2011 TopLeft -108 21600 200x200
2012 Bottom Right 0 21492
2014 TopLeft -216 21600 100x100
2015 Bottom Right 0 21384
2017 TopLeft -432 21600 50x50
2018 Bottom Right 0 21168
2020 TopLeft -76 21600 283x212
2021 Bottom Right 0 21498
2023 So given that the size of the values remains pretty much the
2024 same despite the size of the graphic, we can tell that the
2025 polygon is measured in units that are independent of the
2026 graphic. But why does the left corner move a different value
2027 to the left each time, and why does the bottom move upwards
2028 each time, when the right and top remain at the same value ?
2030 I have no idea, but clearly once we calculate the values out
2031 we see that the left margin is always a fixed realworld
2032 distance from the true left and the polygon bottom is the same
2033 fixed value from the bottom. i.e. 15twips.
2035 So here we take our word provided polygon, shift it to the
2036 right by 15twips and rescale it widthwise to shrink the width
2037 a little to fit the now moved right margin back to where it
2038 was, and stretch the height a little to make the bottom move
2039 down the missing 15twips then we get a polygon that matches
2040 what I actually see in word
2043 tools::PolyPolygon
aPoly(*pRecord
->pWrapPolygon
);
2044 const Size
&rSize
= pNd
->GetTwipSize();
2046 Move to the left by 15twips, and rescale to
2047 a) shrink right bound back to orig position
2048 b) stretch bottom bound to where I think it should have been
2051 Fraction
aMoveHack(ww::nWrap100Percent
, rSize
.Width());
2052 aMoveHack
*= Fraction(15, 1);
2053 tools::Long
nMove(aMoveHack
);
2054 aPoly
.Move(nMove
, 0);
2056 Fraction
aHackX(ww::nWrap100Percent
, ww::nWrap100Percent
+ nMove
);
2057 Fraction
aHackY(ww::nWrap100Percent
, ww::nWrap100Percent
- nMove
);
2058 aPoly
.Scale(double(aHackX
), double(aHackY
));
2060 // Turn polygon back into units that match the graphic's
2061 const Size
&rOrigSize
= pNd
->GetGraphic().GetPrefSize();
2062 Fraction
aMapPolyX(rOrigSize
.Width(), ww::nWrap100Percent
);
2063 Fraction
aMapPolyY(rOrigSize
.Height(), ww::nWrap100Percent
);
2064 aPoly
.Scale(double(aMapPolyX
), double(aMapPolyY
));
2066 // #i47277# - contour is already in unit of the
2067 // graphic preferred unit. Thus, call method <SetContour(..)>
2068 pNd
->SetContour(&aPoly
);
2071 else if (pFlyFormat
->GetSurround().IsContour())
2073 // Contour is enabled, but no polygon is set: disable contour, because Word does not
2074 // Writer-style auto-contour in that case.
2075 SwFormatSurround
aSurround(pFlyFormat
->GetSurround());
2076 aSurround
.SetContour(false);
2077 pFlyFormat
->SetFormatAttr(aSurround
);
2081 static sal_Int32
lcl_ConvertCrop(sal_uInt32
const nCrop
, sal_Int32
const nSize
)
2083 // cast to sal_Int32 to handle negative crop properly
2084 sal_Int32
const nIntegral(static_cast<sal_Int32
>(nCrop
) >> 16);
2085 // fdo#77454: heuristic to detect mangled values written by old OOo/LO
2086 if (abs(nIntegral
) >= 50) // FIXME: what's a good cut-off?
2088 SAL_INFO("sw.ww8", "ignoring suspiciously large crop: " << nIntegral
);
2091 return (nIntegral
* nSize
) + (((nCrop
& 0xffff) * nSize
) >> 16);
2095 SwWW8ImplReader::SetAttributesAtGrfNode(SvxMSDffImportRec
const*const pRecord
,
2096 SwFrameFormat
const *pFlyFormat
, WW8_FSPA
const *pF
)
2098 const SwNodeIndex
* pIdx
= pFlyFormat
->GetContent(false).GetContentIdx();
2099 SwGrfNode
*const pGrfNd(
2100 pIdx
? m_rDoc
.GetNodes()[pIdx
->GetIndex() + 1]->GetGrfNode() : nullptr);
2104 Size
aSz(pGrfNd
->GetTwipSize());
2105 // use type <sal_uInt64> instead of sal_uLong to get correct results
2106 // in the following calculations.
2107 sal_uInt64 nHeight
= aSz
.Height();
2108 sal_uInt64 nWidth
= aSz
.Width();
2110 nWidth
= o3tl::saturating_sub(pF
->nXaRight
, pF
->nXaLeft
);
2111 else if (!nHeight
&& pF
)
2112 nHeight
= o3tl::saturating_sub(pF
->nYaBottom
, pF
->nYaTop
);
2114 if( pRecord
->nCropFromTop
|| pRecord
->nCropFromBottom
||
2115 pRecord
->nCropFromLeft
|| pRecord
->nCropFromRight
)
2117 SwCropGrf aCrop
; // Cropping is stored in 'fixed floats'
2118 // 16.16 (fraction times total
2119 if( pRecord
->nCropFromTop
) // image width or height resp.)
2121 aCrop
.SetTop(lcl_ConvertCrop(pRecord
->nCropFromTop
, nHeight
));
2123 if( pRecord
->nCropFromBottom
)
2125 aCrop
.SetBottom(lcl_ConvertCrop(pRecord
->nCropFromBottom
, nHeight
));
2127 if( pRecord
->nCropFromLeft
)
2129 aCrop
.SetLeft(lcl_ConvertCrop(pRecord
->nCropFromLeft
, nWidth
));
2131 if( pRecord
->nCropFromRight
)
2133 aCrop
.SetRight(lcl_ConvertCrop(pRecord
->nCropFromRight
, nWidth
));
2136 pGrfNd
->SetAttr( aCrop
);
2139 bool bFlipH(pRecord
->nFlags
& ShapeFlag::FlipH
);
2140 bool bFlipV(pRecord
->nFlags
& ShapeFlag::FlipV
);
2141 if ( bFlipH
|| bFlipV
)
2143 SwMirrorGrf aMirror
= pGrfNd
->GetSwAttrSet().GetMirrorGrf();
2147 aMirror
.SetValue(MirrorGraph::Both
);
2149 aMirror
.SetValue(MirrorGraph::Vertical
);
2152 aMirror
.SetValue(MirrorGraph::Horizontal
);
2154 pGrfNd
->SetAttr( aMirror
);
2160 const SfxItemSet
& rOldSet
= pRecord
->pObj
->GetMergedItemSet();
2162 if (WW8ITEMVALUE(rOldSet
, SDRATTR_GRAFCONTRAST
,
2163 SdrGrafContrastItem
))
2165 SwContrastGrf
aContrast(
2166 WW8ITEMVALUE(rOldSet
,
2167 SDRATTR_GRAFCONTRAST
, SdrGrafContrastItem
));
2168 pGrfNd
->SetAttr( aContrast
);
2172 if (WW8ITEMVALUE(rOldSet
, SDRATTR_GRAFLUMINANCE
,
2173 SdrGrafLuminanceItem
))
2175 SwLuminanceGrf
aLuminance(WW8ITEMVALUE(rOldSet
,
2176 SDRATTR_GRAFLUMINANCE
, SdrGrafLuminanceItem
));
2177 pGrfNd
->SetAttr( aLuminance
);
2180 if (WW8ITEMVALUE(rOldSet
, SDRATTR_GRAFGAMMA
, SdrGrafGamma100Item
))
2182 double fVal
= WW8ITEMVALUE(rOldSet
, SDRATTR_GRAFGAMMA
,
2183 SdrGrafGamma100Item
);
2184 pGrfNd
->SetAttr(SwGammaGrf(fVal
/100.));
2188 auto nGrafMode
= rOldSet
.GetItem
<SdrGrafModeItem
>(SDRATTR_GRAFMODE
)->GetValue();
2189 if ( nGrafMode
!= GraphicDrawMode::Standard
)
2191 SwDrawModeGrf
aDrawMode( nGrafMode
);
2192 pGrfNd
->SetAttr( aDrawMode
);
2196 SdrObject
* SwWW8ImplReader::CreateContactObject(SwFrameFormat
* pFlyFormat
)
2200 SdrObject
* pNewObject
= m_bNewDoc
? nullptr : pFlyFormat
->FindRealSdrObject();
2202 pNewObject
= pFlyFormat
->FindSdrObject();
2203 if (!pNewObject
&& dynamic_cast< const SwFlyFrameFormat
*>( pFlyFormat
) != nullptr)
2205 SwFlyDrawContact
* pContactObject(static_cast<SwFlyFrameFormat
*>(pFlyFormat
)->GetOrCreateContact());
2206 pNewObject
= pContactObject
->GetMaster();
2213 // Miserable miserable hack to fudge word's graphic layout in RTL mode to ours.
2214 bool SwWW8ImplReader::MiserableRTLGraphicsHack(SwTwips
&rLeft
, SwTwips nWidth
,
2215 sal_Int16 eHoriOri
, sal_Int16 eHoriRel
)
2217 if (!IsRightToLeft())
2219 return RTLGraphicsHack(rLeft
, nWidth
, eHoriOri
, eHoriRel
,
2220 m_aSectionManager
.GetPageLeft(),
2221 m_aSectionManager
.GetPageRight(),
2222 m_aSectionManager
.GetPageWidth());
2225 RndStdIds
SwWW8ImplReader::ProcessEscherAlign(SvxMSDffImportRec
* pRecord
,
2226 WW8_FSPA
*pFSPA
, SfxItemSet
&rFlySet
)
2228 OSL_ENSURE(pRecord
|| pFSPA
, "give me something! to work with for anchoring");
2229 if (!pRecord
&& !pFSPA
)
2230 return RndStdIds::FLY_AT_PAGE
;
2231 bool bCurSectionVertical
= m_aSectionManager
.CurrentSectionIsVertical();
2233 SvxMSDffImportRec aRecordFromFSPA
;
2235 pRecord
= &aRecordFromFSPA
;
2236 if (!(pRecord
->nXRelTo
) && pFSPA
)
2238 pRecord
->nXRelTo
= sal_Int32(pFSPA
->nbx
);
2240 if (!(pRecord
->nYRelTo
) && pFSPA
)
2242 pRecord
->nYRelTo
= sal_Int32(pFSPA
->nby
);
2245 // nXAlign - abs. Position, Left, Centered, Right, Inside, Outside
2246 // nYAlign - abs. Position, Top, Centered, Bottom, Inside, Outside
2248 // nXRelTo - Page printable area, Page, Column, Character
2249 // nYRelTo - Page printable area, Page, Paragraph, Line
2251 const sal_uInt32 nCntXAlign
= 6;
2252 const sal_uInt32 nCntYAlign
= 6;
2254 const sal_uInt32 nCntRelTo
= 4;
2256 sal_uInt32 nXAlign
= nCntXAlign
> pRecord
->nXAlign
? pRecord
->nXAlign
: 1;
2257 sal_uInt32 nYAlign
= nCntYAlign
> pRecord
->nYAlign
? pRecord
->nYAlign
: 1;
2261 // #i52565# - try to handle special case for objects in tables regarding its X Rel
2263 // if X and Y Rel values are on default take it as a hint, that they have not been set
2264 // by <SwMSDffManager::ProcessObj(..)>
2265 const bool bXYRelHaveDefaultValues
= *pRecord
->nXRelTo
== 2 && *pRecord
->nYRelTo
== 2;
2266 if ( bXYRelHaveDefaultValues
2268 && !bCurSectionVertical
)
2270 if ( sal_uInt32(pFSPA
->nby
) != pRecord
->nYRelTo
)
2272 pRecord
->nYRelTo
= sal_uInt32(pFSPA
->nby
);
2277 sal_uInt32 nXRelTo
= (pRecord
->nXRelTo
&& nCntRelTo
> pRecord
->nXRelTo
) ? *pRecord
->nXRelTo
: 1;
2278 sal_uInt32 nYRelTo
= (pRecord
->nYRelTo
&& nCntRelTo
> pRecord
->nYRelTo
) ? *pRecord
->nYRelTo
: 1;
2280 RndStdIds eAnchor
= IsInlineEscherHack() ? RndStdIds::FLY_AS_CHAR
: RndStdIds::FLY_AT_CHAR
; // #i43718#
2282 SwFormatAnchor
aAnchor( eAnchor
);
2283 aAnchor
.SetAnchor( m_pPaM
->GetPoint() );
2284 rFlySet
.Put( aAnchor
);
2289 // Given new layout where everything is changed to be anchored to
2290 // character the following 4 tables may need to be changed.
2292 // horizontal Adjustment
2293 static const sal_Int16 aHoriOriTab
[ nCntXAlign
] =
2295 text::HoriOrientation::NONE
, // From left position
2296 text::HoriOrientation::LEFT
, // left
2297 text::HoriOrientation::CENTER
, // centered
2298 text::HoriOrientation::RIGHT
, // right
2300 // - inside -> text::HoriOrientation::LEFT and outside -> text::HoriOrientation::RIGHT
2301 text::HoriOrientation::LEFT
, // inside
2302 text::HoriOrientation::RIGHT
// outside
2305 // generic vertical Adjustment
2306 static const sal_Int16 aVertOriTab
[ nCntYAlign
] =
2308 text::VertOrientation::NONE
, // From Top position
2309 text::VertOrientation::TOP
, // top
2310 text::VertOrientation::CENTER
, // centered
2311 text::VertOrientation::BOTTOM
, // bottom
2312 text::VertOrientation::LINE_TOP
, // inside (obscure)
2313 text::VertOrientation::LINE_BOTTOM
// outside (obscure)
2316 // #i22673# - to-line vertical alignment
2317 static const sal_Int16 aToLineVertOriTab
[ nCntYAlign
] =
2319 text::VertOrientation::NONE
, // below
2320 text::VertOrientation::LINE_BOTTOM
, // top
2321 text::VertOrientation::LINE_CENTER
, // centered
2322 text::VertOrientation::LINE_TOP
, // bottom
2323 text::VertOrientation::LINE_BOTTOM
, // inside (obscure)
2324 text::VertOrientation::LINE_TOP
// outside (obscure)
2327 // Adjustment is horizontally relative to...
2328 static const sal_Int16 aHoriRelOriTab
[nCntRelTo
] =
2330 text::RelOrientation::PAGE_PRINT_AREA
, // 0 is page textarea margin
2331 text::RelOrientation::PAGE_FRAME
, // 1 is page margin
2332 text::RelOrientation::FRAME
, // 2 is relative to column
2333 text::RelOrientation::CHAR
// 3 is relative to character
2336 // Adjustment is vertically relative to...
2337 // #i22673# - adjustment for new vertical alignment at top of line.
2338 static const sal_Int16 aVertRelOriTab
[nCntRelTo
] =
2340 text::RelOrientation::PAGE_PRINT_AREA
, // 0 is page textarea margin
2341 text::RelOrientation::PAGE_FRAME
, // 1 is page margin
2342 text::RelOrientation::FRAME
, // 2 is relative to paragraph
2343 text::RelOrientation::TEXT_LINE
// 3 is relative to line
2346 sal_Int16 eHoriOri
= aHoriOriTab
[ nXAlign
];
2347 sal_Int16 eHoriRel
= aHoriRelOriTab
[ nXRelTo
];
2349 // #i36649# - adjustments for certain alignments
2350 if ( eHoriOri
== text::HoriOrientation::LEFT
&& eHoriRel
== text::RelOrientation::PAGE_FRAME
)
2352 // convert 'left to page' to 'from left -<width> to page text area'
2353 eHoriOri
= text::HoriOrientation::NONE
;
2354 eHoriRel
= text::RelOrientation::PAGE_PRINT_AREA
;
2355 const tools::Long nWidth
= pFSPA
->nXaRight
- pFSPA
->nXaLeft
;
2356 pFSPA
->nXaLeft
= -nWidth
;
2357 pFSPA
->nXaRight
= 0;
2359 else if ( eHoriOri
== text::HoriOrientation::RIGHT
&& eHoriRel
== text::RelOrientation::PAGE_FRAME
)
2361 // convert 'right to page' to 'from left 0 to right page border'
2362 eHoriOri
= text::HoriOrientation::NONE
;
2363 eHoriRel
= text::RelOrientation::PAGE_RIGHT
;
2364 const tools::Long nWidth
= pFSPA
->nXaRight
- pFSPA
->nXaLeft
;
2366 pFSPA
->nXaRight
= nWidth
;
2369 // #i24255# - position of floating screen objects in
2370 // R2L layout are given in L2R layout, thus convert them of all
2371 // floating screen objects, which are imported.
2373 // Miserable miserable hack.
2374 SwTwips nWidth
= o3tl::saturating_sub(pFSPA
->nXaRight
, pFSPA
->nXaLeft
);
2375 SwTwips nLeft
= pFSPA
->nXaLeft
;
2376 if (MiserableRTLGraphicsHack(nLeft
, nWidth
, eHoriOri
,
2379 pFSPA
->nXaLeft
= nLeft
;
2380 pFSPA
->nXaRight
= pFSPA
->nXaLeft
+ nWidth
;
2384 // if the object is anchored inside a table cell, is horizontal aligned
2385 // at frame|character and has wrap through, but its attribute
2386 // 'layout in table cell' isn't set, convert its horizontal alignment to page text area.
2387 // #i84783# - use new method <IsObjectLayoutInTableCell()>
2389 ( eHoriRel
== text::RelOrientation::FRAME
|| eHoriRel
== text::RelOrientation::CHAR
) &&
2391 !IsObjectLayoutInTableCell( pRecord
->nLayoutInTableCell
) )
2393 eHoriRel
= text::RelOrientation::PAGE_PRINT_AREA
;
2396 // Writer honours this wrap distance when aligned as "left" or "right",
2397 // Word doesn't. Writer doesn't honour it when its "from left".
2398 if (eHoriOri
== text::HoriOrientation::LEFT
)
2399 pRecord
->nDxWrapDistLeft
=0;
2400 else if (eHoriOri
== text::HoriOrientation::RIGHT
)
2401 pRecord
->nDxWrapDistRight
=0;
2405 eVertRel
= aVertRelOriTab
[ nYRelTo
]; // #i18732#
2406 if ( bCurSectionVertical
&& nYRelTo
== 2 )
2407 eVertRel
= text::RelOrientation::PAGE_PRINT_AREA
;
2408 // #i22673# - fill <eVertOri> in dependence of <eVertRel>
2410 if ( eVertRel
== text::RelOrientation::TEXT_LINE
)
2412 eVertOri
= aToLineVertOriTab
[ nYAlign
];
2416 eVertOri
= aVertOriTab
[ nYAlign
];
2419 // Below line in word is a positive value, while in writer its
2421 tools::Long nYPos
= pFSPA
->nYaTop
;
2423 if ((eVertRel
== text::RelOrientation::TEXT_LINE
) && (eVertOri
== text::VertOrientation::NONE
))
2426 SwFormatHoriOrient
aHoriOri(MakeSafePositioningValue( bCurSectionVertical
? nYPos
: pFSPA
->nXaLeft
),
2427 bCurSectionVertical
? eVertOri
: eHoriOri
,
2428 bCurSectionVertical
? eVertRel
: eHoriRel
);
2430 aHoriOri
.SetPosToggle(true);
2431 rFlySet
.Put( aHoriOri
);
2433 rFlySet
.Put(SwFormatVertOrient(MakeSafePositioningValue( !bCurSectionVertical
? nYPos
: -pFSPA
->nXaRight
),
2434 !bCurSectionVertical
? eVertOri
: eHoriOri
,
2435 !bCurSectionVertical
? eVertRel
: eHoriRel
));
2442 bool SwWW8ImplReader::IsObjectLayoutInTableCell( const sal_uInt32 nLayoutInTableCell
) const
2444 bool bIsObjectLayoutInTableCell
= false;
2448 sal_uInt16 nWWVersion
= m_xWwFib
->m_nProduct
& 0xE000;
2449 if (nWWVersion
== 0)
2451 // 0 nProduct can happen for Word >97 as well, check cswNew in this case instead.
2452 if (m_xWwFib
->m_cswNew
> 0)
2454 // This is Word >=2000.
2455 nWWVersion
= 0x2000;
2459 switch ( nWWVersion
)
2461 case 0x0000: // version 8 aka Microsoft Word 97
2463 bIsObjectLayoutInTableCell
= false;
2464 OSL_ENSURE( nLayoutInTableCell
== 0xFFFFFFFF,
2465 "no explicit object attribute layout in table cell expected." );
2468 case 0x2000: // version 9 aka Microsoft Word 2000
2469 case 0x4000: // version 10 aka Microsoft Word 2002
2470 case 0x6000: // version 11 aka Microsoft Word 2003
2471 case 0x8000: // version 12 aka Microsoft Word 2007
2472 case 0xC000: // version 14 aka Microsoft Word 2010
2473 case 0xE000: // version 15 aka Microsoft Word 2013
2476 // adjustment of conditions needed after deeper analysis of
2477 // certain test cases.
2478 if ( nLayoutInTableCell
== 0xFFFFFFFF || // no explicit attribute value given
2479 nLayoutInTableCell
== 0x80008000 ||
2480 ( nLayoutInTableCell
& 0x02000000 &&
2481 !(nLayoutInTableCell
& 0x80000000 ) ) )
2483 bIsObjectLayoutInTableCell
= true;
2487 // Documented in [MS-ODRAW], 2.3.4.44 "Group Shape Boolean Properties".
2488 bool fUsefLayoutInCell
= (nLayoutInTableCell
& 0x80000000) >> 31;
2489 bool fLayoutInCell
= (nLayoutInTableCell
& 0x8000) >> 15;
2490 bIsObjectLayoutInTableCell
= fUsefLayoutInCell
&& fLayoutInCell
;
2496 OSL_FAIL( "unknown version." );
2501 return bIsObjectLayoutInTableCell
;
2504 SwFrameFormat
* SwWW8ImplReader::Read_GrafLayer( tools::Long nGrafAnchorCp
)
2506 if( m_nIniFlags
& WW8FL_NO_GRAFLAYER
)
2509 ::SetProgressState(m_nProgress
, m_pDocShell
); // Update
2512 m_bDrawCpOValid
= m_xWwFib
->GetBaseCp(m_xPlcxMan
->GetManType() == MAN_HDFT
? MAN_TXBX_HDFT
: MAN_TXBX
, &m_nDrawCpO
);
2516 WW8PLCFspecial
* pPF
= m_xPlcxMan
->GetFdoa();
2519 OSL_ENSURE( false, "Where is the graphic (1) ?" );
2525 tools::Long nOldPos
= m_pStrm
->Tell();
2527 m_nDrawXOfs
= m_nDrawYOfs
= 0;
2528 ReadGrafLayer1( pPF
, nGrafAnchorCp
);
2530 m_pStrm
->Seek( nOldPos
);
2534 // Normal case of Word 8+ version stuff
2535 pPF
->SeekPos( nGrafAnchorCp
);
2539 if( !pPF
->Get( nStartFc
, pF0
) ){
2540 OSL_ENSURE( false, "+Where is the graphic (2) ?" );
2544 WW8_FSPA_SHADOW
* pFS
= static_cast<WW8_FSPA_SHADOW
*>(pF0
);
2548 WW8FSPAShadowToReal( pFS
, pF
);
2551 OSL_ENSURE( false, "+Where is the graphic (3) ?" );
2555 if (!m_xMSDffManager
->GetModel())
2556 m_xMSDffManager
->SetModel(m_pDrawModel
, 1440);
2558 tools::Rectangle
aRect(pF
->nXaLeft
, pF
->nYaTop
, pF
->nXaRight
, pF
->nYaBottom
);
2559 SvxMSDffImportData
aData( aRect
);
2563 The SdrOle2Obj will try and manage any ole objects it finds, causing all
2564 sorts of trouble later on
2566 SwDocShell
* pPersist
= m_rDoc
.GetDocShell();
2567 m_rDoc
.SetDocShell(nullptr); // #i20540# Persist guard
2569 SdrObject
* pObject
= nullptr;
2570 bool bOk
= (m_xMSDffManager
->GetShape(pF
->nSpId
, pObject
, aData
) && pObject
);
2572 m_rDoc
.SetDocShell(pPersist
); // #i20540# Persist guard
2576 OSL_ENSURE( false, "Where is the Shape ?" );
2580 // tdf#118375 Word relates position to the unrotated rectangle,
2581 // Writer uses the rotated one.
2582 if (pObject
->GetRotateAngle())
2584 tools::Rectangle
aObjSnapRect(pObject
->GetSnapRect()); // recalculates the SnapRect
2585 pF
->nXaLeft
= aObjSnapRect
.Left();
2586 pF
->nYaTop
= aObjSnapRect
.Top();
2587 pF
->nXaRight
= aObjSnapRect
.Right();
2588 pF
->nYaBottom
= aObjSnapRect
.Bottom();
2592 SdrObject
* pOurNewObject
= nullptr;
2593 bool bReplaceable
= false;
2595 switch (pObject
->GetObjIdentifier())
2598 bReplaceable
= true;
2602 bReplaceable
= true;
2609 // when in a header or footer word appears to treat all elements as wrap through
2611 // determine wrapping mode
2612 SfxItemSet
aFlySet(m_rDoc
.GetAttrPool(), svl::Items
<RES_FRMATR_BEGIN
, RES_FRMATR_END
-1, XATTR_START
, XATTR_END
>{});
2613 Reader::ResetFrameFormatAttrs(aFlySet
); // tdf#122425: Explicitly remove borders and spacing
2614 css::text::WrapTextMode eSurround
= css::text::WrapTextMode_PARALLEL
;
2615 bool bContour
= false;
2618 case 0: // 0 like 2, but doesn't require absolute object
2619 case 2: // 2 wrap around absolute object
2620 eSurround
= css::text::WrapTextMode_PARALLEL
;
2622 case 1: // 1 no text next to shape
2623 eSurround
= css::text::WrapTextMode_NONE
;
2625 case 3: // 3 wrap as if no object present
2626 eSurround
= css::text::WrapTextMode_THROUGH
;
2628 case 4: // 4 wrap tightly around object
2629 case 5: // 5 wrap tightly, but allow holes
2630 eSurround
= css::text::WrapTextMode_PARALLEL
;
2635 // if mode 2 or 4 also regard the additional parameters
2636 if ( (2 == pF
->nwr
) || (4 == pF
->nwr
) )
2640 // 0 wrap both sides
2642 eSurround
= css::text::WrapTextMode_PARALLEL
;
2644 // 1 wrap only on left
2646 eSurround
= css::text::WrapTextMode_LEFT
;
2648 // 2 wrap only on right
2650 eSurround
= css::text::WrapTextMode_RIGHT
;
2652 // 3 wrap only on largest side
2654 eSurround
= css::text::WrapTextMode_DYNAMIC
;
2659 SwFormatSurround
aSur( eSurround
);
2660 aSur
.SetContour( bContour
);
2661 aSur
.SetOutside(true); // Winword can only do outside contours
2662 aFlySet
.Put( aSur
);
2664 // now position imported object correctly and so on (can be a whole group)
2666 OSL_ENSURE(!((aData
.size() != 1) && bReplaceable
),
2667 "Replaceable drawing with > 1 entries ?");
2669 if (aData
.size() != 1)
2670 bReplaceable
= false;
2673 Get the record for top level object, so we can get the word anchoring
2674 and wrapping information for it.
2676 SvxMSDffImportRec
* pRecord
= aData
.find(pObject
);
2677 OSL_ENSURE(pRecord
, "how did that happen?");
2680 // remove old object from the Z-Order list
2681 m_xMSDffManager
->RemoveFromShapeOrder(pObject
);
2682 // and delete the object
2683 SdrObject::Free(pObject
);
2686 const bool bLayoutInTableCell
=
2687 m_nInTable
&& IsObjectLayoutInTableCell( pRecord
->nLayoutInTableCell
);
2689 // #i18732# - Switch on 'follow text flow', if object is laid out
2690 // inside table cell
2691 if (bLayoutInTableCell
)
2693 SwFormatFollowTextFlow
aFollowTextFlow( true );
2694 aFlySet
.Put( aFollowTextFlow
);
2698 // Some shapes are set to *hidden*, don't import those ones.
2699 if (pRecord
->bHidden
)
2701 // remove old object from the Z-Order list
2702 m_xMSDffManager
->RemoveFromShapeOrder(pObject
);
2703 // and delete the object
2704 SdrObject::Free(pObject
);
2708 sal_uInt16 nCount
= pObject
->GetUserDataCount();
2711 OUString lnName
, aObjName
, aTarFrame
;
2712 for (sal_uInt16 i
= 0; i
< nCount
; i
++ )
2714 SdrObjUserData
* pData
= pObject
->GetUserData( i
);
2715 if( pData
&& pData
->GetInventor() == SdrInventor::ScOrSwDraw
2716 && pData
->GetId() == SW_UD_IMAPDATA
)
2718 SwMacroInfo
* macInf
= dynamic_cast<SwMacroInfo
*>(pData
);
2719 if( macInf
&& macInf
->GetShapeId() == pF
->nSpId
)
2721 lnName
= macInf
->GetHlink();
2722 aObjName
= macInf
->GetName();
2723 aTarFrame
= macInf
->GetTarFrame();
2728 SwFormatURL
* pFormatURL
= new SwFormatURL();
2729 pFormatURL
->SetURL( lnName
, false );
2730 if (!aObjName
.isEmpty())
2731 pFormatURL
->SetName(aObjName
);
2732 if (!aTarFrame
.isEmpty())
2733 pFormatURL
->SetTargetFrameName(aTarFrame
);
2734 pFormatURL
->SetMap(nullptr);
2735 aFlySet
.Put(*pFormatURL
);
2738 // If we are to be "below text" then we are not to be opaque
2739 // #i14045# MM If we are in a header or footer then make the object transparent
2740 // Not exactly like word but close enough for now
2742 // both flags <bBelowText> and <bDrawHell> have to be set to move object into the background.
2743 // #i46794# - it reveals that value of flag <bBelowText> can be neglected.
2744 const bool bMoveToBackgrd
= pRecord
->bDrawHell
||
2745 ( ( m_bIsHeader
|| m_bIsFooter
) && pF
->nwr
== 3 );
2746 if ( bMoveToBackgrd
)
2747 aFlySet
.Put(SvxOpaqueItem(RES_OPAQUE
,false));
2749 OUString aObjName
= pObject
->GetName();
2751 bool bDrawObj
= false;
2752 bool bFrame
= false;
2754 SwFrameFormat
* pRetFrameFormat
= nullptr;
2757 // Single graphics or ole objects
2758 pRetFrameFormat
= ImportReplaceableDrawables(pObject
, pOurNewObject
, pRecord
,
2765 // Drawing objects, (e.g. ovals or drawing groups)
2768 pF
->nbx
= WW8_FSPA::RelPageBorder
;
2769 pF
->nby
= WW8_FSPA::RelPageBorder
;
2772 RndStdIds eAnchor
= ProcessEscherAlign(pRecord
, pF
, aFlySet
);
2774 // Should we, and is it possible to make this into a writer textbox
2775 if ((!(m_nIniFlags1
& WW8FL_NO_FLY_FOR_TXBX
)) && pRecord
->bReplaceByFly
)
2777 pRetFrameFormat
= ConvertDrawTextToFly(pObject
, pOurNewObject
, pRecord
,
2778 eAnchor
, pF
, aFlySet
);
2779 if (pRetFrameFormat
)
2789 sw::util::SetLayer
aSetLayer(m_rDoc
);
2790 if ( bMoveToBackgrd
)
2791 aSetLayer
.SendObjectToHell(*pObject
);
2793 aSetLayer
.SendObjectToHeaven(*pObject
);
2795 if (!IsInlineEscherHack())
2797 /* Need to make sure that the correct layer ordering is applied. */
2798 // pass information, if object is in page header|footer to method.
2799 m_xWWZOrder
->InsertEscherObject( pObject
, pF
->nSpId
,
2800 m_bIsHeader
|| m_bIsFooter
);
2804 m_xWWZOrder
->InsertTextLayerObject(pObject
);
2807 pRetFrameFormat
= m_rDoc
.getIDocumentContentOperations().InsertDrawObj(*m_pPaM
, *pObject
, aFlySet
);
2809 OSL_ENSURE(pRetFrameFormat
->GetAnchor().GetAnchorId() ==
2810 eAnchor
, "Not the anchor type requested!");
2813 Insert text if necessary into textboxes contained in groups.
2815 for (const auto& it
: aData
)
2818 if (pRecord
->pObj
&& pRecord
->aTextId
.nTxBxS
)
2819 { // #i52825# pRetFrameFormat can be NULL
2820 pRetFrameFormat
= MungeTextIntoDrawBox(
2821 pRecord
, nGrafAnchorCp
, pRetFrameFormat
);
2827 SwDrawFrameFormat
* pDrawFrameFormat
= dynamic_cast<SwDrawFrameFormat
*>(pRetFrameFormat
);
2828 // #i44344#, #i44681# - positioning attributes already set
2829 if (pDrawFrameFormat
)
2830 pDrawFrameFormat
->PosAttrSet();
2831 if (!IsInlineEscherHack())
2832 MapWrapIntoFlyFormat(pRecord
, pRetFrameFormat
);
2834 // Set frame name with object name
2835 if (pRetFrameFormat
/*#i52825# */)
2837 if (!aObjName
.isEmpty())
2838 pRetFrameFormat
->SetName( aObjName
);
2839 if (pRetFrameFormat
->GetName().isEmpty())
2842 pRetFrameFormat
->SetName(m_rDoc
.GetUniqueDrawObjectName());
2844 pRetFrameFormat
->SetName(m_rDoc
.GetUniqueFrameName());
2847 return AddAutoAnchor(pRetFrameFormat
);
2850 SwFrameFormat
*SwWW8ImplReader::AddAutoAnchor(SwFrameFormat
*pFormat
)
2853 * anchored to character at the current position will move along the
2854 * paragraph as text is added because we are at the insertion point.
2856 * Leave to later and set the correct location then.
2858 if (pFormat
&& (pFormat
->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR
))
2860 m_xAnchorStck
->AddAnchor(*m_pPaM
->GetPoint(), pFormat
);
2865 SwFrameFormat
* SwWW8ImplReader::MungeTextIntoDrawBox(SvxMSDffImportRec
*pRecord
,
2866 tools::Long nGrafAnchorCp
, SwFrameFormat
* pRetFrameFormat
)
2868 SdrObject
* pTrueObject
= pRecord
->pObj
;
2870 SdrTextObj
* pSdrTextObj
;
2872 // check for group object (e.g. two parentheses)
2873 if (SdrObjGroup
* pThisGroup
= dynamic_cast<SdrObjGroup
*>( pRecord
->pObj
) )
2875 // Group objects don't have text. Insert a text object into
2876 // the group for holding the text.
2877 pSdrTextObj
= new SdrRectObj(
2880 pThisGroup
->GetCurrentBoundRect());
2882 SfxItemSet
aSet(m_pDrawModel
->GetItemPool());
2883 aSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
2884 aSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
2885 aSet
.Put(SdrTextFitToSizeTypeItem( drawing::TextFitToSizeType_NONE
));
2886 aSet
.Put(makeSdrTextAutoGrowHeightItem(false));
2887 aSet
.Put(makeSdrTextAutoGrowWidthItem(false));
2888 pSdrTextObj
->SetMergedItemSet(aSet
);
2889 pSdrTextObj
->NbcSetLayer( pThisGroup
->GetLayer() );
2890 pThisGroup
->GetSubList()->NbcInsertObject(pSdrTextObj
);
2893 pSdrTextObj
= dynamic_cast<SdrTextObj
*>( pRecord
->pObj
);
2897 Size
aObjSize(pSdrTextObj
->GetSnapRect().GetWidth(),
2898 pSdrTextObj
->GetSnapRect().GetHeight());
2900 // Object is part of a group?
2901 SdrObject
* pGroupObject
= pSdrTextObj
->getParentSdrObjectFromSdrObject();
2903 const size_t nOrdNum
= pSdrTextObj
->GetOrdNum();
2904 bool bEraseThisObject
;
2905 InsertTxbxText( pSdrTextObj
, &aObjSize
, pRecord
->aTextId
.nTxBxS
,
2906 pRecord
->aTextId
.nSequence
, nGrafAnchorCp
, pRetFrameFormat
,
2907 (pSdrTextObj
!= pTrueObject
) || (nullptr != pGroupObject
),
2908 bEraseThisObject
, nullptr, nullptr, nullptr, nullptr, pRecord
);
2910 // was this object replaced ??
2911 if (bEraseThisObject
)
2913 if( pGroupObject
|| (pSdrTextObj
!= pTrueObject
) )
2915 // Object is already replaced by a new SdrGrafObj (in the group
2916 // and) the Drawing-Page.
2918 SdrObject
* pNewObj
= pGroupObject
?
2919 pGroupObject
->GetSubList()->GetObj(nOrdNum
) : pTrueObject
;
2920 if (pSdrTextObj
!= pNewObj
)
2922 // Replace object in the Z-Order-List
2923 m_xMSDffManager
->ExchangeInShapeOrder(pSdrTextObj
, 0, pNewObj
);
2924 // now delete object
2925 SdrObject::Free( pRecord
->pObj
);
2926 // and save the new object.
2927 pRecord
->pObj
= pNewObj
;
2932 // remove the object from Z-Order list
2933 m_xMSDffManager
->RemoveFromShapeOrder( pSdrTextObj
);
2934 // take the object from the drawing page
2935 if( pSdrTextObj
->getSdrPageFromSdrObject() )
2936 m_pDrawPg
->RemoveObject( pSdrTextObj
->GetOrdNum() );
2937 // and delete FrameFormat, because replaced by graphic
2938 // (this also deletes the object)
2939 m_rDoc
.DelFrameFormat( pRetFrameFormat
);
2940 pRetFrameFormat
= nullptr;
2941 // also delete the object record
2942 pRecord
->pObj
= nullptr;
2947 // use ww8-default border distance
2948 SfxItemSet
aItemSet(m_pDrawModel
->GetItemPool(),
2949 svl::Items
<SDRATTR_TEXT_LEFTDIST
, SDRATTR_TEXT_LOWERDIST
>{});
2950 aItemSet
.Put( makeSdrTextLeftDistItem( pRecord
->nDxTextLeft
) );
2951 aItemSet
.Put( makeSdrTextRightDistItem( pRecord
->nDxTextRight
) );
2952 aItemSet
.Put( makeSdrTextUpperDistItem( pRecord
->nDyTextTop
) );
2953 aItemSet
.Put( makeSdrTextLowerDistItem( pRecord
->nDyTextBottom
) );
2954 pSdrTextObj
->SetMergedItemSetAndBroadcast(aItemSet
);
2957 return pRetFrameFormat
;
2960 SwFlyFrameFormat
* SwWW8ImplReader::ConvertDrawTextToFly(SdrObject
* &rpObject
,
2961 SdrObject
* &rpOurNewObject
, SvxMSDffImportRec
const * pRecord
, RndStdIds eAnchor
,
2962 WW8_FSPA
const *pF
, SfxItemSet
&rFlySet
)
2964 SwFlyFrameFormat
* pRetFrameFormat
= nullptr;
2965 tools::Long nStartCp
;
2968 // Check if this textbox chain contains text as conversion of an empty
2969 // chain would not make sense.
2970 if ( TxbxChainContainsRealText(pRecord
->aTextId
.nTxBxS
,nStartCp
,nEndCp
) )
2972 // The Text is not read into SdrTextObj! Rather insert a frame and
2973 // insert the text from nStartCp to nEndCp.
2975 // More attributes can be used in a frame compared to the
2976 // Edit-Engine, and it can contain field, OLEs or graphics...
2977 tools::Rectangle
aInnerDist(pRecord
->nDxTextLeft
, pRecord
->nDyTextTop
,
2978 pRecord
->nDxTextRight
, pRecord
->nDyTextBottom
);
2980 SwFormatFrameSize
aFrameSize(SwFrameSize::Fixed
, pF
->nXaRight
- pF
->nXaLeft
, pF
->nYaBottom
- pF
->nYaTop
);
2981 aFrameSize
.SetWidthSizeType(pRecord
->bAutoWidth
? SwFrameSize::Variable
: SwFrameSize::Fixed
);
2982 rFlySet
.Put(aFrameSize
);
2984 MatchSdrItemsIntoFlySet( rpObject
, rFlySet
, pRecord
->eLineStyle
,
2985 pRecord
->eLineDashing
, pRecord
->eShapeType
, aInnerDist
);
2987 SdrTextObj
*pSdrTextObj
= dynamic_cast<SdrTextObj
*>(rpObject
);
2988 if (pSdrTextObj
&& pSdrTextObj
->IsVerticalWriting())
2989 rFlySet
.Put(SvxFrameDirectionItem(SvxFrameDirection::Vertical_RL_TB
, RES_FRAMEDIR
));
2991 pRetFrameFormat
= m_rDoc
.MakeFlySection(eAnchor
, m_pPaM
->GetPoint(), &rFlySet
);
2992 OSL_ENSURE(pRetFrameFormat
->GetAnchor().GetAnchorId() == eAnchor
,
2993 "Not the anchor type requested!");
2995 // if everything is OK, find pointer on new object and correct
2996 // Z-order list (or delete entry)
2997 rpOurNewObject
= CreateContactObject(pRetFrameFormat
);
2999 // remove old object from the Z-Order list
3000 m_xMSDffManager
->RemoveFromShapeOrder( rpObject
);
3002 // and delete the object
3003 SdrObject::Free( rpObject
);
3005 NB: only query pOrgShapeObject starting here!
3011 We do not store our rpOutNewObject in the ShapeOrder because we
3012 have a FrameFormat from which we can regenerate the contact object when
3013 we need it. Because, we can have frames anchored to paragraphs in
3014 header/footers and we can copy header/footers, if we do copy a
3015 header/footer with a nonpage anchored frame in it then the contact
3016 objects are invalidated. Under this condition the FrameFormat will be
3017 updated to reflect this change and can be used to get a new
3018 contact object, while a raw rpOutNewObject stored here becomes
3019 deleted and useless.
3021 m_xMSDffManager
->StoreShapeOrder(pF
->nSpId
,
3022 (static_cast<sal_uLong
>(pRecord
->aTextId
.nTxBxS
) << 16) +
3023 pRecord
->aTextId
.nSequence
, nullptr, pRetFrameFormat
);
3025 // The Contact object has to be inserted into the draw page, so
3026 // SwWW8ImplReader::LoadDoc1() can determine the z-order.
3027 if (!rpOurNewObject
->IsInserted())
3029 // pass information, if object is in page header|footer to method.
3030 m_xWWZOrder
->InsertEscherObject( rpOurNewObject
, pF
->nSpId
,
3031 m_bIsHeader
|| m_bIsFooter
);
3035 // Box-0 receives the text for the whole chain!
3036 if( !pRecord
->aTextId
.nSequence
)
3038 // save flags etc and reset them
3039 WW8ReaderSave
aSave( this );
3041 MoveInsideFly(pRetFrameFormat
);
3043 m_xWWZOrder
->InsideEscher(pF
->nSpId
);
3046 m_bTxbxFlySection
= true;
3047 bool bJoined
= ReadText(nStartCp
, (nEndCp
-nStartCp
),
3048 MAN_MAINTEXT
== m_xPlcxMan
->GetManType() ?
3049 MAN_TXBX
: MAN_TXBX_HDFT
);
3051 m_xWWZOrder
->OutsideEscher();
3053 MoveOutsideFly(pRetFrameFormat
, aSave
.GetStartPos(),!bJoined
);
3055 aSave
.Restore( this );
3057 StripNegativeAfterIndent(pRetFrameFormat
);
3061 return pRetFrameFormat
;
3064 void MatchEscherMirrorIntoFlySet(const SvxMSDffImportRec
&rRecord
,
3065 SfxItemSet
&rFlySet
)
3067 if (rRecord
.bVFlip
|| rRecord
.bHFlip
)
3069 MirrorGraph
eType(MirrorGraph::Dont
);
3070 if (rRecord
.bVFlip
&& rRecord
.bHFlip
)
3071 eType
= MirrorGraph::Both
;
3072 else if (rRecord
.bVFlip
)
3073 eType
= MirrorGraph::Horizontal
;
3075 eType
= MirrorGraph::Vertical
;
3076 rFlySet
.Put( SwMirrorGrf(eType
) );
3080 SwFlyFrameFormat
* SwWW8ImplReader::ImportReplaceableDrawables( SdrObject
* &rpObject
,
3081 SdrObject
* &rpOurNewObject
, SvxMSDffImportRec
* pRecord
, WW8_FSPA
*pF
,
3082 SfxItemSet
&rFlySet
)
3084 SwFlyFrameFormat
* pRetFrameFormat
= nullptr;
3085 sal_Int32 nWidthTw
= o3tl::saturating_sub(pF
->nXaRight
, pF
->nXaLeft
);
3088 sal_Int32 nHeightTw
= o3tl::saturating_sub(pF
->nYaBottom
, pF
->nYaTop
);
3092 ProcessEscherAlign(pRecord
, pF
, rFlySet
);
3094 rFlySet
.Put(SwFormatFrameSize(SwFrameSize::Fixed
, nWidthTw
, nHeightTw
));
3096 SfxItemSet
aGrSet(m_rDoc
.GetAttrPool(), svl::Items
<RES_GRFATR_BEGIN
, RES_GRFATR_END
-1>{});
3100 // Note that the escher inner distance only seems to be honoured in
3101 // word for textboxes, not for graphics and ole objects.
3102 tools::Rectangle
aInnerDist(0, 0, 0, 0);
3104 MatchSdrItemsIntoFlySet(rpObject
, rFlySet
, pRecord
->eLineStyle
,
3105 pRecord
->eLineDashing
, pRecord
->eShapeType
, aInnerDist
);
3107 MatchEscherMirrorIntoFlySet(*pRecord
, aGrSet
);
3110 OUString
aObjectName(rpObject
->GetName());
3111 if (OBJ_OLE2
== rpObject
->GetObjIdentifier())
3112 pRetFrameFormat
= InsertOle(*static_cast<SdrOle2Obj
*>(rpObject
), rFlySet
, &aGrSet
);
3115 const SdrGrafObj
*pGrf
= static_cast<const SdrGrafObj
*>(rpObject
);
3117 if (pGrf
->IsLinkedGraphic() && !pGrf
->GetFileName().isEmpty())
3119 GraphicType eType
= pGrf
->GetGraphicType();
3121 URIHelper::SmartRel2Abs(
3122 INetURLObject(m_sBaseURL
), pGrf
->GetFileName(),
3123 URIHelper::GetMaybeFileHdl()));
3124 // correction of fix for issue #i10939#:
3125 // One of the two conditions have to be true to insert the graphic
3126 // as a linked graphic -
3127 if (GraphicType::NONE
== eType
|| CanUseRemoteLink(aGrfName
))
3129 pRetFrameFormat
= m_rDoc
.getIDocumentContentOperations().InsertGraphic(
3130 *m_pPaM
, aGrfName
, OUString(), nullptr,
3131 &rFlySet
, &aGrSet
, nullptr);
3137 const Graphic
& rGraph
= pGrf
->GetGraphic();
3138 pRetFrameFormat
= m_rDoc
.getIDocumentContentOperations().InsertGraphic(
3139 *m_pPaM
, OUString(), OUString(), &rGraph
,
3140 &rFlySet
, &aGrSet
, nullptr);
3144 if (pRetFrameFormat
)
3148 if( OBJ_OLE2
!= rpObject
->GetObjIdentifier() )
3149 SetAttributesAtGrfNode( pRecord
, pRetFrameFormat
, pF
);
3151 // avoid multiple occurrences of the same graphic name
3152 m_aGrfNameGenerator
.SetUniqueGraphName(pRetFrameFormat
, aObjectName
);
3154 // if everything is OK, determine pointer to new object and correct
3155 // Z-Order-List accordingly (or delete entry)
3156 rpOurNewObject
= CreateContactObject(pRetFrameFormat
);
3158 // remove old object from Z-Order-List
3159 m_xMSDffManager
->RemoveFromShapeOrder( rpObject
);
3160 // remove from Drawing-Page
3161 if( rpObject
->getSdrPageFromSdrObject() )
3162 m_pDrawPg
->RemoveObject( rpObject
->GetOrdNum() );
3164 // and delete the object
3165 SdrObject::Free( rpObject
);
3167 Warning: from now on query only pOrgShapeObject!
3170 // add Contact-Object to the Z-Order-List and the page
3173 if (!m_bHdFtFootnoteEdn
)
3174 m_xMSDffManager
->StoreShapeOrder(pF
->nSpId
, 0, rpOurNewObject
);
3176 // The Contact-Object MUST be set in the Draw-Page, so that in
3177 // SwWW8ImplReader::LoadDoc1() the Z-Order can be defined !!!
3178 if (!rpOurNewObject
->IsInserted())
3180 // pass information, if object is in page header|footer to method.
3181 m_xWWZOrder
->InsertEscherObject( rpOurNewObject
, pF
->nSpId
,
3182 m_bIsHeader
|| m_bIsFooter
);
3185 return pRetFrameFormat
;
3188 void SwWW8ImplReader::GrafikCtor() // For SVDraw and VCControls and Escher
3193 m_rDoc
.getIDocumentDrawModelAccess().GetOrCreateDrawModel(); // #i52858# - method name changed
3194 m_pDrawModel
= m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel();
3195 OSL_ENSURE(m_pDrawModel
, "Cannot create DrawModel");
3196 m_pDrawPg
= m_pDrawModel
->GetPage(0);
3198 m_xMSDffManager
.reset(new SwMSDffManager(*this, m_bSkipImages
));
3199 m_xMSDffManager
->SetModel(m_pDrawModel
, 1440);
3201 Now the dff manager always needs a controls converter as well, but a
3202 control converter may still exist without a dffmanager.
3204 m_xFormImpl
.reset(new SwMSConvertControls(m_pDocShell
, m_pPaM
));
3206 m_xWWZOrder
.reset(new wwZOrderer(sw::util::SetLayer(m_rDoc
), m_pDrawPg
,
3207 m_xMSDffManager
->GetShapeOrders()));
3210 void SwWW8ImplReader::GrafikDtor()
3212 m_pDrawEditEngine
.reset(); // maybe created by graphic
3213 m_xWWZOrder
.reset(); // same
3216 void SwWW8FltAnchorStack::AddAnchor(const SwPosition
& rPos
, SwFrameFormat
*pFormat
)
3218 OSL_ENSURE(pFormat
->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR
,
3219 "Don't use fltanchors with inline frames, slap!");
3220 NewAttr(rPos
, SwFltAnchor(pFormat
));
3223 void SwWW8FltAnchorStack::Flush()
3225 size_t nCnt
= size();
3226 for (size_t i
=0; i
< nCnt
; ++i
)
3228 SwFltStackEntry
&rEntry
= (*this)[i
];
3229 SwPosition
aDummy(rEntry
.m_aMkPos
.m_nNode
);
3230 SetAttrInDoc(aDummy
, rEntry
);
3231 DeleteAndDestroy(i
--);
3236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */