1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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 <svx/fmglob.hxx>
26 #include <svx/sdtaitm.hxx>
27 #include <editeng/lrspitem.hxx>
28 #include <editeng/udlnitem.hxx>
29 #include <svx/xfillit0.hxx>
30 #include <svx/xlineit0.hxx>
31 #include <svx/xlnclit.hxx>
32 #include <svx/xlnwtit.hxx>
33 #include <svx/xlndsit.hxx>
34 #include <svx/xlnstit.hxx>
35 #include <svx/xlnedit.hxx>
36 #include <svx/xlnstwit.hxx>
37 #include <svx/xlnedwit.hxx>
38 #include <svx/xlnstcit.hxx>
39 #include <svx/xlnedcit.hxx>
40 #include <svx/xflclit.hxx>
41 #include <svx/xbtmpit.hxx>
42 #include <svx/svdmodel.hxx>
43 #include <svx/svdocapt.hxx>
44 #include <svx/sxctitm.hxx>
45 #include <svx/sdggaitm.hxx>
46 #include <svx/sdgluitm.hxx>
47 #include <svx/sdgmoitm.hxx>
48 #include <svx/sdmetitm.hxx>
49 #include <svx/sdooitm.hxx>
50 #include <svx/sdshitm.hxx>
51 #include <svx/sdsxyitm.hxx>
52 #include <svx/sdtagitm.hxx>
53 #include <svx/sdtditm.hxx>
54 #include <svx/sdtfsitm.hxx>
55 #include <editeng/editeng.hxx>
56 #include <svx/svdpage.hxx>
57 #include <svx/svdopath.hxx>
58 #include <svx/svdocirc.hxx>
59 #include <editeng/outlobj.hxx>
60 #include <svx/svdogrp.hxx>
61 #include <svx/svdograf.hxx>
62 #include <svx/svdoole2.hxx>
63 #include <editeng/colritem.hxx>
64 #include <editeng/fhgtitem.hxx>
65 #include <editeng/postitem.hxx>
66 #include <editeng/adjustitem.hxx>
67 #include <editeng/wghtitem.hxx>
68 #include <editeng/crossedoutitem.hxx>
69 #include <editeng/contouritem.hxx>
70 #include <editeng/shdditem.hxx>
71 #include <editeng/fontitem.hxx>
72 #include <editeng/ulspitem.hxx>
73 #include <svx/svdoattr.hxx>
74 #include <editeng/brushitem.hxx>
75 #include <svx/rectenum.hxx>
76 #include <editeng/opaqitem.hxx>
77 #include <editeng/shaditem.hxx>
78 #include <editeng/boxitem.hxx>
79 #include <editeng/outliner.hxx>
80 #include <editeng/frmdiritem.hxx>
81 #include <svx/xfltrit.hxx>
82 #include <filter/msfilter/msdffimp.hxx>
83 #include <grfatr.hxx>
84 #include <fmtornt.hxx>
85 #include <fmtcntnt.hxx>
86 #include <frmfmt.hxx>
87 #include <fmtanchr.hxx>
88 #include <pam.hxx>
89 #include <doc.hxx>
90 #include <drawdoc.hxx>
91 #include <IDocumentDrawModelAccess.hxx>
92 #include <docary.hxx>
93 #include <ndgrf.hxx>
94 #include <ndtxt.hxx>
95 #include <dcontact.hxx>
96 #include <docsh.hxx>
97 #include <mdiexp.hxx>
98 #include <fmtcnct.hxx>
99 #include "ww8struc.hxx"
100 #include "ww8scan.hxx"
101 #include "ww8par.hxx"
102 #include "ww8par2.hxx"
103 #include "ww8graf.hxx"
104 #include <fmtinfmt.hxx>
105 #include <editeng/eeitem.hxx>
106 #include <editeng/flditem.hxx>
107 #include <fmtfollowtextflow.hxx>
108 #include "writerhelper.hxx"
109 #include "writerwordglue.hxx"
110 #include <basegfx/point/b2dpoint.hxx>
111 #include <basegfx/polygon/b2dpolygon.hxx>
112 #include <editeng/editobj.hxx>
113 #include <math.h>
114 #include <fmturl.hxx>
115 #include <svx/hlnkitem.hxx>
116 #include <svl/whiter.hxx>
117 #include <o3tl/enumrange.hxx>
118 #include <o3tl/safeint.hxx>
119 #include <memory>
120 #include <filter/msfilter/escherex.hxx>
121 #include "sprmids.hxx"
122
123 using ::editeng::SvxBorderLine;
124 using namespace ::com::sun::star;
125 using namespace sw::types;
126 using namespace sw::util;
127
128 // helper methods
WW8TransCol(SVBT32 nWC)129 static Color WW8TransCol(SVBT32 nWC)
130 {
131 #if 1 // 1 = use predefined color, 0 = ignore
132
133 // color table to convert RGB values to pre-defined colors
134 // (to make the writer UI show the right color names)
135 // the table is split in base 3, the greys are missing as
136 // they don't fit into that system (4 values: bw, wb, 2 * grey)
137 static const Color eColA[] = { // B G R B G R B G R
138 COL_BLACK, COL_RED, COL_LIGHTRED, // 0 0 0, 0 0 1, 0 0 2
139 COL_GREEN, COL_BROWN, COL_BLACK, // 0 1 0, 0 1 1, 0 1 2
140 COL_LIGHTGREEN, COL_BLACK, COL_YELLOW, // 0 2 0, 0 2 1, 0 2 2
141 COL_BLUE, COL_MAGENTA, COL_BLACK, // 1 0 0, 1 0 1, 1 0 2
142 COL_CYAN, COL_LIGHTGRAY, COL_BLACK, // 1 1 0, 1 1 1, 1 1 2
143 COL_BLACK, COL_BLACK, COL_BLACK, // 1 2 0, 1 2 1, 1 2 2
144 COL_LIGHTBLUE, COL_BLACK, COL_LIGHTMAGENTA, // 2 0 0, 2 0 1, 2 0 2
145 COL_BLACK, COL_BLACK, COL_BLACK, // 2 1 0, 2 1 1, 2 1 2
146 COL_LIGHTCYAN, COL_BLACK, COL_WHITE }; // 2 2 0, 2 2 1, 2 2 2
147
148 // In nWC[3] is a byte that's not described in the WW documentation.
149 // Its meaning appears to be the following: For 0, it's a normal color
150 // whose RGB values are in nWC[0..2]. If nWC[3] is 0x1, 0x7d or 0x83,
151 // it's a grey value whose black portion is given in 0.5% in nWC[0].
152 // I guess that BIT(0) in nWC[3] is relevant for distinguishing RGB/Grey.
153
154 if( !( nWC[3] & 0x1 ) && // not special (grey)
155 ( ( nWC[0] == 0 || nWC[0]== 0x80 || nWC[0] == 0xff ) // R
156 && ( nWC[1] == 0 || nWC[1]== 0x80 || nWC[1] == 0xff ) // G
157 && ( nWC[2] == 0 || nWC[2]== 0x80 || nWC[2] == 0xff ) ) ){// B
158 int nIdx = 0; // and now: Idx-calculation in base 3
159 for (int i = 2; i >= 0; i--)
160 {
161 nIdx *= 3;
162 if (nWC[i])
163 nIdx += ((nWC[i] == 0xff) ? 2 : 1);
164 }
165 if (eColA[nIdx] != COL_BLACK)
166 return eColA[nIdx]; // default color
167 }
168 #endif
169
170 if (nWC[3] & 0x1)
171 {
172 // Special color gray
173 sal_uInt8 u = static_cast<sal_uInt8>( static_cast<sal_uLong>( 200 - nWC[0] ) * 256 / 200 );
174 return Color(u, u, u);
175 }
176
177 // User-Color
178 return Color(nWC[0], nWC[1], nWC[2]);
179 }
180
SetUniqueGraphName(SwFrameFormat * pFrameFormat,const OUString & rFixed)181 void wwFrameNamer::SetUniqueGraphName(SwFrameFormat *pFrameFormat, const OUString &rFixed)
182 {
183 if (mbIsDisabled || rFixed.isEmpty())
184 return;
185
186 pFrameFormat->SetName(msSeed+OUString::number(++mnImportedGraphicsCount) + ": " + rFixed);
187 }
188
189 // ReadGrafStart reads object data and if necessary creates an anchor
ReadGrafStart(void * pData,short nDataSiz,WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)190 bool SwWW8ImplReader::ReadGrafStart(void* pData, short nDataSiz,
191 WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
192 {
193 if (SVBT16ToUInt16(pHd->cb) < sizeof(WW8_DPHEAD) + nDataSiz)
194 {
195 OSL_ENSURE( false, "+graphic element: too short?" );
196 m_pStrm->SeekRel(SVBT16ToUInt16(pHd->cb) - sizeof(WW8_DPHEAD));
197 return false;
198 }
199
200 bool bCouldRead = checkRead(*m_pStrm, pData, nDataSiz);
201 OSL_ENSURE(bCouldRead, "Short Graphic header");
202 if (!bCouldRead)
203 return false;
204
205 SwFormatAnchor aAnchor( RndStdIds::FLY_AT_CHAR );
206 aAnchor.SetAnchor( m_pPaM->GetPoint() );
207 rSet.Put( aAnchor );
208
209 m_nDrawXOfs2 = m_nDrawXOfs;
210 m_nDrawYOfs2 = m_nDrawYOfs;
211
212 return true;
213 }
214
215 // SetStdAttr() sets standard attributes
SetStdAttr(SfxItemSet & rSet,WW8_DP_LINETYPE & rL,WW8_DP_SHADOW const & rSh)216 static void SetStdAttr( SfxItemSet& rSet, WW8_DP_LINETYPE& rL,
217 WW8_DP_SHADOW const & rSh )
218 {
219 if( SVBT16ToUInt16( rL.lnps ) == 5 ){ // invisible
220 rSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
221 }else{ // visible
222 Color aCol( WW8TransCol( rL.lnpc ) ); // line color
223 rSet.Put( XLineColorItem( OUString(), aCol ) );
224 rSet.Put( XLineWidthItem( SVBT16ToUInt16( rL.lnpw ) ) );
225 // line thickness
226 if( SVBT16ToUInt16( rL.lnps ) >= 1
227 && SVBT16ToUInt16(rL.lnps ) <= 4 ){ // line style
228 rSet.Put( XLineStyleItem( drawing::LineStyle_DASH ) );
229 sal_Int16 nLen = SVBT16ToUInt16( rL.lnpw );
230 XDash aD( css::drawing::DashStyle_RECT, 1, 2 * nLen, 1, 5 * nLen, 5 * nLen );
231 switch( SVBT16ToUInt16( rL.lnps ) ){
232 case 1: aD.SetDots( 0 ); // Dash
233 aD.SetDashLen( 6 * nLen );
234 aD.SetDistance( 4 * nLen );
235 break;
236 case 2: aD.SetDashes( 0 ); break; // Dot
237 case 3: break; // Dash Dot
238 case 4: aD.SetDots( 2 ); break; // Dash Dot Dot
239 }
240 rSet.Put( XLineDashItem( OUString(), aD ) );
241 }else{
242 rSet.Put( XLineStyleItem( drawing::LineStyle_SOLID ) ); // needed for TextBox
243 }
244 }
245 if( SVBT16ToUInt16( rSh.shdwpi ) ){ // shadow
246 rSet.Put(makeSdrShadowItem(true));
247 rSet.Put( makeSdrShadowXDistItem( SVBT16ToUInt16( rSh.xaOffset ) ) );
248 rSet.Put( makeSdrShadowYDistItem( SVBT16ToUInt16( rSh.yaOffset ) ) );
249 }
250 }
251
252 // SetFill() sets fill attributes such as fore- and background color and
253 // pattern by reducing to a color
254 // SetFill() doesn't yet set a pattern, because Sdr can't easily do that
255 // and the Sdr hatching (XDash) isn't finished yet.
256 // Instead, a mixed color will be picked that's between the selected ones.
SetFill(SfxItemSet & rSet,WW8_DP_FILL & rFill)257 static void SetFill( SfxItemSet& rSet, WW8_DP_FILL& rFill )
258 {
259 static const sal_uInt8 nPatA[] =
260 {
261 0, 0, 5, 10, 20, 25, 30, 40, 50, 60, 70, 75, 80,
262 90, 50, 50, 50, 50, 50, 50, 33, 33, 33, 33, 33, 33
263 };
264 sal_uInt16 nPat = SVBT16ToUInt16(rFill.flpp);
265
266 if (nPat == 0) // transparent
267 rSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
268 else
269 {
270 rSet.Put(XFillStyleItem(drawing::FillStyle_SOLID)); // necessary for textbox
271 if (nPat <= 1 || (SAL_N_ELEMENTS(nPatA) <= nPat))
272 {
273 // Solid background or unknown
274 rSet.Put(XFillColorItem(OUString(), WW8TransCol(rFill.dlpcBg)));
275 }
276 else
277 { // Brush -> color mix
278 Color aB( WW8TransCol( rFill.dlpcBg ) );
279 Color aF( WW8TransCol( rFill.dlpcFg ) );
280 aB.SetRed( static_cast<sal_uInt8>( ( static_cast<sal_uLong>(aF.GetRed()) * nPatA[nPat]
281 + static_cast<sal_uLong>(aB.GetRed()) * ( 100 - nPatA[nPat] ) ) / 100 ) );
282 aB.SetGreen( static_cast<sal_uInt8>( ( static_cast<sal_uLong>(aF.GetGreen()) * nPatA[nPat]
283 + static_cast<sal_uLong>(aB.GetGreen()) * ( 100 - nPatA[nPat] ) ) / 100 ) );
284 aB.SetBlue( static_cast<sal_uInt8>( ( static_cast<sal_uLong>(aF.GetBlue()) * nPatA[nPat]
285 + static_cast<sal_uLong>(aB.GetBlue()) * ( 100 - nPatA[nPat] ) ) / 100 ) );
286 rSet.Put( XFillColorItem( OUString(), aB ) );
287 }
288 }
289 }
290
SetLineEndAttr(SfxItemSet & rSet,WW8_DP_LINEEND const & rLe,WW8_DP_LINETYPE const & rLt)291 static void SetLineEndAttr( SfxItemSet& rSet, WW8_DP_LINEEND const & rLe,
292 WW8_DP_LINETYPE const & rLt )
293 {
294 sal_uInt16 aSB = SVBT16ToUInt16( rLe.aStartBits );
295 if( aSB & 0x3 )
296 {
297 ::basegfx::B2DPolygon aPolygon;
298 aPolygon.append(::basegfx::B2DPoint(0.0, 330.0));
299 aPolygon.append(::basegfx::B2DPoint(100.0, 0.0));
300 aPolygon.append(::basegfx::B2DPoint(200.0, 330.0));
301 aPolygon.setClosed(true);
302 rSet.Put( XLineEndItem( OUString(), ::basegfx::B2DPolyPolygon(aPolygon) ) );
303 sal_uInt16 nSiz = SVBT16ToUInt16( rLt.lnpw )
304 * ( ( aSB >> 2 & 0x3 ) + ( aSB >> 4 & 0x3 ) );
305 if( nSiz < 220 ) nSiz = 220;
306 rSet.Put(XLineEndWidthItem(nSiz));
307 rSet.Put(XLineEndCenterItem(false));
308 }
309
310 sal_uInt16 aEB = SVBT16ToUInt16( rLe.aEndBits );
311 if( aEB & 0x3 ){
312 ::basegfx::B2DPolygon aPolygon;
313 aPolygon.append(::basegfx::B2DPoint(0.0, 330.0));
314 aPolygon.append(::basegfx::B2DPoint(100.0, 0.0));
315 aPolygon.append(::basegfx::B2DPoint(200.0, 330.0));
316 aPolygon.setClosed(true);
317 rSet.Put( XLineStartItem( OUString(), ::basegfx::B2DPolyPolygon(aPolygon) ) );
318 sal_uInt16 nSiz = SVBT16ToUInt16( rLt.lnpw )
319 * ( ( aEB >> 2 & 0x3 ) + ( aEB >> 4 & 0x3 ) );
320 if( nSiz < 220 ) nSiz = 220;
321 rSet.Put(XLineStartWidthItem(nSiz));
322 rSet.Put(XLineStartCenterItem(false));
323 }
324 }
325
326 // start of routines for the different objects
ReadLine(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)327 SdrObject* SwWW8ImplReader::ReadLine(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
328 {
329 WW8_DP_LINE aLine;
330
331 if( !ReadGrafStart( static_cast<void*>(&aLine), sizeof( aLine ), pHd, rSet ) )
332 return nullptr;
333
334 Point aP[2];
335 {
336 Point& rP0 = aP[0];
337 Point& rP1 = aP[1];
338
339 rP0.setX( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa )) + m_nDrawXOfs2 );
340 rP0.setY( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya )) + m_nDrawYOfs2 );
341 rP1 = rP0;
342 rP0.AdjustX(static_cast<sal_Int16>(SVBT16ToUInt16( aLine.xaStart )) );
343 rP0.AdjustY(static_cast<sal_Int16>(SVBT16ToUInt16( aLine.yaStart )) );
344 rP1.AdjustX(static_cast<sal_Int16>(SVBT16ToUInt16( aLine.xaEnd )) );
345 rP1.AdjustY(static_cast<sal_Int16>(SVBT16ToUInt16( aLine.yaEnd )) );
346 }
347
348 ::basegfx::B2DPolygon aPolygon;
349 aPolygon.append(::basegfx::B2DPoint(aP[0].X(), aP[0].Y()));
350 aPolygon.append(::basegfx::B2DPoint(aP[1].X(), aP[1].Y()));
351 SdrObject* pObj = new SdrPathObj(
352 *m_pDrawModel,
353 OBJ_LINE,
354 ::basegfx::B2DPolyPolygon(aPolygon));
355
356 SetStdAttr( rSet, aLine.aLnt, aLine.aShd );
357 SetLineEndAttr( rSet, aLine.aEpp, aLine.aLnt );
358
359 return pObj;
360 }
361
ReadRect(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)362 SdrObject* SwWW8ImplReader::ReadRect(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
363 {
364 WW8_DP_RECT aRect;
365
366 if( !ReadGrafStart( static_cast<void*>(&aRect), sizeof( aRect ), pHd, rSet ) )
367 return nullptr;
368
369 Point aP0( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa )) + m_nDrawXOfs2,
370 static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya )) + m_nDrawYOfs2 );
371 Point aP1( aP0 );
372 aP1.AdjustX(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dxa )) );
373 aP1.AdjustY(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dya )) );
374
375 SdrObject* pObj = new SdrRectObj(
376 *m_pDrawModel,
377 tools::Rectangle(aP0, aP1));
378
379 SetStdAttr( rSet, aRect.aLnt, aRect.aShd );
380 SetFill( rSet, aRect.aFill );
381
382 return pObj;
383 }
384
ReadElipse(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)385 SdrObject* SwWW8ImplReader::ReadElipse(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
386 {
387 WW8_DP_ELIPSE aElipse;
388
389 if( !ReadGrafStart( static_cast<void*>(&aElipse), sizeof( aElipse ), pHd, rSet ) )
390 return nullptr;
391
392 Point aP0( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa )) + m_nDrawXOfs2,
393 static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya )) + m_nDrawYOfs2 );
394 Point aP1( aP0 );
395 aP1.AdjustX(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dxa )) );
396 aP1.AdjustY(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dya )) );
397
398 SdrObject* pObj = new SdrCircObj(
399 *m_pDrawModel,
400 SdrCircKind::Full,
401 tools::Rectangle(aP0, aP1));
402
403 SetStdAttr( rSet, aElipse.aLnt, aElipse.aShd );
404 SetFill( rSet, aElipse.aFill );
405
406 return pObj;
407 }
408
ReadArc(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)409 SdrObject* SwWW8ImplReader::ReadArc(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
410 {
411 WW8_DP_ARC aArc;
412
413 if( !ReadGrafStart( static_cast<void*>(&aArc), sizeof( aArc ), pHd, rSet ) )
414 return nullptr;
415
416 Point aP0( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa )) + m_nDrawXOfs2,
417 static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya )) + m_nDrawYOfs2 );
418 Point aP1( aP0 );
419 aP1.AdjustX(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dxa )) * 2 );
420 aP1.AdjustY(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dya )) * 2 );
421
422 short nA[] = { 2, 3, 1, 0 };
423 short nW = nA[ ( ( aArc.fLeft & 1 ) << 1 ) + ( aArc.fUp & 1 ) ];
424 if( !aArc.fLeft ){
425 aP0.AdjustY( -static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dya )) );
426 aP1.AdjustY( -static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dya )) );
427 }
428 if( aArc.fUp ){
429 aP0.AdjustX( -static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dxa )) );
430 aP1.AdjustX( -static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dxa )) );
431 }
432
433 SdrObject* pObj = new SdrCircObj(
434 *m_pDrawModel,
435 SdrCircKind::Section,
436 tools::Rectangle(aP0, aP1),
437 nW * 9000,
438 ( ( nW + 1 ) & 3 ) * 9000);
439
440 SetStdAttr( rSet, aArc.aLnt, aArc.aShd );
441 SetFill( rSet, aArc.aFill );
442
443 return pObj;
444 }
445
ReadPolyLine(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)446 SdrObject* SwWW8ImplReader::ReadPolyLine(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
447 {
448 WW8_DP_POLYLINE aPoly;
449
450 if( !ReadGrafStart( static_cast<void*>(&aPoly), sizeof( aPoly ), pHd, rSet ) )
451 return nullptr;
452
453 sal_uInt16 nCount = SVBT16ToUInt16( aPoly.aBits1 ) >> 1 & 0x7fff;
454 std::unique_ptr<SVBT16[]> xP(new SVBT16[nCount * 2]);
455
456 bool bCouldRead = checkRead(*m_pStrm, xP.get(), nCount * 4); // read points
457 OSL_ENSURE(bCouldRead, "Short PolyLine header");
458 if (!bCouldRead)
459 return nullptr;
460
461 tools::Polygon aP( nCount );
462 Point aPt;
463 for (sal_uInt16 i=0; i<nCount; ++i)
464 {
465 aPt.setX( SVBT16ToUInt16( xP[i << 1] ) + m_nDrawXOfs2
466 + static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa )) );
467 aPt.setY( SVBT16ToUInt16( xP[( i << 1 ) + 1] ) + m_nDrawYOfs2
468 + static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya )) );
469 aP[i] = aPt;
470 }
471 xP.reset();
472
473 SdrObject* pObj = new SdrPathObj(
474 *m_pDrawModel,
475 (SVBT16ToUInt16(aPoly.aBits1) & 0x1) ? OBJ_POLY : OBJ_PLIN,
476 ::basegfx::B2DPolyPolygon(aP.getB2DPolygon()));
477
478 SetStdAttr( rSet, aPoly.aLnt, aPoly.aShd );
479 SetFill( rSet, aPoly.aFill );
480
481 return pObj;
482 }
483
GetESelection(EditEngine const & rDrawEditEngine,long nCpStart,long nCpEnd)484 static ESelection GetESelection(EditEngine const &rDrawEditEngine, long nCpStart, long nCpEnd)
485 {
486 sal_Int32 nPCnt = rDrawEditEngine.GetParagraphCount();
487 sal_Int32 nSP = 0;
488 sal_Int32 nEP = 0;
489 while( (nSP < nPCnt)
490 && (nCpStart >= rDrawEditEngine.GetTextLen( nSP ) + 1) )
491 {
492 nCpStart -= rDrawEditEngine.GetTextLen( nSP ) + 1;
493 nSP++;
494 }
495 // at the end, switch to the new line only 1 character later as
496 // otherwise line attributes reach one line too far
497 while( (nEP < nPCnt)
498 && (nCpEnd > rDrawEditEngine.GetTextLen( nEP ) + 1) )
499 {
500 nCpEnd -= rDrawEditEngine.GetTextLen( nEP ) + 1;
501 nEP++;
502 }
503 return ESelection( nSP, nCpStart, nEP, nCpEnd );
504 }
505
506 // InsertTxbxStyAttrs() sets style attributes into the passed ItemSet.
507 // SW styles are used since import-WW-styles are already destroyed.
508 // SW styles are examined in depth first search order (with parent styles)
509 // for the attributes given in aSrcTab. They're cloned, and the clones'
510 // Which-IDs are changed according to the aDstTab table so that the
511 // EditEngine will not ignore them.
512 // Both Paragraph and character attributes are stuffed into the ItemSet.
InsertTxbxStyAttrs(SfxItemSet & rS,sal_uInt16 nColl)513 void SwWW8ImplReader::InsertTxbxStyAttrs( SfxItemSet& rS, sal_uInt16 nColl )
514 {
515 SwWW8StyInf * pStyInf = GetStyle(nColl);
516 if( pStyInf != nullptr && pStyInf->m_pFormat && pStyInf->m_bColl )
517 {
518 const SfxPoolItem* pItem;
519 for( sal_uInt16 i = POOLATTR_BEGIN; i < POOLATTR_END; i++ )
520 {
521 // If we are set in the source and not set in the destination
522 // then add it in.
523 if ( SfxItemState::SET == pStyInf->m_pFormat->GetItemState(
524 i, true, &pItem ) )
525 {
526 SfxItemPool *pEditPool = rS.GetPool();
527 sal_uInt16 nWhich = i;
528 sal_uInt16 nSlotId = m_rDoc.GetAttrPool().GetSlotId(nWhich);
529 if (
530 nSlotId && nWhich != nSlotId &&
531 0 != (nWhich = pEditPool->GetWhich(nSlotId)) &&
532 nWhich != nSlotId &&
533 ( SfxItemState::SET != rS.GetItemState(nWhich, false) )
534 )
535 {
536 rS.Put( pItem->CloneSetWhich(nWhich) );
537 }
538 }
539 }
540 }
541
542 }
543
lcl_StripFields(OUString & rString,WW8_CP & rNewStartCp)544 static void lcl_StripFields(OUString &rString, WW8_CP &rNewStartCp)
545 {
546 sal_Int32 nStartPos = 0;
547 for (;;)
548 {
549 nStartPos = rString.indexOf(0x13, nStartPos);
550 if (nStartPos<0)
551 return;
552
553 const sal_Unicode cStops[] = {0x14, 0x15, 0};
554 const sal_Int32 nStopPos = comphelper::string::indexOfAny(rString, cStops, nStartPos);
555 if (nStopPos<0)
556 {
557 rNewStartCp += rString.getLength()-nStartPos;
558 rString = rString.copy(0, nStartPos);
559 return;
560 }
561
562 const bool was0x14 = rString[nStopPos]==0x14;
563 rString = rString.replaceAt(nStartPos, nStopPos+1-nStartPos, "");
564 rNewStartCp += nStopPos-nStartPos;
565
566 if (was0x14)
567 {
568 ++rNewStartCp;
569 nStartPos = rString.indexOf(0x15, nStartPos);
570 if (nStartPos<0)
571 return;
572 rString = rString.replaceAt(nStartPos, 1, "");
573 }
574 }
575 }
576
577 class Chunk
578 {
579 private:
580 OUString msURL;
581 long mnStartPos; // 0x13
582 long mnEndPos; // 0x15
583 public:
Chunk(long nStart,const OUString & rURL)584 explicit Chunk(long nStart, const OUString &rURL)
585 : msURL(rURL), mnStartPos(nStart), mnEndPos(0) {}
586
SetEndPos(long nEnd)587 void SetEndPos(long nEnd) { mnEndPos = nEnd; }
GetStartPos() const588 long GetStartPos() const {return mnStartPos;}
GetEndPos() const589 long GetEndPos() const {return mnEndPos;}
GetURL() const590 const OUString &GetURL() const {return msURL;}
Adjust(sal_Int32 nAdjust)591 void Adjust(sal_Int32 nAdjust)
592 {
593 mnStartPos-=nAdjust;
594 mnEndPos-=nAdjust;
595 }
596 };
597
598 namespace
599 {
IsValidSel(const EditEngine & rEngine,const ESelection & rSel)600 bool IsValidSel(const EditEngine& rEngine, const ESelection& rSel)
601 {
602 const auto nParaCount = rEngine.GetParagraphCount();
603 if (rSel.nStartPara < nParaCount && rSel.nEndPara < nParaCount)
604 return rSel.nStartPos >= 0 && rSel.nEndPos >= 0;
605 return false;
606 }
607 }
608
609 // InsertAttrsAsDrawingAttrs() sets attributes between StartCp and EndCp.
610 // Style attributes are set as hard, paragraph and character attributes.
InsertAttrsAsDrawingAttrs(WW8_CP nStartCp,WW8_CP nEndCp,ManTypes eType,bool bONLYnPicLocFc)611 void SwWW8ImplReader::InsertAttrsAsDrawingAttrs(WW8_CP nStartCp, WW8_CP nEndCp,
612 ManTypes eType, bool bONLYnPicLocFc)
613 {
614 /*
615 Save and create new plcxman for this drawing object, of the type that
616 will include the para end mark inside a paragraph property range, as
617 drawing boxes have real paragraph marks as part of their text, while
618 normal writer has separate nodes for each paragraph and so has no actual
619 paragraph mark as part of the paragraph text.
620 */
621 WW8ReaderSave aSave(this);
622 m_xPlcxMan.reset(new WW8PLCFMan(m_xSBase.get(), eType, nStartCp, true));
623
624 WW8_CP nStart = m_xPlcxMan->Where();
625 WW8_CP nNext, nStartReplace=0;
626
627 bool bDoingSymbol = false;
628 sal_Unicode cReplaceSymbol = m_cSymbol;
629
630 std::unique_ptr<SfxItemSet> pS(new SfxItemSet(m_pDrawEditEngine->GetEmptyItemSet()));
631 WW8PLCFManResult aRes;
632
633 std::deque<Chunk> aChunks;
634
635 // Here store stack location
636 size_t nCurrentCount = m_xCtrlStck->size();
637 while (nStart < nEndCp)
638 {
639 // nStart is the beginning of the attributes for this range, and
640 // may be before the text itself. So watch out for that
641 WW8_CP nTextStart = nStart;
642 if (nTextStart < nStartCp)
643 nTextStart = nStartCp;
644
645 // get position of next SPRM
646 bool bStartAttr = m_xPlcxMan->Get(&aRes);
647 m_nCurrentColl = m_xPlcxMan->GetColl();
648 if (aRes.nSprmId)
649 {
650 if( bONLYnPicLocFc )
651 {
652 if ( (68 == aRes.nSprmId) || (0x6A03 == aRes.nSprmId) )
653 {
654 Read_PicLoc(aRes.nSprmId, aRes.pMemPos +
655 m_xSprmParser->DistanceToData(aRes.nSprmId), 4);
656 // Ok, that's what we were looking for. Now let's get
657 // out of here!
658 break;
659 }
660 }
661 else if ((eFTN > aRes.nSprmId) || (0x0800 <= aRes.nSprmId))
662 {
663 // Here place them onto our usual stack and we will pop them
664 // off and convert them later
665 if (bStartAttr)
666 {
667 ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
668 if (!bDoingSymbol && m_bSymbol)
669 {
670 bDoingSymbol = true;
671 nStartReplace = nTextStart;
672 cReplaceSymbol = m_cSymbol;
673 }
674 }
675 else
676 {
677 EndSprm( aRes.nSprmId );
678 if (!m_bSymbol && bDoingSymbol)
679 {
680 bDoingSymbol = false;
681 OUStringBuffer sTemp;
682 comphelper::string::padToLength(sTemp,
683 nTextStart - nStartReplace, cReplaceSymbol);
684 m_pDrawEditEngine->QuickInsertText(sTemp.makeStringAndClear(),
685 GetESelection(*m_pDrawEditEngine, nStartReplace - nStartCp,
686 nTextStart - nStartCp ) );
687 }
688 }
689 }
690 else if (aRes.nSprmId == eFLD)
691 {
692 if (bStartAttr)
693 {
694 size_t nCount = m_xCtrlStck->size();
695 if (m_aFieldStack.empty() && Read_Field(&aRes))
696 {
697 OUString sURL;
698 for (size_t nI = m_xCtrlStck->size(); nI > nCount; --nI)
699 {
700 const SfxPoolItem *pItem = ((*m_xCtrlStck)[nI-1]).pAttr.get();
701 sal_uInt16 nWhich = pItem->Which();
702 if (nWhich == RES_TXTATR_INETFMT)
703 {
704 const SwFormatINetFormat *pURL =
705 static_cast<const SwFormatINetFormat *>(pItem);
706 sURL = pURL->GetValue();
707 }
708 m_xCtrlStck->DeleteAndDestroy(nI-1);
709 }
710 aChunks.emplace_back(nStart, sURL);
711 }
712 }
713 else
714 {
715 if (!m_aFieldStack.empty() && End_Field() && !aChunks.empty())
716 aChunks.back().SetEndPos(nStart+1);
717 }
718 }
719 }
720
721 m_xPlcxMan->advance();
722 nNext = m_xPlcxMan->Where();
723
724 const WW8_CP nEnd = ( nNext < nEndCp ) ? nNext : nEndCp;
725 if (!bONLYnPicLocFc && nNext != nStart && nEnd >= nStartCp)
726 {
727 SfxItemPool *pEditPool = pS->GetPool();
728
729 // Here read current properties and convert them into pS
730 // and put those attrs into the draw box if they can be converted
731 // to draw attributes
732 if (m_xCtrlStck->size() - nCurrentCount)
733 {
734 for (size_t i = nCurrentCount; i < m_xCtrlStck->size(); ++i)
735 {
736 const SfxPoolItem *pItem = ((*m_xCtrlStck)[i]).pAttr.get();
737 sal_uInt16 nWhich = pItem->Which();
738 if( nWhich < RES_FLTRATTR_BEGIN ||
739 nWhich >= RES_FLTRATTR_END )
740 {
741 sal_uInt16 nSlotId = m_rDoc.GetAttrPool().GetSlotId(nWhich);
742 if (
743 nSlotId && nWhich != nSlotId &&
744 0 != (nWhich = pEditPool->GetWhich(nSlotId)) &&
745 nWhich != nSlotId
746 )
747 {
748 pS->Put( pItem->CloneSetWhich(nWhich) );
749 }
750 }
751 }
752 }
753 // Fill in the remainder from the style
754 InsertTxbxStyAttrs(*pS, m_nCurrentColl);
755
756 if( pS->Count() )
757 {
758 m_pDrawEditEngine->QuickSetAttribs( *pS,
759 GetESelection(*m_pDrawEditEngine, nTextStart - nStartCp, nEnd - nStartCp ) );
760 pS.reset( new SfxItemSet(m_pDrawEditEngine->GetEmptyItemSet()) );
761 }
762 }
763 nStart = nNext;
764 }
765 pS.reset();
766
767 // pop off as far as recorded location just in case there were some left
768 // unclosed
769 for (size_t nI = m_xCtrlStck->size(); nI > nCurrentCount; --nI)
770 m_xCtrlStck->DeleteAndDestroy(nI-1);
771
772 auto aEnd = aChunks.end();
773 for (auto aIter = aChunks.begin(); aIter != aEnd; ++aIter)
774 {
775 ESelection aSel(GetESelection(*m_pDrawEditEngine, aIter->GetStartPos()-nStartCp,
776 aIter->GetEndPos()-nStartCp));
777 if (!IsValidSel(*m_pDrawEditEngine, aSel))
778 continue;
779 OUString aString(m_pDrawEditEngine->GetText(aSel));
780 const sal_Int32 nOrigLen = aString.getLength();
781 WW8_CP nDummy(0);
782 lcl_StripFields(aString, nDummy);
783
784 sal_Int32 nChanged;
785 if (!aIter->GetURL().isEmpty())
786 {
787 SvxURLField aURL(aIter->GetURL(), aString, SvxURLFormat::AppDefault);
788 m_pDrawEditEngine->QuickInsertField(SvxFieldItem(aURL, EE_FEATURE_FIELD), aSel);
789 nChanged = nOrigLen - 1;
790 }
791 else
792 {
793 m_pDrawEditEngine->QuickInsertText(aString, aSel);
794 nChanged = nOrigLen - aString.getLength();
795 }
796 for (auto aIter2 = aIter+1; aIter2 != aEnd; ++aIter2)
797 aIter2->Adjust(nChanged);
798 }
799
800 /*
801 Don't worry about the new pPlcxMan, the restore removes it when
802 replacing the current one with the old one.
803 */
804 aSave.Restore(this);
805 }
806
GetTxbxTextSttEndCp(WW8_CP & rStartCp,WW8_CP & rEndCp,sal_uInt16 nTxBxS,sal_uInt16 nSequence)807 bool SwWW8ImplReader::GetTxbxTextSttEndCp(WW8_CP& rStartCp, WW8_CP& rEndCp,
808 sal_uInt16 nTxBxS, sal_uInt16 nSequence)
809 {
810 // grab the TextBox-PLCF quickly
811 WW8PLCFspecial* pT = m_xPlcxMan ? m_xPlcxMan->GetTxbx() : nullptr;
812 if( !pT )
813 {
814 OSL_ENSURE( false, "+where's the text graphic (1)?" );
815 return false;
816 }
817
818 // if applicable first find the right TextBox-Story
819 bool bCheckTextBoxStory = ( nTxBxS && pT->GetIMax() >= nTxBxS );
820 if( bCheckTextBoxStory )
821 pT->SetIdx( nTxBxS-1 );
822
823 // then determine start and end
824 void* pT0;
825 if (!pT->Get(rStartCp, pT0) || rStartCp < 0)
826 {
827 OSL_ENSURE( false, "+where's the text graphic (2)?" );
828 return false;
829 }
830
831 if( bCheckTextBoxStory )
832 {
833 bool bReusable = (0 != SVBT16ToUInt16( static_cast<WW8_TXBXS*>(pT0)->fReusable ));
834 while( bReusable )
835 {
836 pT->advance();
837 if( !pT->Get( rStartCp, pT0 ) )
838 {
839 OSL_ENSURE( false, "+where's the text graphic (2a)?" );
840 return false;
841 }
842 bReusable = (0 != SVBT16ToUInt16( static_cast<WW8_TXBXS*>(pT0)->fReusable ));
843 }
844 }
845 pT->advance();
846 if (!pT->Get(rEndCp, pT0) || rEndCp < 0)
847 {
848 OSL_ENSURE( false, "+where's the text graphic (3)?" );
849 return false;
850 }
851
852 // find the right page in the break table (if necessary)
853 if( bCheckTextBoxStory )
854 {
855 // special case: entire chain should be determined - done!
856 if( USHRT_MAX > nSequence )
857 {
858 long nMinStartCp = rStartCp;
859 long nMaxEndCp = rEndCp;
860 // quickly grab the TextBox-Break-Descriptor-PLCF
861 pT = m_xPlcxMan->GetTxbxBkd();
862 if (!pT) // It can occur on occasion, Caolan
863 return false;
864
865 // find first entry for this TextBox story
866 if( !pT->SeekPos( rStartCp ) )
867 {
868 OSL_ENSURE( false, "+where's the text graphic (4)" );
869 return false;
870 }
871 // if needed skip the appropriate number of entries
872 for (sal_uInt16 iSequence = 0; iSequence < nSequence; ++iSequence)
873 pT->advance();
874 // and determine actual start and end
875 if( (!pT->Get( rStartCp, pT0 ))
876 || ( nMinStartCp > rStartCp ) )
877 {
878 OSL_ENSURE( false, "+where's the text graphic (5)?" );
879 return false;
880 }
881 if( rStartCp >= nMaxEndCp )
882 rEndCp = rStartCp; // not an error: empty string
883 else
884 {
885 pT->advance();
886 if ( (!pT->Get(rEndCp, pT0)) || (nMaxEndCp < rEndCp-1) )
887 {
888 OSL_ENSURE( false, "+where's the text graphic (6)?" );
889 return false;
890 }
891 rEndCp -= 1;
892 }
893 }
894 else
895 rEndCp -= 1;
896 }
897 else
898 rEndCp -= 1;
899 return true;
900 }
901
902 // TxbxText() grabs the text from the WW file and returns that along with
903 // the StartCp and the corrected (by -2, or -1 for version 8) EndCp.
GetRangeAsDrawingString(OUString & rString,long nStartCp,long nEndCp,ManTypes eType)904 sal_Int32 SwWW8ImplReader::GetRangeAsDrawingString(OUString& rString, long nStartCp, long nEndCp, ManTypes eType)
905 {
906 WW8_CP nOffset = 0;
907 m_xWwFib->GetBaseCp(eType, &nOffset); //TODO: check return value
908
909 OSL_ENSURE(nStartCp <= nEndCp, "+where's the graphic text (7)?");
910 if (nStartCp == nEndCp)
911 rString.clear(); // empty string: entirely possible
912 else if (nStartCp < nEndCp)
913 {
914 // read the text: can be split into multiple pieces
915 const sal_Int32 nLen = m_xSBase->WW8ReadString(*m_pStrm, rString,
916 nStartCp + nOffset, nEndCp - nStartCp, GetCurrentCharSet());
917 OSL_ENSURE(nLen, "+where's the text graphic (8)?");
918 if (nLen>0)
919 {
920 if( rString[nLen-1]==0x0d )
921 rString = rString.copy(0, nLen-1);
922
923 rString = rString.replace( 0xb, 0xa );
924 return nLen;
925 }
926 }
927 return 0;
928 }
929
930 //EditEngine::InsertText will replace dos lines resulting in a shorter
931 //string than is passed in, so inserting attributes based on the original
932 //string len can fail. So here replace the dos line ends similar to
933 //how EditEngine does it, but preserve the length and replace the extra
934 //chars with placeholders, record the position of the placeholders and
935 //remove those extra chars after attributes have been inserted
replaceDosLineEndsButPreserveLength(OUString & rIn)936 static std::vector<sal_Int32> replaceDosLineEndsButPreserveLength(OUString &rIn)
937 {
938 OUStringBuffer aNewData(rIn);
939 std::vector<sal_Int32> aDosLineEndDummies;
940 sal_Int32 i = 0;
941 sal_Int32 nStrLen = rIn.getLength();
942 while (i < nStrLen)
943 {
944 // \r or \n causes linebreak
945 if (rIn[i] == '\r' || rIn[i] == '\n')
946 {
947 // skip char if \r\n or \n\r
948 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
949 (rIn[i] != rIn[i+1]) )
950 {
951 ++i;
952 aDosLineEndDummies.push_back(i);
953 aNewData[i] = 0;
954 }
955 }
956 ++i;
957 }
958 rIn = aNewData.makeStringAndClear();
959 return aDosLineEndDummies;
960 }
961
removePositions(EditEngine & rDrawEditEngine,const std::vector<sal_Int32> & rDosLineEndDummies)962 static void removePositions(EditEngine &rDrawEditEngine, const std::vector<sal_Int32>& rDosLineEndDummies)
963 {
964 for (auto aIter = rDosLineEndDummies.rbegin(); aIter != rDosLineEndDummies.rend(); ++aIter)
965 {
966 sal_Int32 nCharPos(*aIter);
967 rDrawEditEngine.QuickDelete(GetESelection(rDrawEditEngine, nCharPos, nCharPos+1));
968 }
969 }
970
ImportAsOutliner(OUString & rString,WW8_CP nStartCp,WW8_CP nEndCp,ManTypes eType)971 std::unique_ptr<OutlinerParaObject> SwWW8ImplReader::ImportAsOutliner(OUString &rString, WW8_CP nStartCp, WW8_CP nEndCp, ManTypes eType)
972 {
973 std::unique_ptr<OutlinerParaObject> pRet;
974
975 sal_Int32 nLen = GetRangeAsDrawingString(rString, nStartCp, nEndCp, eType);
976 if (nLen > 0)
977 {
978 if (!m_pDrawEditEngine)
979 {
980 m_pDrawEditEngine.reset(new EditEngine(nullptr));
981 }
982
983 //replace dos line endings with editeng ones, replace any extra chars with
984 //placeholders to keep the inserted string len in sync with the attribute cps
985 //and record in aDosLineEnds the superfluous positions
986 OUString sEEString(rString);
987 std::vector<sal_Int32> aDosLineEnds(replaceDosLineEndsButPreserveLength(sEEString));
988 m_pDrawEditEngine->SetText(sEEString);
989 InsertAttrsAsDrawingAttrs(nStartCp, nStartCp+nLen, eType);
990 //remove any superfluous placeholders of replaceDosLineEndsButPreserveLength
991 //after attributes have been inserted
992 removePositions(*m_pDrawEditEngine, aDosLineEnds);
993
994 // Annotations typically begin with a (useless) 0x5
995 if ((eType == MAN_AND) && m_pDrawEditEngine->GetTextLen())
996 {
997 ESelection aFirstChar(0, 0, 0, 1);
998 if (m_pDrawEditEngine->GetText( aFirstChar ) == "\x05")
999 m_pDrawEditEngine->QuickDelete(aFirstChar);
1000 }
1001
1002 std::unique_ptr<EditTextObject> pTemporaryText = m_pDrawEditEngine->CreateTextObject();
1003 pRet.reset( new OutlinerParaObject( std::move(pTemporaryText) ) );
1004 pRet->SetOutlinerMode( OutlinerMode::TextObject );
1005
1006 m_pDrawEditEngine->SetText( OUString() );
1007 m_pDrawEditEngine->SetParaAttribs(0, m_pDrawEditEngine->GetEmptyItemSet());
1008
1009 // Strip out fields, leaving the result
1010 WW8_CP nDummy(0);
1011 lcl_StripFields(rString, nDummy);
1012 // Strip out word's special characters for the simple string
1013 rString = rString.replaceAll("\x01", "");
1014 rString = rString.replaceAll("\x05", "");
1015 rString = rString.replaceAll("\x08", "");
1016 rString = rString.replaceAll("\007\007", "\007\012");
1017 rString = rString.replace(0x7, ' ');
1018 }
1019
1020 return pRet;
1021 }
1022
1023 // InsertTxbxText() adds the Text and the Attributes for TextBoxes and CaptionBoxes
InsertTxbxText(SdrTextObj * pTextObj,Size const * pObjSiz,sal_uInt16 nTxBxS,sal_uInt16 nSequence,long nPosCp,SwFrameFormat const * pOldFlyFormat,bool bMakeSdrGrafObj,bool & rbEraseTextObj,bool * pbTestTxbxContainsText,long * pnStartCp,long * pnEndCp,bool * pbContainsGraphics,SvxMSDffImportRec const * pRecord)1024 void SwWW8ImplReader::InsertTxbxText(SdrTextObj* pTextObj,
1025 Size const * pObjSiz, sal_uInt16 nTxBxS, sal_uInt16 nSequence, long nPosCp,
1026 SwFrameFormat const * pOldFlyFormat, bool bMakeSdrGrafObj, bool& rbEraseTextObj,
1027 bool* pbTestTxbxContainsText, long* pnStartCp, long* pnEndCp,
1028 bool* pbContainsGraphics, SvxMSDffImportRec const * pRecord)
1029 {
1030 SwFrameFormat* pFlyFormat = nullptr;
1031 sal_uLong nOld = m_pStrm->Tell();
1032
1033 ManTypes eType = m_xPlcxMan->GetManType() == MAN_HDFT ? MAN_TXBX_HDFT : MAN_TXBX;
1034
1035 rbEraseTextObj = false;
1036
1037 OUString aString;
1038 WW8_CP nStartCp, nEndCp;
1039 bool bContainsGraphics = false;
1040 bool bTextWasRead = GetTxbxTextSttEndCp(nStartCp, nEndCp, nTxBxS, nSequence) &&
1041 GetRangeAsDrawingString(aString, nStartCp, nEndCp, eType) > 0;
1042
1043 if (!m_pDrawEditEngine)
1044 {
1045 m_pDrawEditEngine.reset(new EditEngine(nullptr));
1046 }
1047 if( pObjSiz )
1048 m_pDrawEditEngine->SetPaperSize( *pObjSiz );
1049
1050 const OUString aOrigString(aString);
1051 if( bTextWasRead )
1052 {
1053 WW8_CP nNewStartCp = nStartCp;
1054 lcl_StripFields(aString, nNewStartCp);
1055
1056 if (aString.getLength()!=1)
1057 {
1058 bContainsGraphics = aString.indexOf(0x1)<0 || aString.indexOf(0x8)<0;
1059 }
1060 else // May be a single graphic or object
1061 {
1062 bool bDone = true;
1063 switch( aString[0] )
1064 {
1065 case 0x1:
1066 if (!pbTestTxbxContainsText)
1067 {
1068 WW8ReaderSave aSave(this, nNewStartCp -1);
1069 bool bOldEmbeddObj = m_bEmbeddObj;
1070 // bEmbeddObj Ordinarily would have been set by field
1071 // parse, but this is impossible here so...
1072 m_bEmbeddObj = true;
1073
1074 // 1st look for OLE- or Graph-Indicator Sprms
1075 WW8PLCFx_Cp_FKP* pChp = m_xPlcxMan->GetChpPLCF();
1076 WW8PLCFxDesc aDesc;
1077 pChp->GetSprms( &aDesc );
1078 WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, *m_xSprmParser);
1079
1080 for( int nLoop = 0; nLoop < 2; ++nLoop )
1081 {
1082 while (aSprmIter.GetSprms())
1083 {
1084 const sal_uInt8 *const pParams(aSprmIter.GetCurrentParams());
1085 if (nullptr == pParams)
1086 break;
1087 sal_uInt16 nCurrentId = aSprmIter.GetCurrentId();
1088 switch( nCurrentId )
1089 {
1090 case 75:
1091 case 118:
1092 case 0x080A:
1093 case 0x0856:
1094 Read_Obj(nCurrentId, pParams, 1);
1095 break;
1096 case 68: // Read_Pic()
1097 case 0x6A03:
1098 case NS_sprm::LN_CObjLocation:
1099 Read_PicLoc(nCurrentId, pParams, 1);
1100 break;
1101 }
1102 aSprmIter.advance();
1103 }
1104
1105 if( !nLoop )
1106 {
1107 pChp->GetPCDSprms( aDesc );
1108 aSprmIter.SetSprms( aDesc.pMemPos,
1109 aDesc.nSprmsLen );
1110 }
1111 }
1112 aSave.Restore(this);
1113 m_bEmbeddObj=bOldEmbeddObj;
1114
1115 // then import either an OLE of a Graphic
1116 if( m_bObj )
1117 {
1118 if( bMakeSdrGrafObj && pTextObj &&
1119 pTextObj->getParentSdrObjectFromSdrObject() )
1120 {
1121 // use SdrOleObj/SdrGrafObj instead of
1122 // SdrTextObj in this Group
1123
1124 Graphic aGraph;
1125 SdrObject* pNew = ImportOleBase(aGraph);
1126
1127 if( !pNew )
1128 {
1129 pNew = new SdrGrafObj(*m_pDrawModel);
1130 static_cast<SdrGrafObj*>(pNew)->SetGraphic(aGraph);
1131 }
1132
1133 GrafikCtor();
1134
1135 pNew->SetLogicRect( pTextObj->GetCurrentBoundRect() );
1136 pNew->SetLayer( pTextObj->GetLayer() );
1137
1138 pTextObj->getParentSdrObjectFromSdrObject()->GetSubList()->
1139 ReplaceObject(pNew, pTextObj->GetOrdNum());
1140 }
1141 else
1142 pFlyFormat = ImportOle();
1143 m_bObj = false;
1144 }
1145 else
1146 {
1147 InsertAttrsAsDrawingAttrs(nNewStartCp, nNewStartCp+1,
1148 eType, true);
1149 pFlyFormat = ImportGraf(bMakeSdrGrafObj ? pTextObj : nullptr,
1150 pOldFlyFormat);
1151 }
1152 }
1153 break;
1154 case 0x8:
1155 if ( (!pbTestTxbxContainsText) && (!m_bObj) )
1156 pFlyFormat = Read_GrafLayer( nPosCp );
1157 break;
1158 default:
1159 bDone = false;
1160 break;
1161 }
1162
1163 if( bDone )
1164 {
1165 if( pFlyFormat && pRecord )
1166 {
1167 SfxItemSet aFlySet( m_rDoc.GetAttrPool(),
1168 svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END-1, XATTR_START, XATTR_END>{} );
1169
1170 tools::Rectangle aInnerDist( pRecord->nDxTextLeft,
1171 pRecord->nDyTextTop,
1172 pRecord->nDxTextRight,
1173 pRecord->nDyTextBottom );
1174 MatchSdrItemsIntoFlySet( pTextObj,
1175 aFlySet,
1176 pRecord->eLineStyle,
1177 pRecord->eLineDashing,
1178 pRecord->eShapeType,
1179 aInnerDist );
1180
1181 pFlyFormat->SetFormatAttr( aFlySet );
1182
1183 MapWrapIntoFlyFormat(pRecord, pFlyFormat);
1184 }
1185 aString.clear();
1186 rbEraseTextObj = (nullptr != pFlyFormat);
1187 }
1188 }
1189 }
1190
1191 if( pnStartCp )
1192 *pnStartCp = nStartCp;
1193 if( pnEndCp )
1194 *pnEndCp = nEndCp;
1195
1196 if( pbTestTxbxContainsText )
1197 *pbTestTxbxContainsText = bTextWasRead && ! rbEraseTextObj;
1198 else if( !rbEraseTextObj )
1199 {
1200 if( bTextWasRead )
1201 {
1202 m_pDrawEditEngine->SetText(aOrigString);
1203 InsertAttrsAsDrawingAttrs(nStartCp, nEndCp, eType);
1204 }
1205
1206 bool bVertical = pTextObj->IsVerticalWriting();
1207 std::unique_ptr<EditTextObject> pTemporaryText = m_pDrawEditEngine->CreateTextObject();
1208 std::unique_ptr<OutlinerParaObject> pOp( new OutlinerParaObject(*pTemporaryText) );
1209 pOp->SetOutlinerMode( OutlinerMode::TextObject );
1210 pOp->SetVertical( bVertical );
1211 pTemporaryText.reset();
1212 pTextObj->NbcSetOutlinerParaObject( std::move(pOp) );
1213 pTextObj->SetVerticalWriting(bVertical);
1214
1215 // For the next TextBox also remove the old paragraph attributes
1216 // and styles, otherwise the next box will start with the wrong
1217 // attributes.
1218 // Course of action: delete text = reduce to one paragraph
1219 // and on this one delete the paragraph attributes
1220 // and styles
1221 m_pDrawEditEngine->SetText( OUString() );
1222 m_pDrawEditEngine->SetParaAttribs(0, m_pDrawEditEngine->GetEmptyItemSet());
1223 }
1224
1225 m_pStrm->Seek( nOld );
1226 if (pbContainsGraphics)
1227 *pbContainsGraphics = bContainsGraphics;
1228 }
1229
TxbxChainContainsRealText(sal_uInt16 nTxBxS,long & rStartCp,long & rEndCp)1230 bool SwWW8ImplReader::TxbxChainContainsRealText(sal_uInt16 nTxBxS, long& rStartCp,
1231 long& rEndCp)
1232 {
1233 bool bErase, bContainsText;
1234 InsertTxbxText( nullptr,nullptr,nTxBxS,USHRT_MAX,0,nullptr,false, bErase, &bContainsText,
1235 &rStartCp, &rEndCp );
1236 return bContainsText;
1237 }
1238
1239 // TextBoxes only for Ver67 !!
ReadTextBox(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)1240 SdrObject* SwWW8ImplReader::ReadTextBox(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
1241 {
1242 bool bDummy;
1243 WW8_DP_TXTBOX aTextB;
1244
1245 if( !ReadGrafStart( static_cast<void*>(&aTextB), sizeof( aTextB ), pHd, rSet ) )
1246 return nullptr;
1247
1248 Point aP0( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa )) + m_nDrawXOfs2,
1249 static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya )) + m_nDrawYOfs2 );
1250 Point aP1( aP0 );
1251 aP1.AdjustX(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dxa )) );
1252 aP1.AdjustY(static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dya )) );
1253
1254 SdrRectObj* pObj = new SdrRectObj(
1255 *m_pDrawModel,
1256 OBJ_TEXT,
1257 tools::Rectangle(aP0, aP1));
1258
1259 pObj->NbcSetSnapRect(tools::Rectangle(aP0, aP1));
1260 Size aSize( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dxa )) ,
1261 static_cast<sal_Int16>(SVBT16ToUInt16( pHd->dya )) );
1262
1263 long nStartCpFly,nEndCpFly;
1264 bool bContainsGraphics;
1265 InsertTxbxText(pObj, &aSize, 0, 0, 0, nullptr, false,
1266 bDummy,nullptr,&nStartCpFly,&nEndCpFly,&bContainsGraphics);
1267
1268 SetStdAttr( rSet, aTextB.aLnt, aTextB.aShd );
1269 SetFill( rSet, aTextB.aFill );
1270
1271 rSet.Put( SdrTextFitToSizeTypeItem( drawing::TextFitToSizeType_NONE ) );
1272 rSet.Put( makeSdrTextAutoGrowWidthItem(false));
1273 rSet.Put( makeSdrTextAutoGrowHeightItem(false));
1274 rSet.Put( makeSdrTextLeftDistItem( MIN_BORDER_DIST*2 ) );
1275 rSet.Put( makeSdrTextRightDistItem( MIN_BORDER_DIST*2 ) );
1276 rSet.Put( makeSdrTextUpperDistItem( MIN_BORDER_DIST ) );
1277 rSet.Put( makeSdrTextLowerDistItem( MIN_BORDER_DIST ) );
1278
1279 return pObj;
1280 }
1281
ReadCaptionBox(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)1282 SdrObject* SwWW8ImplReader::ReadCaptionBox(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
1283 {
1284 static const SdrCaptionType aCaptA[] = { SdrCaptionType::Type1, SdrCaptionType::Type2,
1285 SdrCaptionType::Type3, SdrCaptionType::Type4 };
1286
1287 WW8_DP_CALLOUT_TXTBOX aCallB;
1288
1289 if( !ReadGrafStart( static_cast<void*>(&aCallB), sizeof( aCallB ), pHd, rSet ) )
1290 return nullptr;
1291
1292 sal_uInt16 nCount = SVBT16ToUInt16( aCallB.dpPolyLine.aBits1 ) >> 1 & 0x7fff;
1293 if (nCount < 1)
1294 {
1295 SAL_WARN("sw.ww8", "Short CaptionBox header");
1296 return nullptr;
1297 }
1298
1299 std::unique_ptr<SVBT16[]> xP(new SVBT16[nCount * 2]);
1300
1301 bool bCouldRead = checkRead(*m_pStrm, xP.get(), nCount * 4); // read points
1302 if (!bCouldRead)
1303 {
1304 SAL_WARN("sw.ww8", "Short CaptionBox header");
1305 return nullptr;
1306 }
1307
1308 sal_uInt8 nTyp = static_cast<sal_uInt8>(nCount) - 1;
1309 if( nTyp == 1 && SVBT16ToUInt16( xP[0] ) == SVBT16ToUInt16( xP[2] ) )
1310 nTyp = 0;
1311
1312 Point aP0( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa )) +
1313 static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadTxbx.xa )) + m_nDrawXOfs2,
1314 static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya ))
1315 + static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadTxbx.ya )) + m_nDrawYOfs2 );
1316 Point aP1( aP0 );
1317 aP1.AdjustX(static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadTxbx.dxa )) );
1318 aP1.AdjustY(static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadTxbx.dya )) );
1319 Point aP2( static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa ))
1320 + static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadPolyLine.xa ))
1321 + m_nDrawXOfs2 + static_cast<sal_Int16>(SVBT16ToUInt16( xP[0] )),
1322 static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya ))
1323 + static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadPolyLine.ya ))
1324 + m_nDrawYOfs2 + static_cast<sal_Int16>(SVBT16ToUInt16( xP[1] )) );
1325 xP.reset();
1326
1327 SdrCaptionObj* pObj = new SdrCaptionObj(
1328 *m_pDrawModel,
1329 tools::Rectangle(aP0, aP1),
1330 aP2);
1331
1332 pObj->NbcSetSnapRect(tools::Rectangle(aP0, aP1));
1333 Size aSize( static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadTxbx.dxa )),
1334 static_cast<sal_Int16>(SVBT16ToUInt16( aCallB.dpheadTxbx.dya )) );
1335 bool bEraseThisObject;
1336
1337 InsertTxbxText(pObj, &aSize, 0, 0, 0, nullptr, false, bEraseThisObject );
1338
1339 if( SVBT16ToUInt16( aCallB.dptxbx.aLnt.lnps ) != 5 ) // Is border visible ?
1340 SetStdAttr( rSet, aCallB.dptxbx.aLnt, aCallB.dptxbx.aShd );
1341 else // no -> take lines
1342 SetStdAttr( rSet, aCallB.dpPolyLine.aLnt, aCallB.dptxbx.aShd );
1343 SetFill( rSet, aCallB.dptxbx.aFill );
1344 rSet.Put(SdrCaptionTypeItem(aCaptA[nTyp % SAL_N_ELEMENTS(aCaptA)]));
1345
1346 return pObj;
1347 }
1348
ReadGroup(WW8_DPHEAD const * pHd,SfxAllItemSet & rSet)1349 SdrObject *SwWW8ImplReader::ReadGroup(WW8_DPHEAD const * pHd, SfxAllItemSet &rSet)
1350 {
1351 sal_Int16 nGrouped;
1352
1353 if( !ReadGrafStart( static_cast<void*>(&nGrouped), sizeof( nGrouped ), pHd, rSet ) )
1354 return nullptr;
1355
1356 #ifdef OSL_BIGENDIAN
1357 nGrouped = (sal_Int16)OSL_SWAPWORD( nGrouped );
1358 #endif
1359
1360 m_nDrawXOfs = m_nDrawXOfs + static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa ));
1361 m_nDrawYOfs = m_nDrawYOfs + static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya ));
1362
1363 SdrObject* pObj = new SdrObjGroup(*m_pDrawModel);
1364
1365 short nLeft = static_cast<sal_Int16>(SVBT16ToUInt16( pHd->cb )) - sizeof( WW8_DPHEAD );
1366 for (int i = 0; i < nGrouped && nLeft >= static_cast<short>(sizeof(WW8_DPHEAD)); ++i)
1367 {
1368 SfxAllItemSet aSet(m_pDrawModel->GetItemPool());
1369 if (SdrObject *pObject = ReadGrafPrimitive(nLeft, aSet))
1370 {
1371 // first add and then set ItemSet
1372 SdrObjList *pSubGroup = pObj->GetSubList();
1373 OSL_ENSURE(pSubGroup, "Why no sublist available?");
1374 if (pSubGroup)
1375 pSubGroup->InsertObject(pObject, 0);
1376 pObject->SetMergedItemSetAndBroadcast(aSet);
1377 }
1378 }
1379
1380 m_nDrawXOfs = m_nDrawXOfs - static_cast<sal_Int16>(SVBT16ToUInt16( pHd->xa ));
1381 m_nDrawYOfs = m_nDrawYOfs - static_cast<sal_Int16>(SVBT16ToUInt16( pHd->ya ));
1382
1383 return pObj;
1384 }
1385
ReadGrafPrimitive(short & rLeft,SfxAllItemSet & rSet)1386 SdrObject* SwWW8ImplReader::ReadGrafPrimitive(short& rLeft, SfxAllItemSet &rSet)
1387 {
1388 // This whole archaic word 6 graphic import can probably be refactored
1389 // into an object hierarchy with a little effort.
1390 SdrObject *pRet=nullptr;
1391 WW8_DPHEAD aHd; // Read Draw-Primitive-Header
1392 bool bCouldRead = checkRead(*m_pStrm, &aHd, sizeof(WW8_DPHEAD)) &&
1393 SVBT16ToUInt16(aHd.cb) >= sizeof(WW8_DPHEAD);
1394 OSL_ENSURE(bCouldRead, "Graphic Primitive header short read" );
1395 if (!bCouldRead)
1396 {
1397 rLeft=0;
1398 return pRet;
1399 }
1400
1401 if( rLeft >= SVBT16ToUInt16(aHd.cb) ) // precautions
1402 {
1403 rSet.Put(SwFormatSurround(css::text::WrapTextMode_THROUGH));
1404 switch (SVBT16ToUInt16(aHd.dpk) & 0xff )
1405 {
1406 case 0:
1407 pRet = ReadGroup(&aHd, rSet);
1408 break;
1409 case 1:
1410 pRet = ReadLine(&aHd, rSet);
1411 break;
1412 case 2:
1413 pRet = ReadTextBox(&aHd, rSet);
1414 break;
1415 case 3:
1416 pRet = ReadRect(&aHd, rSet);
1417 break;
1418 case 4:
1419 pRet = ReadElipse(&aHd, rSet);
1420 break;
1421 case 5:
1422 pRet = ReadArc(&aHd, rSet);
1423 break;
1424 case 6:
1425 pRet = ReadPolyLine(&aHd, rSet);
1426 break;
1427 case 7:
1428 pRet = ReadCaptionBox(&aHd, rSet);
1429 break;
1430 default: // unknown
1431 m_pStrm->SeekRel(SVBT16ToUInt16(aHd.cb) - sizeof(WW8_DPHEAD));
1432 break;
1433 }
1434 }
1435 else
1436 {
1437 OSL_ENSURE( false, "+Grafik-Overlap" );
1438 }
1439 rLeft = rLeft - SVBT16ToUInt16( aHd.cb );
1440 return pRet;
1441 }
1442
ReadGrafLayer1(WW8PLCFspecial * pPF,long nGrafAnchorCp)1443 void SwWW8ImplReader::ReadGrafLayer1( WW8PLCFspecial* pPF, long nGrafAnchorCp )
1444 {
1445 pPF->SeekPos( nGrafAnchorCp );
1446 WW8_FC nStartFc;
1447 void* pF0;
1448 if( !pPF->Get( nStartFc, pF0 ) )
1449 {
1450 OSL_ENSURE( false, "+Where is the graphic (2) ?" );
1451 return;
1452 }
1453 WW8_FDOA* pF = static_cast<WW8_FDOA*>(pF0);
1454 if( !SVBT32ToUInt32( pF->fc ) )
1455 {
1456 OSL_ENSURE( false, "+Where is the graphic (3) ?" );
1457 return;
1458 }
1459
1460 bool bCouldSeek = checkSeek(*m_pStrm, SVBT32ToUInt32(pF->fc));
1461 OSL_ENSURE(bCouldSeek, "Invalid graphic offset");
1462 if (!bCouldSeek)
1463 return;
1464
1465 // read Draw-Header
1466 WW8_DO aDo;
1467 bool bCouldRead = checkRead(*m_pStrm, &aDo, sizeof(WW8_DO));
1468 OSL_ENSURE(bCouldRead, "Short graphic header");
1469 if (!bCouldRead)
1470 return;
1471
1472 short nLeft = SVBT16ToUInt16( aDo.cb ) - sizeof( WW8_DO );
1473 while (nLeft > static_cast<short>(sizeof(WW8_DPHEAD)))
1474 {
1475 SfxAllItemSet aSet( m_pDrawModel->GetItemPool() );
1476 if (SdrObject *pObject = ReadGrafPrimitive(nLeft, aSet))
1477 {
1478 m_xWWZOrder->InsertDrawingObject(pObject, SVBT16ToUInt16(aDo.dhgt));
1479
1480 tools::Rectangle aRect(pObject->GetSnapRect());
1481
1482 const sal_uInt32 nCntRelTo = 3;
1483
1484 // Adjustment is horizontally relative to...
1485 static const sal_Int16 aHoriRelOriTab[nCntRelTo] =
1486 {
1487 text::RelOrientation::PAGE_PRINT_AREA, // 0 is page textarea margin
1488 text::RelOrientation::PAGE_FRAME, // 1 is page margin
1489 text::RelOrientation::FRAME, // 2 is relative to paragraph
1490 };
1491
1492 // Adjustment is vertically relative to...
1493 static const sal_Int16 aVertRelOriTab[nCntRelTo] =
1494 {
1495 text::RelOrientation::PAGE_PRINT_AREA, // 0 is page textarea margin
1496 text::RelOrientation::PAGE_FRAME, // 1 is page margin
1497 text::RelOrientation::FRAME, // 2 is relative to paragraph
1498 };
1499
1500 const int nXAlign = aDo.bx < nCntRelTo ? aDo.bx : 0;
1501 const int nYAlign = aDo.by < nCntRelTo ? aDo.by : 0;
1502
1503 aSet.Put(SwFormatHoriOrient(aRect.Left(), text::HoriOrientation::NONE,
1504 aHoriRelOriTab[ nXAlign ]));
1505 aSet.Put(SwFormatVertOrient(aRect.Top(), text::VertOrientation::NONE,
1506 aVertRelOriTab[ nYAlign ]));
1507
1508 SwFrameFormat *pFrame = m_rDoc.getIDocumentContentOperations().InsertDrawObj( *m_pPaM, *pObject, aSet );
1509 pObject->SetMergedItemSet(aSet);
1510
1511 if (SwDrawFrameFormat *pDrawFrame = dynamic_cast<SwDrawFrameFormat*>(pFrame))
1512 {
1513 pDrawFrame->PosAttrSet();
1514 }
1515
1516 AddAutoAnchor(pFrame);
1517 }
1518 }
1519 }
1520
GetEscherLineMatch(MSO_LineStyle eStyle,MSO_SPT eShapeType,sal_Int32 & rThick)1521 sal_Int32 SwMSDffManager::GetEscherLineMatch(MSO_LineStyle eStyle,
1522 MSO_SPT eShapeType, sal_Int32 &rThick)
1523 {
1524 sal_Int32 nOutsideThick = 0;
1525 /*
1526 Note: In contrast to the regular WinWord table and frame border width,
1527 where the overall border width has to be calculated from the width of *one*
1528 line, the data from ESCHER already contains the overall width [twips]!
1529
1530 The WinWord default is 15 tw. We take for this our 20 tw line.
1531 (0.75 pt and 1.0 pt looking more similar on hardcopy than 0.75 pt and our
1532 0.05 pt hairline.) The hairline we only set by WinWord width up to max.
1533 0.5 pt.
1534 */
1535 switch( eStyle )
1536 {
1537 case mso_lineTriple:
1538 case mso_lineSimple:
1539 nOutsideThick = eShapeType != mso_sptTextBox ? rThick : rThick/2;
1540 break;
1541 case mso_lineDouble:
1542 if (eShapeType == mso_sptTextBox)
1543 {
1544 nOutsideThick = rThick/6;
1545 rThick = rThick*2/3;
1546 }
1547 else
1548 nOutsideThick = rThick*2/3;
1549 break;
1550 case mso_lineThickThin:
1551 if (eShapeType == mso_sptTextBox)
1552 {
1553 nOutsideThick = rThick*3/10;
1554 rThick = rThick*4/5;
1555 }
1556 else
1557 nOutsideThick = rThick*4/5;
1558 break;
1559 case mso_lineThinThick:
1560 {
1561 if (eShapeType == mso_sptTextBox)
1562 {
1563 nOutsideThick = rThick/10;
1564 rThick = rThick*3/5;
1565 }
1566 else
1567 nOutsideThick = rThick*3/5;
1568 }
1569 break;
1570 default:
1571 break;
1572 }
1573 return nOutsideThick;
1574 }
1575
1576 // Returns the thickness of the line outside the frame, the logic of
1577 // words positioning of borders around floating objects is that of a
1578 // disturbed mind.
MatchSdrBoxIntoFlyBoxItem(const Color & rLineColor,MSO_LineStyle eLineStyle,MSO_LineDashing eDashing,MSO_SPT eShapeType,sal_Int32 & rLineThick,SvxBoxItem & rBox)1579 sal_Int32 SwWW8ImplReader::MatchSdrBoxIntoFlyBoxItem(const Color& rLineColor,
1580 MSO_LineStyle eLineStyle, MSO_LineDashing eDashing, MSO_SPT eShapeType, sal_Int32 &rLineThick,
1581 SvxBoxItem& rBox )
1582 {
1583 sal_Int32 nOutsideThick = 0;
1584 if( !rLineThick )
1585 return nOutsideThick;
1586
1587 SvxBorderLineStyle nIdx = SvxBorderLineStyle::NONE;
1588
1589 sal_Int32 nLineThick=rLineThick;
1590 nOutsideThick = SwMSDffManager::GetEscherLineMatch(eLineStyle,
1591 eShapeType, rLineThick);
1592
1593 /*
1594 Note: In contrast to the regular WinWord table and frame border width,
1595 where the overall border width has to be calculated from the width of *one*
1596 line, the data from ESCHER already contains the overall width [twips]!
1597
1598 The WinWord default is 15 tw. We take for this our 20 tw line.
1599 (0.75 pt and 1.0 pt looking more similar on hardcopy than 0.75 pt and our
1600 0.05 pt hairline.) The hairline we only set by WinWord width up to max.
1601 0.5 pt.
1602 */
1603 switch( +eLineStyle )
1604 {
1605 // first the single lines
1606 case mso_lineSimple:
1607 nIdx = SvxBorderLineStyle::SOLID;
1608 break;
1609 // second the double lines
1610 case mso_lineDouble:
1611 nIdx = SvxBorderLineStyle::DOUBLE;
1612 break;
1613 case mso_lineThickThin:
1614 nIdx = SvxBorderLineStyle::THICKTHIN_SMALLGAP;
1615 break;
1616 case mso_lineThinThick:
1617 nIdx = SvxBorderLineStyle::THINTHICK_SMALLGAP;
1618 break;
1619 // We have no triple border, use double instead.
1620 case mso_lineTriple:
1621 nIdx = SvxBorderLineStyle::DOUBLE;
1622 break;
1623 // no line style is set
1624 case MSO_LineStyle(USHRT_MAX):
1625 break;
1626 // erroneously not implemented line style is set
1627 default:
1628 OSL_ENSURE(false, "eLineStyle is not (yet) implemented!");
1629 break;
1630 }
1631
1632 switch( eDashing )
1633 {
1634 case mso_lineDashGEL:
1635 nIdx = SvxBorderLineStyle::DASHED;
1636 break;
1637 case mso_lineDotGEL:
1638 nIdx = SvxBorderLineStyle::DOTTED;
1639 break;
1640 default:
1641 break;
1642 }
1643
1644 if (SvxBorderLineStyle::NONE != nIdx)
1645 {
1646 SvxBorderLine aLine;
1647 aLine.SetColor( rLineColor );
1648
1649 aLine.SetWidth( nLineThick ); // No conversion here, nLineThick is already in twips
1650 aLine.SetBorderLineStyle(nIdx);
1651
1652 for(SvxBoxItemLine nLine : o3tl::enumrange<SvxBoxItemLine>())
1653 {
1654 // aLine is cloned by SetLine
1655 rBox.SetLine(&aLine, nLine);
1656 }
1657 }
1658
1659 return nOutsideThick;
1660 }
1661
1662 #define WW8ITEMVALUE(ItemSet,Id,Cast) ItemSet.GetItem<Cast>(Id)->GetValue()
1663
MatchSdrItemsIntoFlySet(SdrObject const * pSdrObj,SfxItemSet & rFlySet,MSO_LineStyle eLineStyle,MSO_LineDashing eDashing,MSO_SPT eShapeType,tools::Rectangle & rInnerDist)1664 void SwWW8ImplReader::MatchSdrItemsIntoFlySet( SdrObject const * pSdrObj,
1665 SfxItemSet& rFlySet, MSO_LineStyle eLineStyle, MSO_LineDashing eDashing, MSO_SPT eShapeType,
1666 tools::Rectangle& rInnerDist )
1667 {
1668 /*
1669 attributes to be set on the frame
1670 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1671 SwFormatFrameSize if not set, set here
1672 SvxLRSpaceItem set here
1673 SvxULSpaceItem set here
1674 SvxOpaqueItem (Currently not possible for frames! khz 10.2.1999)
1675 SwFormatSurround already set
1676 SwFormatVertOrient already set
1677 SwFormatHoriOrient already set
1678 SwFormatAnchor already set
1679 SvxBoxItem set here
1680 SvxBrushItem set here
1681 SvxShadowItem set here
1682 */
1683
1684 // 1. GraphicObject of documents?
1685 GrafikCtor();
1686
1687 const SfxItemSet& rOldSet = pSdrObj->GetMergedItemSet();
1688
1689 // some Items can be taken over directly
1690 static sal_uInt16 const aDirectMatch[]
1691 {
1692 RES_LR_SPACE, // outer spacing left/right: SvxLRSpaceItem
1693 RES_UL_SPACE // outer spacing top/bottom: SvxULSpaceItem
1694 };
1695 const SfxPoolItem* pPoolItem;
1696 for(sal_uInt16 i : aDirectMatch)
1697 if( SfxItemState::SET == rOldSet.GetItemState(i, false, &pPoolItem) )
1698 {
1699 rFlySet.Put( *pPoolItem );
1700 }
1701
1702 // take new XATTR items directly. Skip old RES_BACKGROUND if new FILLSTYLE taken.
1703 bool bSkipResBackground = false;
1704 SfxItemPool* pPool = rFlySet.GetPool();
1705 if ( pPool )
1706 {
1707 for ( sal_uInt16 i = XATTR_START; i < XATTR_END; ++i )
1708 {
1709 // Not all Fly types support XATTRs - skip unsupported attributes
1710 SfxItemPool* pAttrPool = pPool->GetMasterPool();
1711 while ( pAttrPool && !pAttrPool->IsInRange(i) )
1712 pAttrPool = pAttrPool->GetSecondaryPool();
1713 if ( !pAttrPool )
1714 continue;
1715
1716 if ( SfxItemState::SET == rOldSet.GetItemState(i, false, &pPoolItem) )
1717 {
1718 rFlySet.Put( *pPoolItem );
1719 if ( i == XATTR_FILLSTYLE )
1720 {
1721 const drawing::FillStyle eFill = static_cast<const XFillStyleItem*>(pPoolItem)->GetValue();
1722 // Transparency forced in certain situations when fillstyle is none - use old logic for that case still
1723 // which is especially needed for export purposes (tdf112618).
1724 if ( eFill != drawing::FillStyle_NONE )
1725 bSkipResBackground = true;
1726 }
1727 }
1728 }
1729 }
1730
1731 // now calculate the borders and build the box: The unit is needed for the
1732 // frame SIZE!
1733 SvxBoxItem aBox(sw::util::ItemGet<SvxBoxItem>(rFlySet, RES_BOX));
1734 // dashed or solid becomes solid
1735 // WW-default: 0.75 pt = 15 twips
1736 sal_Int32 nLineThick = 15, nOutside=0;
1737
1738 // check if LineStyle is *really* set!
1739 const SfxPoolItem* pItem;
1740
1741 SfxItemState eState = rOldSet.GetItemState(XATTR_LINESTYLE,true,&pItem);
1742 if( eState == SfxItemState::SET )
1743 {
1744 // Now, that we know there is a line style we will make use the
1745 // parameter given to us when calling the method... :-)
1746 const Color aLineColor = rOldSet.Get(XATTR_LINECOLOR).GetColorValue();
1747 nLineThick = WW8ITEMVALUE(rOldSet, XATTR_LINEWIDTH, XLineWidthItem);
1748
1749 if( !nLineThick )
1750 nLineThick = 1; // for Writer, zero is "no border", so set a minimal value
1751
1752 nOutside = MatchSdrBoxIntoFlyBoxItem(aLineColor, eLineStyle,
1753 eDashing, eShapeType, nLineThick, aBox);
1754 }
1755
1756 rInnerDist.AdjustLeft(nLineThick );
1757 rInnerDist.AdjustTop(nLineThick );
1758 rInnerDist.AdjustRight(nLineThick );
1759 rInnerDist.AdjustBottom(nLineThick );
1760
1761 rInnerDist.AdjustLeft( -(aBox.CalcLineWidth( SvxBoxItemLine::LEFT )) );
1762 rInnerDist.AdjustTop( -(aBox.CalcLineWidth( SvxBoxItemLine::TOP )) );
1763 rInnerDist.AdjustRight( -(aBox.CalcLineWidth( SvxBoxItemLine::RIGHT )) );
1764 rInnerDist.AdjustBottom( -(aBox.CalcLineWidth( SvxBoxItemLine::BOTTOM )) );
1765
1766 // set distances from box's border to text contained within the box
1767 if( 0 < rInnerDist.Left() )
1768 aBox.SetDistance( static_cast<sal_uInt16>(rInnerDist.Left()), SvxBoxItemLine::LEFT );
1769 if( 0 < rInnerDist.Top() )
1770 aBox.SetDistance( static_cast<sal_uInt16>(rInnerDist.Top()), SvxBoxItemLine::TOP );
1771 if( 0 < rInnerDist.Right() )
1772 aBox.SetDistance( static_cast<sal_uInt16>(rInnerDist.Right()), SvxBoxItemLine::RIGHT );
1773 if( 0 < rInnerDist.Bottom() )
1774 aBox.SetDistance( static_cast<sal_uInt16>(rInnerDist.Bottom()), SvxBoxItemLine::BOTTOM );
1775
1776 bool bFixSize = !(WW8ITEMVALUE(rOldSet, SDRATTR_TEXT_AUTOGROWHEIGHT,
1777 SdrOnOffItem));
1778
1779 // Size: SwFormatFrameSize
1780 if( SfxItemState::SET != rFlySet.GetItemState(RES_FRM_SIZE, false) )
1781 {
1782 const tools::Rectangle& rSnapRect = pSdrObj->GetSnapRect();
1783 // if necessary adapt width and position of the framework: The
1784 // recorded interior is to remain equally large despite thick edges.
1785 rFlySet.Put( SwFormatFrameSize(bFixSize ? ATT_FIX_SIZE : ATT_VAR_SIZE,
1786 rSnapRect.GetWidth() + 2*nOutside,
1787 rSnapRect.GetHeight() + 2*nOutside) );
1788 }
1789 else // If a size is set, adjust it to consider border thickness
1790 {
1791 SwFormatFrameSize aSize = rFlySet.Get(RES_FRM_SIZE);
1792
1793 SwFormatFrameSize aNewSize(bFixSize ? ATT_FIX_SIZE : ATT_VAR_SIZE,
1794 aSize.GetWidth() + 2*nOutside,
1795 aSize.GetHeight() + 2*nOutside);
1796 aNewSize.SetWidthSizeType(aSize.GetWidthSizeType());
1797 rFlySet.Put( aNewSize );
1798 }
1799
1800 // Sadly word puts escher borders outside the graphic, but orients the
1801 // graphic in relation to the top left inside the border. We don't
1802 if (nOutside)
1803 {
1804 SwFormatHoriOrient aHori = rFlySet.Get(RES_HORI_ORIENT);
1805 aHori.SetPos(MakeSafePositioningValue(aHori.GetPos()-nOutside));
1806 rFlySet.Put(aHori);
1807
1808 SwFormatVertOrient aVert = rFlySet.Get(RES_VERT_ORIENT);
1809 aVert.SetPos(aVert.GetPos()-nOutside);
1810 rFlySet.Put(aVert);
1811 }
1812
1813 // now set the border
1814 rFlySet.Put( aBox );
1815
1816 // shadow of the box: SvxShadowItem
1817 if( WW8ITEMVALUE(rOldSet, SDRATTR_SHADOW, SdrOnOffItem) )
1818 {
1819 SvxShadowItem aShadow( RES_SHADOW );
1820
1821 const Color aShdColor = rOldSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue();
1822 const sal_Int32 nShdDistX = WW8ITEMVALUE(rOldSet, SDRATTR_SHADOWXDIST,
1823 SdrMetricItem);
1824 const sal_Int32 nShdDistY = WW8ITEMVALUE(rOldSet, SDRATTR_SHADOWYDIST,
1825 SdrMetricItem);
1826
1827 aShadow.SetColor( aShdColor );
1828
1829 aShadow.SetWidth(writer_cast<sal_uInt16>((std::abs( nShdDistX) +
1830 std::abs( nShdDistY )) / 2 ));
1831
1832 SvxShadowLocation eShdPosi;
1833 if( 0 <= nShdDistX )
1834 {
1835 if( 0 <= nShdDistY )
1836 eShdPosi = SvxShadowLocation::BottomRight;
1837 else
1838 eShdPosi = SvxShadowLocation::TopRight;
1839 }
1840 else
1841 {
1842 if( 0 <= nShdDistY )
1843 eShdPosi = SvxShadowLocation::BottomLeft;
1844 else
1845 eShdPosi = SvxShadowLocation::TopLeft;
1846 }
1847 aShadow.SetLocation( eShdPosi );
1848
1849 rFlySet.Put( aShadow );
1850 }
1851 SvxBrushItem aBrushItem(COL_WHITE, RES_BACKGROUND);
1852 bool bBrushItemOk = false;
1853 sal_uInt8 nTrans = 0;
1854
1855 // Separate transparency
1856 eState = rOldSet.GetItemState(XATTR_FILLTRANSPARENCE, true, &pItem);
1857 if (!bSkipResBackground && eState == SfxItemState::SET)
1858 {
1859 sal_uInt16 nRes = WW8ITEMVALUE(rOldSet, XATTR_FILLTRANSPARENCE,
1860 XFillTransparenceItem);
1861 nTrans = sal_uInt8((nRes * 0xFE) / 100);
1862 aBrushItem.GetColor().SetTransparency(nTrans);
1863 bBrushItemOk = true;
1864 }
1865
1866 // Background: SvxBrushItem
1867 eState = rOldSet.GetItemState(XATTR_FILLSTYLE, true, &pItem);
1868 if (!bSkipResBackground && eState == SfxItemState::SET)
1869 {
1870 const drawing::FillStyle eFill = static_cast<const XFillStyleItem*>(pItem)->GetValue();
1871
1872 switch (eFill)
1873 {
1874 default:
1875 case drawing::FillStyle_NONE:
1876 // Writer graphics don't have it yet
1877 if (eShapeType != mso_sptPictureFrame)
1878 {
1879 aBrushItem.GetColor().SetTransparency(0xFE);
1880 bBrushItemOk = true;
1881 }
1882 break;
1883 case drawing::FillStyle_SOLID:
1884 case drawing::FillStyle_GRADIENT:
1885 {
1886 const Color aColor =
1887 rOldSet.Get(XATTR_FILLCOLOR).GetColorValue();
1888 aBrushItem.SetColor(aColor);
1889
1890 if (bBrushItemOk) // has trans
1891 aBrushItem.GetColor().SetTransparency(nTrans);
1892
1893 bBrushItemOk = true;
1894 }
1895 break;
1896 case drawing::FillStyle_HATCH:
1897 break;
1898 case drawing::FillStyle_BITMAP:
1899 {
1900 GraphicObject aGrfObj(rOldSet.Get(XATTR_FILLBITMAP).GetGraphicObject());
1901 const bool bTile(WW8ITEMVALUE(rOldSet, XATTR_FILLBMP_TILE, SfxBoolItem));
1902
1903 if(bBrushItemOk) // has trans
1904 {
1905 GraphicAttr aAttr(aGrfObj.GetAttr());
1906
1907 aAttr.SetTransparency(nTrans);
1908 aGrfObj.SetAttr(aAttr);
1909 }
1910
1911 aBrushItem.SetGraphicObject(aGrfObj);
1912 aBrushItem.SetGraphicPos(bTile ? GPOS_TILED : GPOS_AREA);
1913 bBrushItemOk = true;
1914 }
1915 break;
1916 }
1917 }
1918
1919 if (bBrushItemOk)
1920 rFlySet.Put(aBrushItem);
1921 }
1922
AdjustLRWrapForWordMargins(const SvxMSDffImportRec & rRecord,SvxLRSpaceItem & rLR)1923 void SwWW8ImplReader::AdjustLRWrapForWordMargins(
1924 const SvxMSDffImportRec &rRecord, SvxLRSpaceItem &rLR)
1925 {
1926 sal_uInt32 nXRelTo = SvxMSDffImportRec::RELTO_DEFAULT;
1927 if ( rRecord.nXRelTo )
1928 {
1929 nXRelTo = rRecord.nXRelTo.get();
1930 }
1931
1932 // Left adjustments - if horizontally aligned to left of
1933 // margin or column then remove the left wrapping
1934 if (rRecord.nXAlign == 1)
1935 {
1936 if ((nXRelTo == 0) || (nXRelTo == 2))
1937 rLR.SetLeft(sal_uInt16(0));
1938 }
1939
1940 // Right adjustments - if horizontally aligned to right of
1941 // margin or column then remove the right wrapping
1942 if (rRecord.nXAlign == 3)
1943 {
1944 if ((nXRelTo == 0) || (nXRelTo == 2))
1945 rLR.SetRight(sal_uInt16(0));
1946 }
1947
1948 // Inside margin, remove left wrapping
1949 if ((rRecord.nXAlign == 4) && (nXRelTo == 0))
1950 {
1951 rLR.SetLeft(sal_uInt16(0));
1952 }
1953
1954 // Outside margin, remove left wrapping
1955 if ((rRecord.nXAlign == 5) && (nXRelTo == 0))
1956 {
1957 rLR.SetRight(sal_uInt16(0));
1958 }
1959 }
1960
AdjustULWrapForWordMargins(const SvxMSDffImportRec & rRecord,SvxULSpaceItem & rUL)1961 void SwWW8ImplReader::AdjustULWrapForWordMargins(
1962 const SvxMSDffImportRec &rRecord, SvxULSpaceItem &rUL)
1963 {
1964 sal_uInt32 nYRelTo = SvxMSDffImportRec::RELTO_DEFAULT;
1965 if ( rRecord.nYRelTo )
1966 {
1967 nYRelTo = rRecord.nYRelTo.get();
1968 }
1969
1970 // Top adjustment - remove upper wrapping if aligned to page
1971 // printable area or to page
1972 if (rRecord.nYAlign == 1)
1973 {
1974 if ((nYRelTo == 0) || (nYRelTo == 1))
1975 rUL.SetUpper(sal_uInt16(0));
1976 }
1977
1978 // Bottom adjustment - remove bottom wrapping if aligned to page or
1979 // printable area or to page
1980 if (rRecord.nYAlign == 3)
1981 {
1982 if ((nYRelTo == 0) || (nYRelTo == 1))
1983 rUL.SetLower(sal_uInt16(0));
1984 }
1985
1986 // Remove top margin if aligned vertically inside margin
1987 if ((rRecord.nYAlign == 4) && (nYRelTo == 0))
1988 rUL.SetUpper(sal_uInt16(0));
1989 }
1990
MapWrapIntoFlyFormat(SvxMSDffImportRec const * pRecord,SwFrameFormat * pFlyFormat)1991 void SwWW8ImplReader::MapWrapIntoFlyFormat(SvxMSDffImportRec const * pRecord,
1992 SwFrameFormat* pFlyFormat)
1993 {
1994 if (!pRecord || !pFlyFormat)
1995 return;
1996
1997 if (pRecord->nDxWrapDistLeft || pRecord->nDxWrapDistRight)
1998 {
1999 SvxLRSpaceItem aLR(writer_cast<sal_uInt16>(pRecord->nDxWrapDistLeft),
2000 writer_cast<sal_uInt16>(pRecord->nDxWrapDistRight), 0, 0, RES_LR_SPACE);
2001 AdjustLRWrapForWordMargins(*pRecord, aLR);
2002 pFlyFormat->SetFormatAttr(aLR);
2003 }
2004 if (pRecord->nDyWrapDistTop || pRecord->nDyWrapDistBottom)
2005 {
2006 SvxULSpaceItem aUL(writer_cast<sal_uInt16>(pRecord->nDyWrapDistTop),
2007 writer_cast<sal_uInt16>(pRecord->nDyWrapDistBottom), RES_UL_SPACE);
2008 AdjustULWrapForWordMargins(*pRecord, aUL);
2009 pFlyFormat->SetFormatAttr(aUL);
2010 }
2011
2012 // If we are contoured and have a custom polygon...
2013 if (pRecord->pWrapPolygon && pFlyFormat->GetSurround().IsContour())
2014 {
2015 if (SwNoTextNode *pNd = GetNoTextNodeFromSwFrameFormat(*pFlyFormat))
2016 {
2017
2018 /*
2019 Gather round children and hear of a tale that will raise the
2020 hairs on the back of your neck this dark halloween night.
2021
2022 There is a polygon in word that describes the wrapping around
2023 the graphic.
2024
2025 Here are some sample values for the simplest case of a square
2026 around some solid coloured graphics
2027
2028 X Y Pixel size of graphic
2029 TopLeft -54 21600 400x400
2030 Bottom Right 0 21546
2031
2032 TopLeft -108 21600 200x200
2033 Bottom Right 0 21492
2034
2035 TopLeft -216 21600 100x100
2036 Bottom Right 0 21384
2037
2038 TopLeft -432 21600 50x50
2039 Bottom Right 0 21168
2040
2041 TopLeft -76 21600 283x212
2042 Bottom Right 0 21498
2043
2044 So given that the size of the values remains pretty much the
2045 same despite the size of the graphic, we can tell that the
2046 polygon is measured in units that are independent of the
2047 graphic. But why does the left corner move a different value
2048 to the left each time, and why does the bottom move upwards
2049 each time, when the right and top remain at the same value ?
2050
2051 I have no idea, but clearly once we calculate the values out
2052 we see that the left margin is always a fixed realworld
2053 distance from the true left and the polygon bottom is the same
2054 fixed value from the bottom. i.e. 15twips.
2055
2056 So here we take our word provided polygon, shift it to the
2057 right by 15twips and rescale it widthwise to shrink the width
2058 a little to fit the now moved right margin back to where it
2059 was, and stretch the height a little to make the bottom move
2060 down the missing 15twips then we get a polygon that matches
2061 what I actually see in word
2062 */
2063
2064 tools::PolyPolygon aPoly(*pRecord->pWrapPolygon);
2065 const Size &rSize = pNd->GetTwipSize();
2066 /*
2067 Move to the left by 15twips, and rescale to
2068 a) shrink right bound back to orig position
2069 b) stretch bottom bound to where I think it should have been
2070 in the first place
2071 */
2072 Fraction aMoveHack(ww::nWrap100Percent, rSize.Width());
2073 aMoveHack *= Fraction(15, 1);
2074 long nMove(aMoveHack);
2075 aPoly.Move(nMove, 0);
2076
2077 Fraction aHackX(ww::nWrap100Percent, ww::nWrap100Percent + nMove);
2078 Fraction aHackY(ww::nWrap100Percent, ww::nWrap100Percent - nMove);
2079 aPoly.Scale(double(aHackX), double(aHackY));
2080
2081 // Turn polygon back into units that match the graphic's
2082 const Size &rOrigSize = pNd->GetGraphic().GetPrefSize();
2083 Fraction aMapPolyX(rOrigSize.Width(), ww::nWrap100Percent);
2084 Fraction aMapPolyY(rOrigSize.Height(), ww::nWrap100Percent);
2085 aPoly.Scale(double(aMapPolyX), double(aMapPolyY));
2086
2087 // #i47277# - contour is already in unit of the
2088 // graphic preferred unit. Thus, call method <SetContour(..)>
2089 pNd->SetContour(&aPoly);
2090 }
2091 }
2092 else if (pFlyFormat->GetSurround().IsContour())
2093 {
2094 // Contour is enabled, but no polygon is set: disable contour, because Word does not
2095 // Writer-style auto-contour in that case.
2096 SwFormatSurround aSurround(pFlyFormat->GetSurround());
2097 aSurround.SetContour(false);
2098 pFlyFormat->SetFormatAttr(aSurround);
2099 }
2100 }
2101
lcl_ConvertCrop(sal_uInt32 const nCrop,sal_Int32 const nSize)2102 static sal_Int32 lcl_ConvertCrop(sal_uInt32 const nCrop, sal_Int32 const nSize)
2103 {
2104 // cast to sal_Int32 to handle negative crop properly
2105 sal_Int32 const nIntegral(static_cast<sal_Int32>(nCrop) >> 16);
2106 // fdo#77454: heuristic to detect mangled values written by old OOo/LO
2107 if (abs(nIntegral) >= 50) // FIXME: what's a good cut-off?
2108 {
2109 SAL_INFO("sw.ww8", "ignoring suspiciously large crop: " << nIntegral);
2110 return 0;
2111 }
2112 return (nIntegral * nSize) + (((nCrop & 0xffff) * nSize) >> 16);
2113 }
2114
2115 void
SetAttributesAtGrfNode(SvxMSDffImportRec const * const pRecord,SwFrameFormat const * pFlyFormat,WW8_FSPA const * pF)2116 SwWW8ImplReader::SetAttributesAtGrfNode(SvxMSDffImportRec const*const pRecord,
2117 SwFrameFormat const *pFlyFormat, WW8_FSPA const *pF )
2118 {
2119 const SwNodeIndex* pIdx = pFlyFormat->GetContent(false).GetContentIdx();
2120 SwGrfNode *const pGrfNd(
2121 pIdx ? m_rDoc.GetNodes()[pIdx->GetIndex() + 1]->GetGrfNode() : nullptr);
2122 if (pGrfNd)
2123 {
2124 Size aSz(pGrfNd->GetTwipSize());
2125 // use type <sal_uInt64> instead of sal_uLong to get correct results
2126 // in the following calculations.
2127 sal_uInt64 nHeight = aSz.Height();
2128 sal_uInt64 nWidth = aSz.Width();
2129 if (!nWidth && pF)
2130 nWidth = o3tl::saturating_sub(pF->nXaRight, pF->nXaLeft);
2131 else if (!nHeight && pF)
2132 nHeight = o3tl::saturating_sub(pF->nYaBottom, pF->nYaTop);
2133
2134 if( pRecord->nCropFromTop || pRecord->nCropFromBottom ||
2135 pRecord->nCropFromLeft || pRecord->nCropFromRight )
2136 {
2137 SwCropGrf aCrop; // Cropping is stored in 'fixed floats'
2138 // 16.16 (fraction times total
2139 if( pRecord->nCropFromTop ) // image width or height resp.)
2140 {
2141 aCrop.SetTop(lcl_ConvertCrop(pRecord->nCropFromTop, nHeight));
2142 }
2143 if( pRecord->nCropFromBottom )
2144 {
2145 aCrop.SetBottom(lcl_ConvertCrop(pRecord->nCropFromBottom, nHeight));
2146 }
2147 if( pRecord->nCropFromLeft )
2148 {
2149 aCrop.SetLeft(lcl_ConvertCrop(pRecord->nCropFromLeft, nWidth));
2150 }
2151 if( pRecord->nCropFromRight )
2152 {
2153 aCrop.SetRight(lcl_ConvertCrop(pRecord->nCropFromRight, nWidth));
2154 }
2155
2156 pGrfNd->SetAttr( aCrop );
2157 }
2158
2159 bool bFlipH(pRecord->nFlags & ShapeFlag::FlipH);
2160 bool bFlipV(pRecord->nFlags & ShapeFlag::FlipV);
2161 if ( bFlipH || bFlipV )
2162 {
2163 SwMirrorGrf aMirror = pGrfNd->GetSwAttrSet().GetMirrorGrf();
2164 if( bFlipH )
2165 {
2166 if( bFlipV )
2167 aMirror.SetValue(MirrorGraph::Both);
2168 else
2169 aMirror.SetValue(MirrorGraph::Vertical);
2170 }
2171 else
2172 aMirror.SetValue(MirrorGraph::Horizontal);
2173
2174 pGrfNd->SetAttr( aMirror );
2175 }
2176
2177 if (pRecord->pObj)
2178 {
2179 const SfxItemSet& rOldSet = pRecord->pObj->GetMergedItemSet();
2180 // contrast
2181 if (WW8ITEMVALUE(rOldSet, SDRATTR_GRAFCONTRAST,
2182 SdrGrafContrastItem))
2183 {
2184 SwContrastGrf aContrast(
2185 WW8ITEMVALUE(rOldSet,
2186 SDRATTR_GRAFCONTRAST, SdrGrafContrastItem));
2187 pGrfNd->SetAttr( aContrast );
2188 }
2189
2190 // luminance
2191 if (WW8ITEMVALUE(rOldSet, SDRATTR_GRAFLUMINANCE,
2192 SdrGrafLuminanceItem))
2193 {
2194 SwLuminanceGrf aLuminance(WW8ITEMVALUE(rOldSet,
2195 SDRATTR_GRAFLUMINANCE, SdrGrafLuminanceItem));
2196 pGrfNd->SetAttr( aLuminance );
2197 }
2198 // gamma
2199 if (WW8ITEMVALUE(rOldSet, SDRATTR_GRAFGAMMA, SdrGrafGamma100Item))
2200 {
2201 double fVal = WW8ITEMVALUE(rOldSet, SDRATTR_GRAFGAMMA,
2202 SdrGrafGamma100Item);
2203 pGrfNd->SetAttr(SwGammaGrf(fVal/100.));
2204 }
2205
2206 // drawmode
2207 auto nGrafMode = rOldSet.GetItem<SdrGrafModeItem>(SDRATTR_GRAFMODE)->GetValue();
2208 if ( nGrafMode != GraphicDrawMode::Standard)
2209 {
2210 SwDrawModeGrf aDrawMode( nGrafMode );
2211 pGrfNd->SetAttr( aDrawMode );
2212 }
2213 }
2214 }
2215 }
2216
CreateContactObject(SwFrameFormat * pFlyFormat)2217 SdrObject* SwWW8ImplReader::CreateContactObject(SwFrameFormat* pFlyFormat)
2218 {
2219 if (pFlyFormat)
2220 {
2221 SdrObject* pNewObject = m_bNewDoc ? nullptr : pFlyFormat->FindRealSdrObject();
2222 if (!pNewObject)
2223 pNewObject = pFlyFormat->FindSdrObject();
2224 if (!pNewObject && dynamic_cast< const SwFlyFrameFormat *>( pFlyFormat ) != nullptr)
2225 {
2226 SwFlyDrawContact* pContactObject(static_cast<SwFlyFrameFormat*>(pFlyFormat)->GetOrCreateContact());
2227 pNewObject = pContactObject->GetMaster();
2228 }
2229 return pNewObject;
2230 }
2231 return nullptr;
2232 }
2233
2234 // Miserable miserable hack to fudge word's graphic layout in RTL mode to ours.
MiserableRTLGraphicsHack(SwTwips & rLeft,SwTwips nWidth,sal_Int16 eHoriOri,sal_Int16 eHoriRel)2235 bool SwWW8ImplReader::MiserableRTLGraphicsHack(SwTwips &rLeft, SwTwips nWidth,
2236 sal_Int16 eHoriOri, sal_Int16 eHoriRel)
2237 {
2238 if (!IsRightToLeft())
2239 return false;
2240 return RTLGraphicsHack(rLeft, nWidth, eHoriOri, eHoriRel,
2241 m_aSectionManager.GetPageLeft(),
2242 m_aSectionManager.GetPageRight(),
2243 m_aSectionManager.GetPageWidth());
2244 }
2245
ProcessEscherAlign(SvxMSDffImportRec * pRecord,WW8_FSPA * pFSPA,SfxItemSet & rFlySet)2246 RndStdIds SwWW8ImplReader::ProcessEscherAlign(SvxMSDffImportRec* pRecord,
2247 WW8_FSPA *pFSPA, SfxItemSet &rFlySet)
2248 {
2249 OSL_ENSURE(pRecord || pFSPA, "give me something! to work with for anchoring");
2250 if (!pRecord && !pFSPA)
2251 return RndStdIds::FLY_AT_PAGE;
2252 bool bCurSectionVertical = m_aSectionManager.CurrentSectionIsVertical();
2253
2254 SvxMSDffImportRec aRecordFromFSPA;
2255 if (!pRecord)
2256 pRecord = &aRecordFromFSPA;
2257 if (!(pRecord->nXRelTo) && pFSPA)
2258 {
2259 pRecord->nXRelTo = sal_Int32(pFSPA->nbx);
2260 }
2261 if (!(pRecord->nYRelTo) && pFSPA)
2262 {
2263 pRecord->nYRelTo = sal_Int32(pFSPA->nby);
2264 }
2265
2266 // nXAlign - abs. Position, Left, Centered, Right, Inside, Outside
2267 // nYAlign - abs. Position, Top, Centered, Bottom, Inside, Outside
2268
2269 // nXRelTo - Page printable area, Page, Column, Character
2270 // nYRelTo - Page printable area, Page, Paragraph, Line
2271
2272 const sal_uInt32 nCntXAlign = 6;
2273 const sal_uInt32 nCntYAlign = 6;
2274
2275 const sal_uInt32 nCntRelTo = 4;
2276
2277 sal_uInt32 nXAlign = nCntXAlign > pRecord->nXAlign ? pRecord->nXAlign : 1;
2278 sal_uInt32 nYAlign = nCntYAlign > pRecord->nYAlign ? pRecord->nYAlign : 1;
2279
2280 if (pFSPA)
2281 {
2282 // #i52565# - try to handle special case for objects in tables regarding its X Rel
2283
2284 // if X and Y Rel values are on default take it as a hint, that they have not been set
2285 // by <SwMSDffManager::ProcessObj(..)>
2286 const bool bXYRelHaveDefaultValues = pRecord->nXRelTo.get() == 2 && pRecord->nYRelTo.get() == 2;
2287 if ( bXYRelHaveDefaultValues
2288 && m_nInTable > 0
2289 && !bCurSectionVertical )
2290 {
2291 if ( sal_uInt32(pFSPA->nby) != pRecord->nYRelTo )
2292 {
2293 pRecord->nYRelTo = sal_uInt32(pFSPA->nby);
2294 }
2295 }
2296 }
2297
2298 sal_uInt32 nXRelTo = (pRecord->nXRelTo && nCntRelTo > pRecord->nXRelTo) ? pRecord->nXRelTo.get() : 1;
2299 sal_uInt32 nYRelTo = (pRecord->nYRelTo && nCntRelTo > pRecord->nYRelTo) ? pRecord->nYRelTo.get() : 1;
2300
2301 RndStdIds eAnchor = IsInlineEscherHack() ? RndStdIds::FLY_AS_CHAR : RndStdIds::FLY_AT_CHAR; // #i43718#
2302
2303 SwFormatAnchor aAnchor( eAnchor );
2304 aAnchor.SetAnchor( m_pPaM->GetPoint() );
2305 rFlySet.Put( aAnchor );
2306
2307 if (pFSPA)
2308 {
2309 // #i18732#
2310 // Given new layout where everything is changed to be anchored to
2311 // character the following 4 tables may need to be changed.
2312
2313 // horizontal Adjustment
2314 static const sal_Int16 aHoriOriTab[ nCntXAlign ] =
2315 {
2316 text::HoriOrientation::NONE, // From left position
2317 text::HoriOrientation::LEFT, // left
2318 text::HoriOrientation::CENTER, // centered
2319 text::HoriOrientation::RIGHT, // right
2320 // #i36649#
2321 // - inside -> text::HoriOrientation::LEFT and outside -> text::HoriOrientation::RIGHT
2322 text::HoriOrientation::LEFT, // inside
2323 text::HoriOrientation::RIGHT // outside
2324 };
2325
2326 // generic vertical Adjustment
2327 static const sal_Int16 aVertOriTab[ nCntYAlign ] =
2328 {
2329 text::VertOrientation::NONE, // From Top position
2330 text::VertOrientation::TOP, // top
2331 text::VertOrientation::CENTER, // centered
2332 text::VertOrientation::BOTTOM, // bottom
2333 text::VertOrientation::LINE_TOP, // inside (obscure)
2334 text::VertOrientation::LINE_BOTTOM // outside (obscure)
2335 };
2336
2337 // #i22673# - to-line vertical alignment
2338 static const sal_Int16 aToLineVertOriTab[ nCntYAlign ] =
2339 {
2340 text::VertOrientation::NONE, // below
2341 text::VertOrientation::LINE_BOTTOM, // top
2342 text::VertOrientation::LINE_CENTER, // centered
2343 text::VertOrientation::LINE_TOP, // bottom
2344 text::VertOrientation::LINE_BOTTOM, // inside (obscure)
2345 text::VertOrientation::LINE_TOP // outside (obscure)
2346 };
2347
2348 // Adjustment is horizontally relative to...
2349 static const sal_Int16 aHoriRelOriTab[nCntRelTo] =
2350 {
2351 text::RelOrientation::PAGE_PRINT_AREA, // 0 is page textarea margin
2352 text::RelOrientation::PAGE_FRAME, // 1 is page margin
2353 text::RelOrientation::FRAME, // 2 is relative to column
2354 text::RelOrientation::CHAR // 3 is relative to character
2355 };
2356
2357 // Adjustment is vertically relative to...
2358 // #i22673# - adjustment for new vertical alignment at top of line.
2359 static const sal_Int16 aVertRelOriTab[nCntRelTo] =
2360 {
2361 text::RelOrientation::PAGE_PRINT_AREA, // 0 is page textarea margin
2362 text::RelOrientation::PAGE_FRAME, // 1 is page margin
2363 text::RelOrientation::FRAME, // 2 is relative to paragraph
2364 text::RelOrientation::TEXT_LINE // 3 is relative to line
2365 };
2366
2367 sal_Int16 eHoriOri = aHoriOriTab[ nXAlign ];
2368 sal_Int16 eHoriRel = aHoriRelOriTab[ nXRelTo ];
2369
2370 // #i36649# - adjustments for certain alignments
2371 if ( eHoriOri == text::HoriOrientation::LEFT && eHoriRel == text::RelOrientation::PAGE_FRAME )
2372 {
2373 // convert 'left to page' to 'from left -<width> to page text area'
2374 eHoriOri = text::HoriOrientation::NONE;
2375 eHoriRel = text::RelOrientation::PAGE_PRINT_AREA;
2376 const long nWidth = pFSPA->nXaRight - pFSPA->nXaLeft;
2377 pFSPA->nXaLeft = -nWidth;
2378 pFSPA->nXaRight = 0;
2379 }
2380 else if ( eHoriOri == text::HoriOrientation::RIGHT && eHoriRel == text::RelOrientation::PAGE_FRAME )
2381 {
2382 // convert 'right to page' to 'from left 0 to right page border'
2383 eHoriOri = text::HoriOrientation::NONE;
2384 eHoriRel = text::RelOrientation::PAGE_RIGHT;
2385 const long nWidth = pFSPA->nXaRight - pFSPA->nXaLeft;
2386 pFSPA->nXaLeft = 0;
2387 pFSPA->nXaRight = nWidth;
2388 }
2389
2390 // #i24255# - position of floating screen objects in
2391 // R2L layout are given in L2R layout, thus convert them of all
2392 // floating screen objects, which are imported.
2393 {
2394 // Miserable miserable hack.
2395 SwTwips nWidth = o3tl::saturating_sub(pFSPA->nXaRight, pFSPA->nXaLeft);
2396 SwTwips nLeft = pFSPA->nXaLeft;
2397 if (MiserableRTLGraphicsHack(nLeft, nWidth, eHoriOri,
2398 eHoriRel))
2399 {
2400 pFSPA->nXaLeft = nLeft;
2401 pFSPA->nXaRight = pFSPA->nXaLeft + nWidth;
2402 }
2403 }
2404
2405 // if the object is anchored inside a table cell, is horizontal aligned
2406 // at frame|character and has wrap through, but its attribute
2407 // 'layout in table cell' isn't set, convert its horizontal alignment to page text area.
2408 // #i84783# - use new method <IsObjectLayoutInTableCell()>
2409 if ( m_nInTable &&
2410 ( eHoriRel == text::RelOrientation::FRAME || eHoriRel == text::RelOrientation::CHAR ) &&
2411 pFSPA->nwr == 3 &&
2412 !IsObjectLayoutInTableCell( pRecord->nLayoutInTableCell ) )
2413 {
2414 eHoriRel = text::RelOrientation::PAGE_PRINT_AREA;
2415 }
2416
2417 // Writer honours this wrap distance when aligned as "left" or "right",
2418 // Word doesn't. Writer doesn't honour it when its "from left".
2419 if (eHoriOri == text::HoriOrientation::LEFT)
2420 pRecord->nDxWrapDistLeft=0;
2421 else if (eHoriOri == text::HoriOrientation::RIGHT)
2422 pRecord->nDxWrapDistRight=0;
2423
2424 sal_Int16 eVertRel;
2425
2426 eVertRel = aVertRelOriTab[ nYRelTo ]; // #i18732#
2427 if ( bCurSectionVertical && nYRelTo == 2 )
2428 eVertRel = text::RelOrientation::PAGE_PRINT_AREA;
2429 // #i22673# - fill <eVertOri> in dependence of <eVertRel>
2430 sal_Int16 eVertOri;
2431 if ( eVertRel == text::RelOrientation::TEXT_LINE )
2432 {
2433 eVertOri = aToLineVertOriTab[ nYAlign ];
2434 }
2435 else
2436 {
2437 eVertOri = aVertOriTab[ nYAlign ];
2438 }
2439
2440 // Below line in word is a positive value, while in writer its
2441 // negative
2442 long nYPos = pFSPA->nYaTop;
2443 // #i22673#
2444 if ((eVertRel == text::RelOrientation::TEXT_LINE) && (eVertOri == text::VertOrientation::NONE))
2445 nYPos = -nYPos;
2446
2447 SwFormatHoriOrient aHoriOri(MakeSafePositioningValue( bCurSectionVertical ? nYPos : pFSPA->nXaLeft ),
2448 bCurSectionVertical ? eVertOri : eHoriOri,
2449 bCurSectionVertical ? eVertRel : eHoriRel);
2450 if( 4 <= nXAlign )
2451 aHoriOri.SetPosToggle(true);
2452 rFlySet.Put( aHoriOri );
2453
2454 rFlySet.Put(SwFormatVertOrient(MakeSafePositioningValue( !bCurSectionVertical ? nYPos : -pFSPA->nXaRight ),
2455 !bCurSectionVertical ? eVertOri : eHoriOri,
2456 !bCurSectionVertical ? eVertRel : eHoriRel ));
2457 }
2458
2459 return eAnchor;
2460 }
2461
2462 // #i84783#
IsObjectLayoutInTableCell(const sal_uInt32 nLayoutInTableCell) const2463 bool SwWW8ImplReader::IsObjectLayoutInTableCell( const sal_uInt32 nLayoutInTableCell ) const
2464 {
2465 bool bIsObjectLayoutInTableCell = false;
2466
2467 if ( m_bVer8 )
2468 {
2469 sal_uInt16 nWWVersion = m_xWwFib->m_nProduct & 0xE000;
2470 if (nWWVersion == 0)
2471 {
2472 // 0 nProduct can happen for Word >97 as well, check cswNew in this case instead.
2473 if (m_xWwFib->m_cswNew > 0)
2474 {
2475 // This is Word >=2000.
2476 nWWVersion = 0x2000;
2477 }
2478 }
2479
2480 switch ( nWWVersion )
2481 {
2482 case 0x0000: // version 8 aka Microsoft Word 97
2483 {
2484 bIsObjectLayoutInTableCell = false;
2485 OSL_ENSURE( nLayoutInTableCell == 0xFFFFFFFF,
2486 "no explicit object attribute layout in table cell expected." );
2487 }
2488 break;
2489 case 0x2000: // version 9 aka Microsoft Word 2000
2490 case 0x4000: // version 10 aka Microsoft Word 2002
2491 case 0x6000: // version 11 aka Microsoft Word 2003
2492 case 0x8000: // version 12 aka Microsoft Word 2007
2493 case 0xC000: // version 14 aka Microsoft Word 2010
2494 {
2495 // #i98037#
2496 // adjustment of conditions needed after deeper analysis of
2497 // certain test cases.
2498 if ( nLayoutInTableCell == 0xFFFFFFFF || // no explicit attribute value given
2499 nLayoutInTableCell == 0x80008000 ||
2500 ( nLayoutInTableCell & 0x02000000 &&
2501 !(nLayoutInTableCell & 0x80000000 ) ) )
2502 {
2503 bIsObjectLayoutInTableCell = true;
2504 }
2505 else
2506 {
2507 // Documented in [MS-ODRAW], 2.3.4.44 "Group Shape Boolean Properties".
2508 bool fUsefLayoutInCell = (nLayoutInTableCell & 0x80000000) >> 31;
2509 bool fLayoutInCell = (nLayoutInTableCell & 0x8000) >> 15;
2510 bIsObjectLayoutInTableCell = fUsefLayoutInCell && fLayoutInCell;
2511 }
2512 }
2513 break;
2514 default:
2515 {
2516 OSL_FAIL( "unknown version." );
2517 }
2518 }
2519 }
2520
2521 return bIsObjectLayoutInTableCell;
2522 }
2523
Read_GrafLayer(long nGrafAnchorCp)2524 SwFrameFormat* SwWW8ImplReader::Read_GrafLayer( long nGrafAnchorCp )
2525 {
2526 if( m_nIniFlags & WW8FL_NO_GRAFLAYER )
2527 return nullptr;
2528
2529 ::SetProgressState(m_nProgress, m_pDocShell); // Update
2530
2531 m_nDrawCpO = 0;
2532 m_bDrawCpOValid = m_xWwFib->GetBaseCp(m_xPlcxMan->GetManType() == MAN_HDFT ? MAN_TXBX_HDFT : MAN_TXBX, &m_nDrawCpO);
2533
2534 GrafikCtor();
2535
2536 WW8PLCFspecial* pPF = m_xPlcxMan->GetFdoa();
2537 if( !pPF )
2538 {
2539 OSL_ENSURE( false, "Where is the graphic (1) ?" );
2540 return nullptr;
2541 }
2542
2543 if( m_bVer67 )
2544 {
2545 long nOldPos = m_pStrm->Tell();
2546
2547 m_nDrawXOfs = m_nDrawYOfs = 0;
2548 ReadGrafLayer1( pPF, nGrafAnchorCp );
2549
2550 m_pStrm->Seek( nOldPos );
2551 return nullptr;
2552 }
2553
2554 // Normal case of Word 8+ version stuff
2555 pPF->SeekPos( nGrafAnchorCp );
2556
2557 WW8_FC nStartFc;
2558 void* pF0;
2559 if( !pPF->Get( nStartFc, pF0 ) ){
2560 OSL_ENSURE( false, "+Where is the graphic (2) ?" );
2561 return nullptr;
2562 }
2563
2564 WW8_FSPA_SHADOW* pFS = static_cast<WW8_FSPA_SHADOW*>(pF0);
2565 WW8_FSPA* pF;
2566 WW8_FSPA aFSFA;
2567 pF = &aFSFA;
2568 WW8FSPAShadowToReal( pFS, pF );
2569 if( !pF->nSpId )
2570 {
2571 OSL_ENSURE( false, "+Where is the graphic (3) ?" );
2572 return nullptr;
2573 }
2574
2575 if (!m_xMSDffManager->GetModel())
2576 m_xMSDffManager->SetModel(m_pDrawModel, 1440);
2577
2578 tools::Rectangle aRect(pF->nXaLeft, pF->nYaTop, pF->nXaRight, pF->nYaBottom);
2579 SvxMSDffImportData aData( aRect );
2580
2581 /*
2582 #i20540#
2583 The SdrOle2Obj will try and manage any ole objects it finds, causing all
2584 sorts of trouble later on
2585 */
2586 SwDocShell* pPersist = m_rDoc.GetDocShell();
2587 m_rDoc.SetDocShell(nullptr); // #i20540# Persist guard
2588
2589 SdrObject* pObject = nullptr;
2590 bool bOk = (m_xMSDffManager->GetShape(pF->nSpId, pObject, aData) && pObject);
2591
2592 m_rDoc.SetDocShell(pPersist); // #i20540# Persist guard
2593
2594 if (!bOk)
2595 {
2596 OSL_ENSURE( false, "Where is the Shape ?" );
2597 return nullptr;
2598 }
2599
2600 // tdf#118375 Word relates position to the unrotated rectangle,
2601 // Writer uses the rotated one.
2602 if (pObject->GetRotateAngle())
2603 {
2604 tools::Rectangle aObjSnapRect(pObject->GetSnapRect()); // recalculates the SnapRect
2605 pF->nXaLeft = aObjSnapRect.Left();
2606 pF->nYaTop = aObjSnapRect.Top();
2607 pF->nXaRight = aObjSnapRect.Right();
2608 pF->nYaBottom = aObjSnapRect.Bottom();
2609 }
2610
2611 bool bDone = false;
2612 SdrObject* pOurNewObject = nullptr;
2613 bool bReplaceable = false;
2614
2615 switch (SdrObjKind(pObject->GetObjIdentifier()))
2616 {
2617 case OBJ_GRAF:
2618 bReplaceable = true;
2619 bDone = true;
2620 break;
2621 case OBJ_OLE2:
2622 bReplaceable = true;
2623 break;
2624 default:
2625 break;
2626
2627 }
2628
2629 // when in a header or footer word appears to treat all elements as wrap through
2630
2631 // determine wrapping mode
2632 SfxItemSet aFlySet(m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END-1, XATTR_START, XATTR_END>{});
2633 Reader::ResetFrameFormatAttrs(aFlySet); // tdf#122425: Explicitly remove borders and spacing
2634 css::text::WrapTextMode eSurround = css::text::WrapTextMode_PARALLEL;
2635 bool bContour = false;
2636 switch (pF->nwr)
2637 {
2638 case 0: // 0 like 2, but doesn't require absolute object
2639 case 2: // 2 wrap around absolute object
2640 eSurround = css::text::WrapTextMode_PARALLEL;
2641 break;
2642 case 1: // 1 no text next to shape
2643 eSurround = css::text::WrapTextMode_NONE;
2644 break;
2645 case 3: // 3 wrap as if no object present
2646 eSurround = css::text::WrapTextMode_THROUGH;
2647 break;
2648 case 4: // 4 wrap tightly around object
2649 case 5: // 5 wrap tightly, but allow holes
2650 eSurround = css::text::WrapTextMode_PARALLEL;
2651 bContour = true;
2652 break;
2653 }
2654
2655 // if mode 2 or 4 also regard the additional parameters
2656 if ( (2 == pF->nwr) || (4 == pF->nwr) )
2657 {
2658 switch( pF->nwrk )
2659 {
2660 // 0 wrap both sides
2661 case 0:
2662 eSurround = css::text::WrapTextMode_PARALLEL;
2663 break;
2664 // 1 wrap only on left
2665 case 1:
2666 eSurround = css::text::WrapTextMode_LEFT;
2667 break;
2668 // 2 wrap only on right
2669 case 2:
2670 eSurround = css::text::WrapTextMode_RIGHT;
2671 break;
2672 // 3 wrap only on largest side
2673 case 3:
2674 eSurround = css::text::WrapTextMode_DYNAMIC;
2675 break;
2676 }
2677 }
2678
2679 SwFormatSurround aSur( eSurround );
2680 aSur.SetContour( bContour );
2681 aSur.SetOutside(true); // Winword can only do outside contours
2682 aFlySet.Put( aSur );
2683
2684 // now position imported object correctly and so on (can be a whole group)
2685
2686 OSL_ENSURE(!((aData.size() != 1) && bReplaceable),
2687 "Replaceable drawing with > 1 entries ?");
2688
2689 if (aData.size() != 1)
2690 bReplaceable = false;
2691
2692 /*
2693 Get the record for top level object, so we can get the word anchoring
2694 and wrapping information for it.
2695 */
2696 SvxMSDffImportRec* pRecord = aData.find(pObject);
2697 OSL_ENSURE(pRecord, "how did that happen?");
2698 if (!pRecord)
2699 {
2700 // remove old object from the Z-Order list
2701 m_xMSDffManager->RemoveFromShapeOrder(pObject);
2702 // and delete the object
2703 SdrObject::Free(pObject);
2704 return nullptr;
2705 }
2706
2707 const bool bLayoutInTableCell =
2708 m_nInTable && IsObjectLayoutInTableCell( pRecord->nLayoutInTableCell );
2709
2710 // #i18732# - Switch on 'follow text flow', if object is laid out
2711 // inside table cell
2712 if (bLayoutInTableCell)
2713 {
2714 SwFormatFollowTextFlow aFollowTextFlow( true );
2715 aFlySet.Put( aFollowTextFlow );
2716 }
2717
2718 // #i21847#
2719 // Some shapes are set to *hidden*, don't import those ones.
2720 if (pRecord->bHidden)
2721 {
2722 // remove old object from the Z-Order list
2723 m_xMSDffManager->RemoveFromShapeOrder(pObject);
2724 // and delete the object
2725 SdrObject::Free(pObject);
2726 return nullptr;
2727 }
2728
2729 sal_uInt16 nCount = pObject->GetUserDataCount();
2730 if(nCount)
2731 {
2732 OUString lnName, aObjName, aTarFrame;
2733 for (sal_uInt16 i = 0; i < nCount; i++ )
2734 {
2735 SdrObjUserData* pData = pObject->GetUserData( i );
2736 if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw
2737 && pData->GetId() == SW_UD_IMAPDATA)
2738 {
2739 SwMacroInfo* macInf = dynamic_cast<SwMacroInfo*>(pData);
2740 if( macInf && macInf->GetShapeId() == pF->nSpId )
2741 {
2742 lnName = macInf->GetHlink();
2743 aObjName = macInf->GetName();
2744 aTarFrame = macInf->GetTarFrame();
2745 break;
2746 }
2747 }
2748 }
2749 SwFormatURL* pFormatURL = new SwFormatURL();
2750 pFormatURL->SetURL( lnName, false );
2751 if (!aObjName.isEmpty())
2752 pFormatURL->SetName(aObjName);
2753 if (!aTarFrame.isEmpty())
2754 pFormatURL->SetTargetFrameName(aTarFrame);
2755 pFormatURL->SetMap(nullptr);
2756 aFlySet.Put(*pFormatURL);
2757 }
2758
2759 // If we are to be "below text" then we are not to be opaque
2760 // #i14045# MM If we are in a header or footer then make the object transparent
2761 // Not exactly like word but close enough for now
2762
2763 // both flags <bBelowText> and <bDrawHell> have to be set to move object into the background.
2764 // #i46794# - it reveals that value of flag <bBelowText> can be neglected.
2765 const bool bMoveToBackgrd = pRecord->bDrawHell ||
2766 ( ( m_bIsHeader || m_bIsFooter ) && pF->nwr == 3 );
2767 if ( bMoveToBackgrd )
2768 aFlySet.Put(SvxOpaqueItem(RES_OPAQUE,false));
2769
2770 OUString aObjName = pObject->GetName();
2771
2772 SwFrameFormat* pRetFrameFormat = nullptr;
2773 if (bReplaceable)
2774 {
2775 // Single graphics or ole objects
2776 pRetFrameFormat = ImportReplaceableDrawables(pObject, pOurNewObject, pRecord,
2777 pF, aFlySet);
2778 }
2779 else
2780 {
2781 // Drawing objects, (e.g. ovals or drawing groups)
2782 if (pF->bRcaSimple)
2783 {
2784 pF->nbx = WW8_FSPA::RelPageBorder;
2785 pF->nby = WW8_FSPA::RelPageBorder;
2786 }
2787
2788 RndStdIds eAnchor = ProcessEscherAlign(pRecord, pF, aFlySet);
2789
2790 // Should we, and is it possible to make this into a writer textbox
2791 if ((!(m_nIniFlags1 & WW8FL_NO_FLY_FOR_TXBX)) && pRecord->bReplaceByFly)
2792 {
2793 pRetFrameFormat = ConvertDrawTextToFly(pObject, pOurNewObject, pRecord,
2794 eAnchor, pF, aFlySet);
2795 if (pRetFrameFormat)
2796 bDone = true;
2797 }
2798
2799 if (!bDone)
2800 {
2801 sw::util::SetLayer aSetLayer(m_rDoc);
2802 if ( bMoveToBackgrd )
2803 aSetLayer.SendObjectToHell(*pObject);
2804 else
2805 aSetLayer.SendObjectToHeaven(*pObject);
2806
2807 if (!IsInlineEscherHack())
2808 {
2809 /* Need to make sure that the correct layer ordering is applied. */
2810 // pass information, if object is in page header|footer to method.
2811 m_xWWZOrder->InsertEscherObject( pObject, pF->nSpId,
2812 m_bIsHeader || m_bIsFooter );
2813 }
2814 else
2815 {
2816 m_xWWZOrder->InsertTextLayerObject(pObject);
2817 }
2818
2819 pRetFrameFormat = m_rDoc.getIDocumentContentOperations().InsertDrawObj(*m_pPaM, *pObject, aFlySet );
2820
2821 OSL_ENSURE(pRetFrameFormat->GetAnchor().GetAnchorId() ==
2822 eAnchor, "Not the anchor type requested!");
2823
2824 /*
2825 Insert text if necessary into textboxes contained in groups.
2826 */
2827 for (const auto& it : aData)
2828 {
2829 pRecord = it.get();
2830 if (pRecord->pObj && pRecord->aTextId.nTxBxS)
2831 { // #i52825# pRetFrameFormat can be NULL
2832 pRetFrameFormat = MungeTextIntoDrawBox(
2833 pRecord, nGrafAnchorCp, pRetFrameFormat);
2834 }
2835 }
2836 }
2837 }
2838
2839 // #i44344#, #i44681# - positioning attributes already set
2840 if ( pRetFrameFormat /*#i52825# */ && dynamic_cast< const SwDrawFrameFormat *>( pRetFrameFormat ) != nullptr )
2841 {
2842 static_cast<SwDrawFrameFormat*>(pRetFrameFormat)->PosAttrSet();
2843 }
2844 if (!IsInlineEscherHack())
2845 MapWrapIntoFlyFormat(pRecord, pRetFrameFormat);
2846
2847 // Set frame name with object name
2848 if( pRetFrameFormat /*#i52825# */ && !aObjName.isEmpty() )
2849 pRetFrameFormat->SetName( aObjName );
2850 return AddAutoAnchor(pRetFrameFormat);
2851 }
2852
AddAutoAnchor(SwFrameFormat * pFormat)2853 SwFrameFormat *SwWW8ImplReader::AddAutoAnchor(SwFrameFormat *pFormat)
2854 {
2855 /*
2856 * anchored to character at the current position will move along the
2857 * paragraph as text is added because we are at the insertion point.
2858 *
2859 * Leave to later and set the correct location then.
2860 */
2861 if (pFormat && (pFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR))
2862 {
2863 m_xAnchorStck->AddAnchor(*m_pPaM->GetPoint(), pFormat);
2864 }
2865 return pFormat;
2866 }
2867
MungeTextIntoDrawBox(SvxMSDffImportRec * pRecord,long nGrafAnchorCp,SwFrameFormat * pRetFrameFormat)2868 SwFrameFormat* SwWW8ImplReader::MungeTextIntoDrawBox(SvxMSDffImportRec *pRecord,
2869 long nGrafAnchorCp, SwFrameFormat* pRetFrameFormat)
2870 {
2871 SdrObject* pTrueObject = pRecord->pObj;
2872
2873 SdrTextObj* pSdrTextObj;
2874
2875 // check for group object (e.g. two parentheses)
2876 if (SdrObjGroup* pThisGroup = dynamic_cast<SdrObjGroup*>( pRecord->pObj) )
2877 {
2878 // Group objects don't have text. Insert a text object into
2879 // the group for holding the text.
2880 pSdrTextObj = new SdrRectObj(
2881 *m_pDrawModel,
2882 OBJ_TEXT,
2883 pThisGroup->GetCurrentBoundRect());
2884
2885 SfxItemSet aSet(m_pDrawModel->GetItemPool());
2886 aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
2887 aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
2888 aSet.Put(SdrTextFitToSizeTypeItem( drawing::TextFitToSizeType_NONE ));
2889 aSet.Put(makeSdrTextAutoGrowHeightItem(false));
2890 aSet.Put(makeSdrTextAutoGrowWidthItem(false));
2891 pSdrTextObj->SetMergedItemSet(aSet);
2892 pSdrTextObj->NbcSetLayer( pThisGroup->GetLayer() );
2893 pThisGroup->GetSubList()->NbcInsertObject(pSdrTextObj);
2894 }
2895 else
2896 pSdrTextObj = dynamic_cast<SdrTextObj*>( pRecord->pObj );
2897
2898 if( pSdrTextObj )
2899 {
2900 Size aObjSize(pSdrTextObj->GetSnapRect().GetWidth(),
2901 pSdrTextObj->GetSnapRect().GetHeight());
2902
2903 // Object is part of a group?
2904 SdrObject* pGroupObject = pSdrTextObj->getParentSdrObjectFromSdrObject();
2905
2906 const size_t nOrdNum = pSdrTextObj->GetOrdNum();
2907 bool bEraseThisObject;
2908 InsertTxbxText( pSdrTextObj, &aObjSize, pRecord->aTextId.nTxBxS,
2909 pRecord->aTextId.nSequence, nGrafAnchorCp, pRetFrameFormat,
2910 (pSdrTextObj != pTrueObject) || (nullptr != pGroupObject),
2911 bEraseThisObject, nullptr, nullptr, nullptr, nullptr, pRecord);
2912
2913 // was this object replaced ??
2914 if (bEraseThisObject)
2915 {
2916 if( pGroupObject || (pSdrTextObj != pTrueObject) )
2917 {
2918 // Object is already replaced by a new SdrGrafObj (in the group
2919 // and) the Drawing-Page.
2920
2921 SdrObject* pNewObj = pGroupObject ?
2922 pGroupObject->GetSubList()->GetObj(nOrdNum) : pTrueObject;
2923 if (pSdrTextObj != pNewObj)
2924 {
2925 // Replace object in the Z-Order-List
2926 m_xMSDffManager->ExchangeInShapeOrder(pSdrTextObj, 0, pNewObj);
2927 // now delete object
2928 SdrObject::Free( pRecord->pObj );
2929 // and save the new object.
2930 pRecord->pObj = pNewObj;
2931 }
2932 }
2933 else
2934 {
2935 // remove the object from Z-Order list
2936 m_xMSDffManager->RemoveFromShapeOrder( pSdrTextObj );
2937 // take the object from the drawing page
2938 if( pSdrTextObj->getSdrPageFromSdrObject() )
2939 m_pDrawPg->RemoveObject( pSdrTextObj->GetOrdNum() );
2940 // and delete FrameFormat, because replaced by graphic
2941 // (this also deletes the object)
2942 m_rDoc.DelFrameFormat( pRetFrameFormat );
2943 pRetFrameFormat = nullptr;
2944 // also delete the object record
2945 pRecord->pObj = nullptr;
2946 }
2947 }
2948 else
2949 {
2950 // use ww8-default border distance
2951 SfxItemSet aItemSet(m_pDrawModel->GetItemPool(),
2952 svl::Items<SDRATTR_TEXT_LEFTDIST, SDRATTR_TEXT_LOWERDIST>{});
2953 aItemSet.Put( makeSdrTextLeftDistItem( pRecord->nDxTextLeft ) );
2954 aItemSet.Put( makeSdrTextRightDistItem( pRecord->nDxTextRight ) );
2955 aItemSet.Put( makeSdrTextUpperDistItem( pRecord->nDyTextTop ) );
2956 aItemSet.Put( makeSdrTextLowerDistItem( pRecord->nDyTextBottom ) );
2957 pSdrTextObj->SetMergedItemSetAndBroadcast(aItemSet);
2958 }
2959 }
2960 return pRetFrameFormat;
2961 }
2962
ConvertDrawTextToFly(SdrObject * & rpObject,SdrObject * & rpOurNewObject,SvxMSDffImportRec const * pRecord,RndStdIds eAnchor,WW8_FSPA const * pF,SfxItemSet & rFlySet)2963 SwFlyFrameFormat* SwWW8ImplReader::ConvertDrawTextToFly(SdrObject* &rpObject,
2964 SdrObject* &rpOurNewObject, SvxMSDffImportRec const * pRecord, RndStdIds eAnchor,
2965 WW8_FSPA const *pF, SfxItemSet &rFlySet)
2966 {
2967 SwFlyFrameFormat* pRetFrameFormat = nullptr;
2968 long nStartCp;
2969 long nEndCp;
2970
2971 // Check if this textbox chain contains text as conversion of an empty
2972 // chain would not make sense.
2973 if ( TxbxChainContainsRealText(pRecord->aTextId.nTxBxS,nStartCp,nEndCp) )
2974 {
2975 // The Text is not read into SdrTextObj! Rather insert a frame and
2976 // insert the text from nStartCp to nEndCp.
2977
2978 // More attributes can be used in a frame compared to the
2979 // Edit-Engine, and it can contain field, OLEs or graphics...
2980 tools::Rectangle aInnerDist(pRecord->nDxTextLeft, pRecord->nDyTextTop,
2981 pRecord->nDxTextRight, pRecord->nDyTextBottom);
2982
2983 SwFormatFrameSize aFrameSize(ATT_FIX_SIZE, pF->nXaRight - pF->nXaLeft, pF->nYaBottom - pF->nYaTop);
2984 aFrameSize.SetWidthSizeType(pRecord->bAutoWidth ? ATT_VAR_SIZE : ATT_FIX_SIZE);
2985 rFlySet.Put(aFrameSize);
2986
2987 MatchSdrItemsIntoFlySet( rpObject, rFlySet, pRecord->eLineStyle,
2988 pRecord->eLineDashing, pRecord->eShapeType, aInnerDist );
2989
2990 SdrTextObj *pSdrTextObj = dynamic_cast<SdrTextObj*>(rpObject);
2991 if (pSdrTextObj && pSdrTextObj->IsVerticalWriting())
2992 rFlySet.Put(SvxFrameDirectionItem(SvxFrameDirection::Vertical_RL_TB, RES_FRAMEDIR));
2993
2994 pRetFrameFormat = m_rDoc.MakeFlySection(eAnchor, m_pPaM->GetPoint(), &rFlySet);
2995 OSL_ENSURE(pRetFrameFormat->GetAnchor().GetAnchorId() == eAnchor,
2996 "Not the anchor type requested!");
2997
2998 // if everything is OK, find pointer on new object and correct
2999 // Z-order list (or delete entry)
3000 rpOurNewObject = CreateContactObject(pRetFrameFormat);
3001
3002 // remove old object from the Z-Order list
3003 m_xMSDffManager->RemoveFromShapeOrder( rpObject );
3004
3005 // and delete the object
3006 SdrObject::Free( rpObject );
3007 /*
3008 NB: only query pOrgShapeObject starting here!
3009 */
3010
3011 if (rpOurNewObject)
3012 {
3013 /*
3014 We do not store our rpOutNewObject in the ShapeOrder because we
3015 have a FrameFormat from which we can regenerate the contact object when
3016 we need it. Because, we can have frames anchored to paragraphs in
3017 header/footers and we can copy header/footers, if we do copy a
3018 header/footer with a nonpage anchored frame in it then the contact
3019 objects are invalidated. Under this condition the FrameFormat will be
3020 updated to reflect this change and can be used to get a new
3021 contact object, while a raw rpOutNewObject stored here becomes
3022 deleted and useless.
3023 */
3024 m_xMSDffManager->StoreShapeOrder(pF->nSpId,
3025 (static_cast<sal_uLong>(pRecord->aTextId.nTxBxS) << 16) +
3026 pRecord->aTextId.nSequence, nullptr, pRetFrameFormat);
3027
3028 // The Contact object has to be inserted into the draw page, so
3029 // SwWW8ImplReader::LoadDoc1() can determine the z-order.
3030 if (!rpOurNewObject->IsInserted())
3031 {
3032 // pass information, if object is in page header|footer to method.
3033 m_xWWZOrder->InsertEscherObject( rpOurNewObject, pF->nSpId,
3034 m_bIsHeader || m_bIsFooter );
3035 }
3036 }
3037
3038 // Box-0 receives the text for the whole chain!
3039 if( !pRecord->aTextId.nSequence )
3040 {
3041 // save flags etc and reset them
3042 WW8ReaderSave aSave( this );
3043
3044 MoveInsideFly(pRetFrameFormat);
3045
3046 SwNodeIndex aStart(m_pPaM->GetPoint()->nNode);
3047
3048 m_xWWZOrder->InsideEscher(pF->nSpId);
3049
3050 // read in the text
3051 m_bTxbxFlySection = true;
3052 bool bJoined = ReadText(nStartCp, (nEndCp-nStartCp),
3053 MAN_MAINTEXT == m_xPlcxMan->GetManType() ?
3054 MAN_TXBX : MAN_TXBX_HDFT);
3055
3056 m_xWWZOrder->OutsideEscher();
3057
3058 MoveOutsideFly(pRetFrameFormat, aSave.GetStartPos(),!bJoined);
3059
3060 aSave.Restore( this );
3061
3062 StripNegativeAfterIndent(pRetFrameFormat);
3063 }
3064
3065 }
3066 return pRetFrameFormat;
3067 }
3068
MatchEscherMirrorIntoFlySet(const SvxMSDffImportRec & rRecord,SfxItemSet & rFlySet)3069 void MatchEscherMirrorIntoFlySet(const SvxMSDffImportRec &rRecord,
3070 SfxItemSet &rFlySet)
3071 {
3072 if (rRecord.bVFlip || rRecord.bHFlip)
3073 {
3074 MirrorGraph eType(MirrorGraph::Dont);
3075 if (rRecord.bVFlip && rRecord.bHFlip)
3076 eType = MirrorGraph::Both;
3077 else if (rRecord.bVFlip)
3078 eType = MirrorGraph::Horizontal;
3079 else
3080 eType = MirrorGraph::Vertical;
3081 rFlySet.Put( SwMirrorGrf(eType) );
3082 }
3083 }
3084
ImportReplaceableDrawables(SdrObject * & rpObject,SdrObject * & rpOurNewObject,SvxMSDffImportRec * pRecord,WW8_FSPA * pF,SfxItemSet & rFlySet)3085 SwFlyFrameFormat* SwWW8ImplReader::ImportReplaceableDrawables( SdrObject* &rpObject,
3086 SdrObject* &rpOurNewObject, SvxMSDffImportRec* pRecord, WW8_FSPA *pF,
3087 SfxItemSet &rFlySet )
3088 {
3089 SwFlyFrameFormat* pRetFrameFormat = nullptr;
3090 sal_Int32 nWidthTw = o3tl::saturating_sub(pF->nXaRight, pF->nXaLeft);
3091 if (0 > nWidthTw)
3092 nWidthTw = 0;
3093 sal_Int32 nHeightTw = o3tl::saturating_sub(pF->nYaBottom, pF->nYaTop);
3094 if (0 > nHeightTw)
3095 nHeightTw = 0;
3096
3097 ProcessEscherAlign(pRecord, pF, rFlySet);
3098
3099 rFlySet.Put(SwFormatFrameSize(ATT_FIX_SIZE, nWidthTw, nHeightTw));
3100
3101 SfxItemSet aGrSet(m_rDoc.GetAttrPool(), svl::Items<RES_GRFATR_BEGIN, RES_GRFATR_END-1>{});
3102
3103 if (pRecord)
3104 {
3105 // Note that the escher inner distance only seems to be honoured in
3106 // word for textboxes, not for graphics and ole objects.
3107 tools::Rectangle aInnerDist(0, 0, 0, 0);
3108
3109 MatchSdrItemsIntoFlySet(rpObject, rFlySet, pRecord->eLineStyle,
3110 pRecord->eLineDashing, pRecord->eShapeType, aInnerDist);
3111
3112 MatchEscherMirrorIntoFlySet(*pRecord, aGrSet);
3113 }
3114
3115 OUString aObjectName(rpObject->GetName());
3116 if (OBJ_OLE2 == SdrObjKind(rpObject->GetObjIdentifier()))
3117 pRetFrameFormat = InsertOle(*static_cast<SdrOle2Obj*>(rpObject), rFlySet, &aGrSet);
3118 else
3119 {
3120 const SdrGrafObj *pGrf = static_cast<const SdrGrafObj*>(rpObject);
3121 bool bDone = false;
3122 if (pGrf->IsLinkedGraphic() && !pGrf->GetFileName().isEmpty())
3123 {
3124 GraphicType eType = pGrf->GetGraphicType();
3125 OUString aGrfName(
3126 URIHelper::SmartRel2Abs(
3127 INetURLObject(m_sBaseURL), pGrf->GetFileName(),
3128 URIHelper::GetMaybeFileHdl()));
3129 // correction of fix for issue #i10939#:
3130 // One of the two conditions have to be true to insert the graphic
3131 // as a linked graphic -
3132 if (GraphicType::NONE == eType || CanUseRemoteLink(aGrfName))
3133 {
3134 pRetFrameFormat = m_rDoc.getIDocumentContentOperations().InsertGraphic(
3135 *m_pPaM, aGrfName, OUString(), nullptr,
3136 &rFlySet, &aGrSet, nullptr);
3137 bDone = true;
3138 }
3139 }
3140 if (!bDone)
3141 {
3142 const Graphic& rGraph = pGrf->GetGraphic();
3143 pRetFrameFormat = m_rDoc.getIDocumentContentOperations().InsertGraphic(
3144 *m_pPaM, OUString(), OUString(), &rGraph,
3145 &rFlySet, &aGrSet, nullptr);
3146 }
3147 }
3148
3149 if (pRetFrameFormat)
3150 {
3151 if( pRecord )
3152 {
3153 if( OBJ_OLE2 != SdrObjKind(rpObject->GetObjIdentifier()) )
3154 SetAttributesAtGrfNode( pRecord, pRetFrameFormat, pF );
3155 }
3156 // avoid multiple occurrences of the same graphic name
3157 m_aGrfNameGenerator.SetUniqueGraphName(pRetFrameFormat, aObjectName);
3158 }
3159 // if everything is OK, determine pointer to new object and correct
3160 // Z-Order-List accordingly (or delete entry)
3161 rpOurNewObject = CreateContactObject(pRetFrameFormat);
3162
3163 // remove old object from Z-Order-List
3164 m_xMSDffManager->RemoveFromShapeOrder( rpObject );
3165 // remove from Drawing-Page
3166 if( rpObject->getSdrPageFromSdrObject() )
3167 m_pDrawPg->RemoveObject( rpObject->GetOrdNum() );
3168
3169 // and delete the object
3170 SdrObject::Free( rpObject );
3171 /*
3172 Warning: from now on query only pOrgShapeObject!
3173 */
3174
3175 // add Contact-Object to the Z-Order-List and the page
3176 if (rpOurNewObject)
3177 {
3178 if (!m_bHdFtFootnoteEdn)
3179 m_xMSDffManager->StoreShapeOrder(pF->nSpId, 0, rpOurNewObject );
3180
3181 // The Contact-Object MUST be set in the Draw-Page, so that in
3182 // SwWW8ImplReader::LoadDoc1() the Z-Order can be defined !!!
3183 if (!rpOurNewObject->IsInserted())
3184 {
3185 // pass information, if object is in page header|footer to method.
3186 m_xWWZOrder->InsertEscherObject( rpOurNewObject, pF->nSpId,
3187 m_bIsHeader || m_bIsFooter );
3188 }
3189 }
3190 return pRetFrameFormat;
3191 }
3192
GrafikCtor()3193 void SwWW8ImplReader::GrafikCtor() // For SVDraw and VCControls and Escher
3194 {
3195 if (!m_pDrawModel)
3196 {
3197 m_rDoc.getIDocumentDrawModelAccess().GetOrCreateDrawModel(); // #i52858# - method name changed
3198 m_pDrawModel = m_rDoc.getIDocumentDrawModelAccess().GetDrawModel();
3199 OSL_ENSURE(m_pDrawModel, "Cannot create DrawModel");
3200 m_pDrawPg = m_pDrawModel->GetPage(0);
3201
3202 m_xMSDffManager.reset(new SwMSDffManager(*this, m_bSkipImages));
3203 m_xMSDffManager->SetModel(m_pDrawModel, 1440);
3204 /*
3205 Now the dff manager always needs a controls converter as well, but a
3206 control converter may still exist without a dffmanager.
3207 */
3208 m_xFormImpl.reset(new SwMSConvertControls(m_pDocShell, m_pPaM));
3209
3210 m_xWWZOrder.reset(new wwZOrderer(sw::util::SetLayer(m_rDoc), m_pDrawPg,
3211 m_xMSDffManager->GetShapeOrders()));
3212 }
3213 }
3214
GrafikDtor()3215 void SwWW8ImplReader::GrafikDtor()
3216 {
3217 m_pDrawEditEngine.reset(); // maybe created by graphic
3218 m_xWWZOrder.reset(); // same
3219 }
3220
AddAnchor(const SwPosition & rPos,SwFrameFormat * pFormat)3221 void SwWW8FltAnchorStack::AddAnchor(const SwPosition& rPos, SwFrameFormat *pFormat)
3222 {
3223 OSL_ENSURE(pFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR,
3224 "Don't use fltanchors with inline frames, slap!");
3225 NewAttr(rPos, SwFltAnchor(pFormat));
3226 }
3227
Flush()3228 void SwWW8FltAnchorStack::Flush()
3229 {
3230 size_t nCnt = size();
3231 for (size_t i=0; i < nCnt; ++i)
3232 {
3233 SwFltStackEntry &rEntry = (*this)[i];
3234 SwPosition aDummy(rEntry.m_aMkPos.m_nNode);
3235 SetAttrInDoc(aDummy, rEntry);
3236 DeleteAndDestroy(i--);
3237 --nCnt;
3238 }
3239 }
3240
3241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3242