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