Line data Source code
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 <sal/config.h>
21 :
22 : #include <boost/noncopyable.hpp>
23 : #include <boost/scoped_ptr.hpp>
24 : #include <comphelper/string.hxx>
25 : #include <tools/solar.h>
26 : #include <vcl/vclenum.hxx>
27 : #include <vcl/font.hxx>
28 : #include <hintids.hxx>
29 : #include <editeng/colritem.hxx>
30 : #include <editeng/orphitem.hxx>
31 : #include <editeng/widwitem.hxx>
32 : #include <editeng/brushitem.hxx>
33 : #include <editeng/boxitem.hxx>
34 : #include <editeng/lrspitem.hxx>
35 : #include <editeng/ulspitem.hxx>
36 : #include <editeng/fhgtitem.hxx>
37 : #include <editeng/hyphenzoneitem.hxx>
38 : #include <editeng/frmdiritem.hxx>
39 : #include <editeng/langitem.hxx>
40 : #include <editeng/charrotateitem.hxx>
41 : #include <editeng/pgrditem.hxx>
42 : #include <msfilter.hxx>
43 : #include <pam.hxx>
44 : #include <doc.hxx>
45 : #include <IDocumentStylePoolAccess.hxx>
46 : #include <docary.hxx>
47 : #include <ndtxt.hxx>
48 : #include <paratr.hxx>
49 : #include <poolfmt.hxx>
50 : #include <swtable.hxx>
51 : #include <tblsel.hxx>
52 : #include <mdiexp.hxx>
53 : #include <fmtpdsc.hxx>
54 : #include <txtftn.hxx>
55 : #include <frmfmt.hxx>
56 : #include <ftnidx.hxx>
57 : #include <fmtftn.hxx>
58 : #include <charfmt.hxx>
59 : #include <SwStyleNameMapper.hxx>
60 : #include <fltshell.hxx>
61 : #include <fmtanchr.hxx>
62 : #include <fmtrowsplt.hxx>
63 : #include <fmtfollowtextflow.hxx>
64 : #include <numrule.hxx>
65 : #include <sprmids.hxx>
66 : #include <wwstyles.hxx>
67 : #include "writerhelper.hxx"
68 : #include "ww8struc.hxx"
69 : #include "ww8par.hxx"
70 : #include "ww8par2.hxx"
71 :
72 : #include <frmatr.hxx>
73 :
74 : #include <iostream>
75 :
76 : using namespace ::com::sun::star;
77 :
78 12 : class WW8SelBoxInfo
79 : : public std::vector<SwTableBox*>, private boost::noncopyable
80 : {
81 : public:
82 : short nGroupXStart;
83 : short nGroupWidth;
84 : bool bGroupLocked;
85 :
86 12 : WW8SelBoxInfo(short nXCenter, short nWidth)
87 12 : : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
88 12 : {}
89 : };
90 :
91 : typedef boost::ptr_vector<WW8SelBoxInfo> WW8MergeGroups;
92 :
93 2222 : WW8TabBandDesc::WW8TabBandDesc()
94 : {
95 2222 : memset(this, 0, sizeof(*this));
96 146652 : for (size_t i = 0; i < sizeof(maDirections)/sizeof(sal_uInt16); ++i)
97 144430 : maDirections[i] = 4;
98 2222 : }
99 :
100 2222 : WW8TabBandDesc::~WW8TabBandDesc()
101 : {
102 2222 : delete[] pTCs;
103 2222 : delete[] pSHDs;
104 2222 : delete[] pNewSHDs;
105 2222 : }
106 :
107 : class WW8TabDesc: private boost::noncopyable
108 : {
109 : std::vector<OUString> aNumRuleNames;
110 : sw::util::RedlineStack *mpOldRedlineStack;
111 :
112 : SwWW8ImplReader* pIo;
113 :
114 : WW8TabBandDesc* pFirstBand;
115 : WW8TabBandDesc* pActBand;
116 :
117 : SwPosition* pTmpPos;
118 :
119 : SwTableNode* pTableNd; // table node
120 : const SwTableLines* pTabLines; // row array of node
121 : SwTableLine* pTabLine; // current row
122 : SwTableBoxes* pTabBoxes; // boxes array in current row
123 : SwTableBox* pTabBox; // current cell
124 :
125 : WW8MergeGroups aMergeGroups; // list of all cells to be merged
126 :
127 : WW8_TCell* pAktWWCell;
128 :
129 : short nRows;
130 : short nDefaultSwCols;
131 : short nBands;
132 : short nMinLeft;
133 : short nConvertedLeft;
134 : short nMaxRight;
135 : short nSwWidth;
136 : short nPreferredWidth;
137 : short nOrgDxaLeft;
138 :
139 : bool bOk;
140 : bool bClaimLineFormat;
141 : sal_Int16 eOri;
142 : bool bIsBiDi;
143 : // 2. common admin info
144 : short nAktRow;
145 : short nAktBandRow; // SW: row of current band
146 : // 3. admin info for writer
147 : short nAktCol;
148 :
149 : sal_uInt16 nRowsToRepeat;
150 :
151 : // 4. methods
152 :
153 : sal_uInt16 GetLogicalWWCol() const;
154 : void SetTabBorders( SwTableBox* pBox, short nIdx );
155 : void SetTabShades( SwTableBox* pBox, short nWwIdx );
156 : void SetTabVertAlign( SwTableBox* pBox, short nWwIdx );
157 : void SetTabDirection( SwTableBox* pBox, short nWwIdx );
158 : void CalcDefaults();
159 : bool SetPamInCell(short nWwCol, bool bPam);
160 : void InsertCells( short nIns );
161 : void AdjustNewBand();
162 :
163 : WW8SelBoxInfo* FindMergeGroup(short nX1, short nWidth, bool bExact);
164 :
165 : // single box - maybe used in a merge group
166 : // (the merge groups are processed later at once)
167 : SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell,
168 : WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, sal_uInt16 nCol );
169 : void StartMiserableHackForUnsupportedDirection(short nWwCol);
170 : void EndMiserableHackForUnsupportedDirection(short nWwCol);
171 :
172 : public:
173 : const SwTable* pTable; // table
174 : SwPosition* pParentPos;
175 : SwFlyFrameFormat* pFlyFormat;
176 : SfxItemSet aItemSet;
177 : bool IsValidCell(short nCol) const;
178 : bool InFirstParaInCell() const;
179 :
180 : WW8TabDesc( SwWW8ImplReader* pIoClass, WW8_CP nStartCp );
181 74 : bool Ok() const { return bOk; }
182 : void CreateSwTable(SvxULSpaceItem* pULSpaceItem = 0);
183 : void UseSwTable();
184 : void SetSizePosition(SwFrameFormat* pFrameFormat);
185 : void TableCellEnd();
186 : void MoveOutsideTable();
187 : void ParkPaM();
188 : void FinishSwTable();
189 : void MergeCells();
190 47 : short GetMinLeft() const { return nConvertedLeft; }
191 : ~WW8TabDesc();
192 :
193 1742 : const WW8_TCell* GetAktWWCell() const { return pAktWWCell; }
194 3923 : short GetAktCol() const { return nAktCol; }
195 : // find name of numrule valid for current WW-COL
196 : OUString GetNumRuleName() const;
197 : void SetNumRuleName( const OUString& rName );
198 :
199 0 : sw::util::RedlineStack* getOldRedlineStack(){ return mpOldRedlineStack; }
200 : };
201 :
202 5 : void sw::util::RedlineStack::close( const SwPosition& rPos,
203 : RedlineType_t eType, WW8TabDesc* pTabDesc )
204 : {
205 : // If the redline type is not found in the redline stack, we have to check if there has been
206 : // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
207 5 : if( !close( rPos, eType ) )
208 : {
209 0 : if( pTabDesc && pTabDesc->getOldRedlineStack() )
210 : {
211 : bool const bResult =
212 0 : pTabDesc->getOldRedlineStack()->close(rPos, eType);
213 : OSL_ENSURE( bResult, "close without open!");
214 : (void) bResult; // unused in non-debug
215 : }
216 : }
217 5 : }
218 :
219 1 : void wwSectionManager::SetCurrentSectionHasFootnote()
220 : {
221 : OSL_ENSURE(!maSegments.empty(),
222 : "should not be possible, must be at least one segment");
223 1 : if (!maSegments.empty())
224 1 : maSegments.back().mbHasFootnote = true;
225 1 : }
226 :
227 133 : bool wwSectionManager::CurrentSectionIsVertical() const
228 : {
229 : OSL_ENSURE(!maSegments.empty(),
230 : "should not be possible, must be at least one segment");
231 133 : if (!maSegments.empty())
232 133 : return maSegments.back().IsVertical();
233 0 : return false;
234 : }
235 :
236 0 : bool wwSectionManager::CurrentSectionIsProtected() const
237 : {
238 : OSL_ENSURE(!maSegments.empty(),
239 : "should not be possible, must be at least one segment");
240 0 : if (!maSegments.empty())
241 0 : return SectionIsProtected(maSegments.back());
242 0 : return false;
243 : }
244 :
245 22 : sal_uInt32 wwSectionManager::GetPageLeft() const
246 : {
247 22 : return !maSegments.empty() ? maSegments.back().nPgLeft : 0;
248 : }
249 :
250 10 : sal_uInt32 wwSectionManager::GetPageRight() const
251 : {
252 10 : return !maSegments.empty() ? maSegments.back().nPgRight : 0;
253 : }
254 :
255 10 : sal_uInt32 wwSectionManager::GetPageWidth() const
256 : {
257 10 : return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0;
258 : }
259 :
260 1865 : sal_uInt32 wwSectionManager::GetTextAreaWidth() const
261 : {
262 1865 : return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0;
263 : }
264 :
265 12 : sal_uInt32 wwSectionManager::GetWWPageTopMargin() const
266 : {
267 12 : return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
268 : }
269 :
270 1 : sal_uInt16 SwWW8ImplReader::End_Footnote()
271 : {
272 : /*
273 : Ignoring Footnote outside of the normal Text. People will put footnotes
274 : into field results and field commands.
275 : */
276 2 : if (m_bIgnoreText ||
277 1 : m_pPaM->GetPoint()->nNode < m_rDoc.GetNodes().GetEndOfExtras().GetIndex())
278 : {
279 0 : return 0;
280 : }
281 :
282 : OSL_ENSURE(!m_aFootnoteStack.empty(), "footnote end without start");
283 1 : if (m_aFootnoteStack.empty())
284 0 : return 0;
285 :
286 1 : bool bFtEdOk = false;
287 1 : const FootnoteDescriptor &rDesc = m_aFootnoteStack.back();
288 :
289 : //Get the footnote character and remove it from the txtnode. We'll
290 : //replace it with the footnote
291 1 : SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
292 1 : sal_Int32 nPos = m_pPaM->GetPoint()->nContent.GetIndex();
293 :
294 1 : OUString sChar;
295 1 : SwTextAttr* pFN = 0;
296 : //There should have been a footnote char, we will replace this.
297 1 : if (pText && nPos)
298 : {
299 1 : sChar += OUString(pText->GetText()[--nPos]);
300 1 : m_pPaM->SetMark();
301 1 : --m_pPaM->GetMark()->nContent;
302 1 : m_rDoc.getIDocumentContentOperations().DeleteRange( *m_pPaM );
303 1 : m_pPaM->DeleteMark();
304 1 : SwFormatFootnote aFootnote(rDesc.meType == MAN_EDN);
305 1 : pFN = pText->InsertItem(aFootnote, nPos, nPos);
306 : }
307 : OSL_ENSURE(pFN, "Probleme beim Anlegen des Fussnoten-Textes");
308 1 : if (pFN)
309 : {
310 :
311 1 : SwPosition aTmpPos( *m_pPaM->GetPoint() ); // remember old cursor position
312 1 : WW8PLCFxSaveAll aSave;
313 1 : m_pPlcxMan->SaveAllPLCFx( aSave );
314 1 : WW8PLCFMan* pOldPlcxMan = m_pPlcxMan;
315 :
316 1 : const SwNodeIndex* pSttIdx = static_cast<SwTextFootnote*>(pFN)->GetStartNode();
317 : OSL_ENSURE(pSttIdx, "Probleme beim Anlegen des Fussnoten-Textes");
318 :
319 1 : static_cast<SwTextFootnote*>(pFN)->SetSeqNo( m_rDoc.GetFootnoteIdxs().size() );
320 :
321 1 : bool bOld = m_bFootnoteEdn;
322 1 : m_bFootnoteEdn = true;
323 :
324 : // read content of Ft-/End-Note
325 1 : Read_HdFtFootnoteText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType);
326 1 : bFtEdOk = true;
327 1 : m_bFootnoteEdn = bOld;
328 :
329 : OSL_ENSURE(sChar.getLength()==1 && ((rDesc.mbAutoNum == (sChar[0] == 2))),
330 : "footnote autonumbering must be 0x02, and everything else must not be");
331 :
332 : // If no automatic numbering use the following char from the main text
333 : // as the footnote number
334 1 : if (!rDesc.mbAutoNum)
335 0 : static_cast<SwTextFootnote*>(pFN)->SetNumber(0, sChar);
336 :
337 : /*
338 : Delete the footnote char from the footnote if its at the beginning
339 : as usual. Might not be if the user has already deleted it, e.g.
340 : #i14737#
341 : */
342 1 : SwNodeIndex& rNIdx = m_pPaM->GetPoint()->nNode;
343 1 : rNIdx = pSttIdx->GetIndex() + 1;
344 1 : SwTextNode* pTNd = rNIdx.GetNode().GetTextNode();
345 1 : if (pTNd && !pTNd->GetText().isEmpty() && !sChar.isEmpty())
346 : {
347 1 : const OUString &rText = pTNd->GetText();
348 1 : if (rText[0] == sChar[0])
349 : {
350 1 : m_pPaM->GetPoint()->nContent.Assign( pTNd, 0 );
351 1 : m_pPaM->SetMark();
352 : // Strip out tabs we may have inserted on export #i24762#
353 1 : if (rText.getLength() > 1 && rText[1] == 0x09)
354 1 : ++m_pPaM->GetMark()->nContent;
355 1 : ++m_pPaM->GetMark()->nContent;
356 1 : m_pReffingStck->Delete(*m_pPaM);
357 1 : m_rDoc.getIDocumentContentOperations().DeleteRange( *m_pPaM );
358 1 : m_pPaM->DeleteMark();
359 : }
360 : }
361 :
362 1 : *m_pPaM->GetPoint() = aTmpPos; // restore Cursor
363 :
364 1 : m_pPlcxMan = pOldPlcxMan; // Restore attributes
365 1 : m_pPlcxMan->RestoreAllPLCFx( aSave );
366 : }
367 :
368 1 : if (bFtEdOk)
369 1 : m_aSectionManager.SetCurrentSectionHasFootnote();
370 :
371 1 : m_aFootnoteStack.pop_back();
372 1 : return 0;
373 : }
374 :
375 1 : long SwWW8ImplReader::Read_Footnote(WW8PLCFManResult* pRes)
376 : {
377 : /*
378 : Ignoring Footnote outside of the normal Text. People will put footnotes
379 : into field results and field commands.
380 : */
381 2 : if (m_bIgnoreText ||
382 1 : m_pPaM->GetPoint()->nNode < m_rDoc.GetNodes().GetEndOfExtras().GetIndex())
383 : {
384 0 : return 0;
385 : }
386 :
387 : FootnoteDescriptor aDesc;
388 1 : aDesc.mbAutoNum = true;
389 1 : if (eEDN == pRes->nSprmId)
390 : {
391 0 : aDesc.meType = MAN_EDN;
392 0 : if (m_pPlcxMan->GetEdn())
393 0 : aDesc.mbAutoNum = 0 != *static_cast<short const *>(m_pPlcxMan->GetEdn()->GetData());
394 : }
395 : else
396 : {
397 1 : aDesc.meType = MAN_FTN;
398 1 : if (m_pPlcxMan->GetFootnote())
399 1 : aDesc.mbAutoNum = 0 != *static_cast<short const *>(m_pPlcxMan->GetFootnote()->GetData());
400 : }
401 :
402 1 : aDesc.mnStartCp = pRes->nCp2OrIdx;
403 1 : aDesc.mnLen = pRes->nMemLen;
404 :
405 1 : m_aFootnoteStack.push_back(aDesc);
406 :
407 1 : return 0;
408 : }
409 :
410 2163 : bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP* pPap, WW8_CP &rStartCp,
411 : int nLevel) const
412 : {
413 2163 : WW8PLCFxDesc aRes;
414 2163 : aRes.pMemPos = 0;
415 2163 : aRes.nEndPos = rStartCp;
416 :
417 23018 : while (pPap->HasFkp() && rStartCp != WW8_CP_MAX)
418 : {
419 20854 : if (pPap->Where() != WW8_CP_MAX)
420 : {
421 20854 : const sal_uInt8* pB = pPap->HasSprm(TabRowSprm(nLevel));
422 20854 : if (pB && *pB == 1)
423 : {
424 2225 : const sal_uInt8 *pLevel = 0;
425 2225 : if (0 != (pLevel = pPap->HasSprm(0x6649)))
426 : {
427 2225 : if (nLevel + 1 == *pLevel)
428 2162 : return true;
429 : }
430 : else
431 : {
432 : OSL_ENSURE(!nLevel || pLevel, "sublevel without level sprm");
433 0 : return true; // RowEnd found
434 : }
435 : }
436 : }
437 :
438 18692 : aRes.nStartPos = aRes.nEndPos;
439 18692 : aRes.pMemPos = 0;
440 : //Seek to our next block of properties
441 18692 : if (!(pPap->SeekPos(aRes.nStartPos)))
442 : {
443 1 : aRes.nEndPos = WW8_CP_MAX;
444 1 : pPap->SetDirty(true);
445 : }
446 18692 : pPap->GetSprms(&aRes);
447 18692 : pPap->SetDirty(false);
448 : //Update our aRes to get the new starting point of the next properties
449 18692 : rStartCp = aRes.nEndPos;
450 : }
451 :
452 1 : return false;
453 : }
454 :
455 4572 : ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd,
456 : const WW8_TablePos *pTabPos)
457 : {
458 4572 : const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : 0;
459 4572 : ApoTestResults aRet;
460 : // Frame in Style Definition (word appears to ignore them if inside an
461 : // text autoshape)
462 4572 : if (!m_bTxbxFlySection && m_nAktColl < m_vColl.size())
463 4506 : aRet.mpStyleApo = StyleExists(m_nAktColl) ? m_vColl[m_nAktColl].pWWFly : 0;
464 :
465 : /*
466 : #i1140#
467 : If I have a table and apply a style to one of its frames that should cause
468 : a paragraph that its applied to it to only exist as a separate floating
469 : frame, then the behaviour depends on which cell that it has been applied
470 : to. If its the first cell of a row then the whole table row jumps into the
471 : new frame, if its not then then the paragraph attributes are applied
472 : "except" for the floating frame stuff. i.e. its ignored. So if theres a
473 : table, and we're not in the first cell then we ignore the fact that the
474 : paragraph style wants to be in a different frame.
475 :
476 : This sort of mindbending inconsistency is surely why frames are deprecated
477 : in word 97 onwards and hidden away from the user
478 :
479 : #i1532# & #i5379#
480 : If we are already a table in a frame then we must grab the para properties
481 : to see if we are still in that frame.
482 : */
483 :
484 4572 : aRet.m_bHasSprm37 = m_pPlcxMan->HasParaSprm( m_bVer67 ? 37 : 0x2423 );
485 4572 : const sal_uInt8 *pSrpm29 = m_pPlcxMan->HasParaSprm( m_bVer67 ? 29 : 0x261B );
486 4572 : aRet.m_bHasSprm29 = pSrpm29 != NULL;
487 4572 : aRet.m_nSprm29 = pSrpm29 ? *pSrpm29 : 0;
488 :
489 : // Is there some frame data here
490 4572 : bool bNowApo = aRet.HasFrame() || pTopLevelTable;
491 4572 : if (bNowApo)
492 : {
493 114 : if (WW8FlyPara *pTest = ConstructApo(aRet, pTabPos))
494 114 : delete pTest;
495 : else
496 0 : bNowApo = false;
497 : }
498 :
499 4572 : bool bTestAllowed = !m_bTxbxFlySection && !bTableRowEnd;
500 4572 : if (bTestAllowed)
501 : {
502 : //Test is allowed if there is no table.
503 : //Otherwise only allowed if we are in the
504 : //first paragraph of the first cell of a row.
505 : //(And only if the row we are inside is at the
506 : //same level as the previous row, think tables
507 : //in tables)
508 4235 : if (nCellLevel == m_nInTable)
509 : {
510 :
511 3877 : if (!m_nInTable)
512 2642 : bTestAllowed = true;
513 : else
514 : {
515 1235 : if (!m_pTableDesc)
516 : {
517 : OSL_ENSURE(m_pTableDesc, "What!");
518 0 : bTestAllowed = false;
519 : }
520 : else
521 : {
522 : // #i39468#
523 : // If current cell isn't valid, the test is allowed.
524 : // The cell isn't valid, if e.g. there is a new row
525 : // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
526 : bTestAllowed =
527 1924 : m_pTableDesc->GetAktCol() == 0 &&
528 946 : ( !m_pTableDesc->IsValidCell( m_pTableDesc->GetAktCol() ) ||
529 1707 : m_pTableDesc->InFirstParaInCell() );
530 : }
531 : }
532 : }
533 : }
534 :
535 4572 : if (!bTestAllowed)
536 1357 : return aRet;
537 :
538 3215 : aRet.mbStartApo = bNowApo && !InAnyApo(); // APO-start
539 3215 : aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo; // APO-end
540 :
541 : //If it happens that we are in a table, then if its not the first cell
542 : //then any attributes that might otherwise cause the contents to jump
543 : //into another frame don't matter, a table row sticks together as one
544 : //unit no matter what else happens. So if we are not in a table at
545 : //all, or if we are in the first cell then test that the last frame
546 : //data is the same as the current one
547 3215 : if (bNowApo && InEqualApo(nCellLevel))
548 : {
549 : // two bordering eachother
550 16 : if (!TestSameApo(aRet, pTabPos))
551 0 : aRet.mbStopApo = aRet.mbStartApo = true;
552 : }
553 :
554 3215 : return aRet;
555 : }
556 :
557 : // helper methods for outline, numbering and bullets
558 :
559 1 : static void SetBaseAnlv(SwNumFormat &rNum, WW8_ANLV const &rAV, sal_uInt8 nSwLevel )
560 : {
561 : static const SvxExtNumType eNumA[8] = { SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
562 : SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N, SVX_NUM_ARABIC,
563 : SVX_NUM_ARABIC, SVX_NUM_ARABIC };
564 :
565 : static const SvxAdjust eAdjA[4] = { SVX_ADJUST_LEFT,
566 : SVX_ADJUST_RIGHT, SVX_ADJUST_LEFT, SVX_ADJUST_LEFT };
567 1 : if (rAV.nfc < 8) {
568 1 : rNum.SetNumberingType( static_cast< sal_Int16 >(eNumA[ rAV.nfc ] ));
569 : } else {
570 0 : sal_Int16 nType= style::NumberingType::ARABIC;
571 0 : switch( rAV.nfc ) {
572 : case 14:
573 0 : case 19:nType = style::NumberingType::FULLWIDTH_ARABIC; break;
574 0 : case 30:nType = style::NumberingType::TIAN_GAN_ZH; break;
575 0 : case 31:nType = style::NumberingType::DI_ZI_ZH; break;
576 : case 35:
577 : case 36:
578 : case 37:
579 : case 39:
580 0 : nType = style::NumberingType::NUMBER_LOWER_ZH; break;
581 0 : case 34:nType = style::NumberingType::NUMBER_UPPER_ZH_TW;break;
582 0 : case 38:nType = style::NumberingType::NUMBER_UPPER_ZH; break;
583 : case 10:
584 : case 11:
585 0 : nType = style::NumberingType::NUMBER_TRADITIONAL_JA;break;
586 0 : case 20:nType = style::NumberingType::AIU_FULLWIDTH_JA;break;
587 0 : case 12:nType = style::NumberingType::AIU_HALFWIDTH_JA;break;
588 0 : case 21:nType = style::NumberingType::IROHA_FULLWIDTH_JA;break;
589 0 : case 13:nType = style::NumberingType::IROHA_HALFWIDTH_JA;break;
590 0 : case 24:nType = style::NumberingType::HANGUL_SYLLABLE_KO;break;
591 0 : case 25:nType = style::NumberingType::HANGUL_JAMO_KO;break;
592 0 : case 41:nType = style::NumberingType::NUMBER_HANGUL_KO;break;
593 : //case 42:
594 : //case 43:
595 0 : case 44:nType = style::NumberingType::NUMBER_UPPER_KO; break;
596 : default:
597 0 : nType= style::NumberingType::ARABIC;break;
598 : }
599 0 : rNum.SetNumberingType( nType );
600 : }
601 :
602 1 : if ((rAV.aBits1 & 0x4) >> 2)
603 : {
604 0 : rNum.SetIncludeUpperLevels(nSwLevel + 1);
605 : }
606 1 : rNum.SetStart( SVBT16ToShort( rAV.iStartAt ) );
607 1 : rNum.SetNumAdjust( eAdjA[ rAV.aBits1 & 0x3] );
608 :
609 1 : rNum.SetCharTextDistance( SVBT16ToShort( rAV.dxaSpace ) );
610 1 : sal_Int16 nIndent = std::abs((sal_Int16)SVBT16ToShort( rAV.dxaIndent ));
611 1 : if( rAV.aBits1 & 0x08 ) //fHang
612 : {
613 1 : rNum.SetFirstLineOffset( -nIndent );
614 1 : rNum.SetAbsLSpace( nIndent );
615 : }
616 : else
617 0 : rNum.SetCharTextDistance( nIndent ); // width of number is missing
618 :
619 1 : if( rAV.nfc == 5 || rAV.nfc == 7 )
620 : {
621 0 : OUString sP = "." + rNum.GetSuffix();
622 0 : rNum.SetSuffix( sP ); // ordinal number
623 : }
624 1 : }
625 :
626 1 : void SwWW8ImplReader::SetAnlvStrings(SwNumFormat &rNum, WW8_ANLV const &rAV,
627 : const sal_uInt8* pText, bool bOutline)
628 : {
629 1 : bool bInsert = false; // Default
630 1 : rtl_TextEncoding eCharSet = m_eStructCharSet;
631 :
632 1 : const WW8_FFN* pF = m_pFonts->GetFont(SVBT16ToShort(rAV.ftc)); // FontInfo
633 1 : bool bListSymbol = pF && ( pF->chs == 2 ); // Symbol/WingDings/...
634 :
635 1 : OUString sText;
636 1 : if (m_bVer67)
637 : {
638 0 : sText = OUString(reinterpret_cast<char const *>(pText), rAV.cbTextBefore + rAV.cbTextAfter, eCharSet);
639 : }
640 : else
641 : {
642 2 : for(sal_Int32 i = 0; i < rAV.cbTextBefore + rAV.cbTextAfter; ++i, pText += 2)
643 : {
644 1 : sText += OUString(SVBT16ToShort(*reinterpret_cast<SVBT16 const *>(pText)));
645 : }
646 : }
647 :
648 1 : if( bOutline )
649 : { // outline
650 0 : if( !rNum.GetIncludeUpperLevels() // there are <= 1 number to show
651 0 : || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ) // or this level has none
652 : {
653 : // if self defined digits
654 0 : bInsert = true; // then apply character
655 :
656 : // replace by simple Bullet ?
657 0 : if( bListSymbol )
658 : {
659 : // use cBulletChar for correct mapping on MAC
660 0 : OUStringBuffer aBuf;
661 : comphelper::string::padToLength(aBuf, rAV.cbTextBefore
662 0 : + rAV.cbTextAfter, cBulletChar);
663 0 : sText = aBuf.makeStringAndClear();
664 : }
665 : }
666 : }
667 : else
668 : { // numbering / bullets
669 1 : bInsert = true;
670 1 : if( bListSymbol )
671 : {
672 : FontFamily eFamily;
673 0 : OUString aName;
674 : FontPitch ePitch;
675 :
676 0 : if( GetFontParams( SVBT16ToShort( rAV.ftc ), eFamily, aName,
677 0 : ePitch, eCharSet ) ){
678 :
679 0 : vcl::Font aFont;
680 0 : aFont.SetName( aName );
681 0 : aFont.SetFamily( eFamily );
682 :
683 0 : aFont.SetCharSet( eCharSet );
684 0 : rNum.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
685 :
686 0 : rNum.SetBulletFont( &aFont );
687 :
688 : // take only the very first character
689 0 : if (rAV.cbTextBefore || rAV.cbTextAfter)
690 0 : rNum.SetBulletChar( sText[ 0 ] );
691 : else
692 0 : rNum.SetBulletChar( 0x2190 );
693 0 : }
694 : }
695 : }
696 1 : if( bInsert )
697 : {
698 1 : if (rAV.cbTextBefore)
699 : {
700 0 : OUString sP( sText.copy( 0, rAV.cbTextBefore ) );
701 0 : rNum.SetPrefix( sP );
702 : }
703 1 : if( rAV.cbTextAfter )
704 : {
705 1 : OUString sP( rNum.GetSuffix() );
706 1 : sP += sText.copy( rAV.cbTextBefore, rAV.cbTextAfter);
707 1 : rNum.SetSuffix( sP );
708 : }
709 : // The characters before and after multipe digits do not apply because
710 : // those are handled different by the writer and the result is in most
711 : // cases worse than without.
712 1 : }
713 1 : }
714 :
715 : // SetAnld gets a WW-ANLD-Descriptor and a Level and modifies the NumRules
716 : // which are provided by pNumR. This is used for everything beside
717 : // outline inside the text.
718 1 : void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD const * pAD, sal_uInt8 nSwLevel,
719 : bool bOutLine)
720 : {
721 1 : SwNumFormat aNF;
722 1 : if (pAD)
723 : { // there is a Anld-Sprm
724 1 : m_bAktAND_fNumberAcross = 0 != pAD->fNumberAcross;
725 1 : WW8_ANLV const &rAV = pAD->eAnlv;
726 1 : SetBaseAnlv(aNF, rAV, nSwLevel); // set the base format
727 1 : SetAnlvStrings(aNF, rAV, pAD->rgchAnld, bOutLine ); // set the rest
728 : }
729 1 : pNumR->Set(nSwLevel, aNF);
730 1 : }
731 :
732 : // chapter numbering and bullets
733 :
734 : // Chapter numbering happens in the style definition.
735 : // Sprm 13 provides the level, Sprm 12 the content.
736 :
737 1 : SwNumRule* SwWW8ImplReader::GetStyRule()
738 : {
739 1 : if( m_pStyles->pStyRule ) // Bullet-Style already present
740 0 : return m_pStyles->pStyRule;
741 :
742 1 : const OUString aBaseName("WW8StyleNum");
743 2 : const OUString aName( m_rDoc.GetUniqueNumRuleName( &aBaseName, false) );
744 :
745 : // #i86652#
746 : sal_uInt16 nRul = m_rDoc.MakeNumRule( aName, 0, false,
747 1 : SvxNumberFormat::LABEL_ALIGNMENT );
748 1 : m_pStyles->pStyRule = m_rDoc.GetNumRuleTable()[nRul];
749 : // Auto == false-> Nummerierungsvorlage
750 1 : m_pStyles->pStyRule->SetAutoRule(false);
751 :
752 2 : return m_pStyles->pStyRule;
753 : }
754 :
755 : // Sprm 13
756 0 : void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16, const sal_uInt8* pData, short nLen )
757 : {
758 0 : m_nSwNumLevel = 0xff; // Default: invalid
759 :
760 0 : if( nLen <= 0 )
761 0 : return;
762 :
763 : // StyleDef ?
764 0 : if( m_pAktColl )
765 : {
766 : // only for SwTextFormatColl, not CharFormat
767 : // WW: 0 = no Numbering
768 0 : SwWW8StyInf * pColl = GetStyle(m_nAktColl);
769 0 : if (pColl != NULL && pColl->bColl && *pData)
770 : {
771 : // Range WW:1..9 -> SW:0..8 no bullets / numbering
772 :
773 0 : if (*pData <= MAXLEVEL && *pData <= 9)
774 : {
775 0 : m_nSwNumLevel = *pData - 1;
776 0 : if (!m_bNoAttrImport)
777 0 : static_cast<SwTextFormatColl*>(m_pAktColl)->AssignToListLevelOfOutlineStyle( m_nSwNumLevel );
778 : // For WW-NoNumbering also NO_NUMBERING could be used.
779 : // ( For normal numberierung NO_NUM has to be used:
780 : // NO_NUM : pauses numbering,
781 : // NO_NUMBERING : no numbering at all )
782 :
783 : }
784 0 : else if( *pData == 10 || *pData == 11 )
785 : {
786 : // remember type, the rest happens at Sprm 12
787 0 : m_pStyles->nWwNumLevel = *pData;
788 : }
789 : }
790 : }
791 : else
792 : {
793 : //Not StyleDef
794 0 : if (!m_bAnl)
795 0 : StartAnl(pData); // begin of outline / bullets
796 0 : NextAnlLine(pData);
797 : }
798 : }
799 :
800 1 : void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm 12
801 : {
802 1 : SwWW8StyInf * pStyInf = GetStyle(m_nAktColl);
803 1 : if( !m_pAktColl || nLen <= 0 // only for Styledef
804 1 : || (pStyInf && !pStyInf->bColl) // ignore CharFormat ->
805 1 : || ( m_nIniFlags & WW8FL_NO_OUTLINE ) )
806 : {
807 0 : m_nSwNumLevel = 0xff;
808 1 : return;
809 : }
810 :
811 1 : if( m_nSwNumLevel <= MAXLEVEL // Value range mapping WW:1..9 -> SW:0..8
812 0 : && m_nSwNumLevel <= 9 ){ // No Bullets or Numbering
813 :
814 : // If NumRuleItems were set, either directly or through inheritance, disable them now
815 0 : m_pAktColl->SetFormatAttr( SwNumRuleItem() );
816 :
817 0 : const OUString aName("Outline");
818 : SwNumRule aNR( m_rDoc.GetUniqueNumRuleName( &aName ),
819 : SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
820 0 : OUTLINE_RULE );
821 0 : aNR = *m_rDoc.GetOutlineNumRule();
822 :
823 0 : SetAnld(&aNR, reinterpret_cast<WW8_ANLD const *>(pData), m_nSwNumLevel, true);
824 :
825 : // Missing Levels need not be replenished
826 0 : m_rDoc.SetOutlineNumRule( aNR );
827 1 : }else if( m_pStyles->nWwNumLevel == 10 || m_pStyles->nWwNumLevel == 11 ){
828 1 : SwNumRule* pNR = GetStyRule();
829 1 : SetAnld(pNR, reinterpret_cast<WW8_ANLD const *>(pData), 0, false);
830 1 : m_pAktColl->SetFormatAttr( SwNumRuleItem( pNR->GetName() ) );
831 :
832 1 : pStyInf = GetStyle(m_nAktColl);
833 1 : if (pStyInf != NULL)
834 1 : pStyInf->bHasStyNumRule = true;
835 : }
836 : }
837 :
838 : // Numbering / Bullets
839 :
840 : // SetNumOlst() carries the Numrules for this cell to SwNumFormat.
841 : // For this the info is fetched from OLST and not from ANLD ( see later )
842 : // ( only for outline inside text; Bullets / numbering use ANLDs )
843 0 : void SwWW8ImplReader::SetNumOlst(SwNumRule* pNumR, WW8_OLST* pO, sal_uInt8 nSwLevel)
844 : {
845 0 : SwNumFormat aNF;
846 0 : WW8_ANLV &rAV = pO->rganlv[nSwLevel];
847 0 : SetBaseAnlv(aNF, rAV, nSwLevel);
848 : // ... and then the Strings
849 0 : int nTextOfs = 0;
850 : sal_uInt8 i;
851 : WW8_ANLV* pAV1; // search String-Positions
852 0 : for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1)
853 0 : nTextOfs += pAV1->cbTextBefore + pAV1->cbTextAfter;
854 :
855 0 : if (!m_bVer67)
856 0 : nTextOfs *= 2;
857 0 : SetAnlvStrings(aNF, rAV, pO->rgch + nTextOfs, true); // and apply
858 0 : pNumR->Set(nSwLevel, aNF);
859 0 : }
860 :
861 : // The OLST is at the beginning of each section that contains outlines.
862 : // The ANLDs that are connected to each outline-line contain only nonsense,
863 : // so the OLSTs are remembered for the section to have usable information
864 : // when outline-paragraphs occur.
865 2 : void SwWW8ImplReader::Read_OLST( sal_uInt16, const sal_uInt8* pData, short nLen )
866 : {
867 2 : delete m_pNumOlst;
868 2 : if (nLen <= 0)
869 : {
870 1 : m_pNumOlst = 0;
871 3 : return;
872 : }
873 1 : m_pNumOlst = new WW8_OLST;
874 1 : if( nLen < sal::static_int_cast< sal_Int32 >(sizeof( WW8_OLST )) ) // fill if to short
875 0 : memset( m_pNumOlst, 0, sizeof( *m_pNumOlst ) );
876 1 : *m_pNumOlst = *reinterpret_cast<WW8_OLST const *>(pData);
877 : }
878 :
879 0 : WW8LvlType GetNumType(sal_uInt8 nWwLevelNo)
880 : {
881 0 : WW8LvlType nRet = WW8_None;
882 0 : if( nWwLevelNo == 12 )
883 0 : nRet = WW8_Pause;
884 0 : else if( nWwLevelNo == 10 )
885 0 : nRet = WW8_Numbering;
886 0 : else if( nWwLevelNo == 11 )
887 0 : nRet = WW8_Sequence;
888 0 : else if( nWwLevelNo > 0 && nWwLevelNo <= 9 )
889 0 : nRet = WW8_Outline;
890 0 : return nRet;
891 : }
892 :
893 0 : SwNumRule *ANLDRuleMap::GetNumRule(sal_uInt8 nNumType)
894 : {
895 0 : return (WW8_Numbering == nNumType ? mpNumberingNumRule : mpOutlineNumRule);
896 : }
897 :
898 0 : void ANLDRuleMap::SetNumRule(SwNumRule *pRule, sal_uInt8 nNumType)
899 : {
900 0 : if (WW8_Numbering == nNumType)
901 0 : mpNumberingNumRule = pRule;
902 : else
903 0 : mpOutlineNumRule = pRule;
904 0 : }
905 :
906 : // StartAnl is called at the beginning of a row area that contains
907 : // outline / numbering / bullets
908 0 : void SwWW8ImplReader::StartAnl(const sal_uInt8* pSprm13)
909 : {
910 0 : m_bAktAND_fNumberAcross = false;
911 :
912 0 : sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType(*pSprm13));
913 0 : if (nT == WW8_Pause || nT == WW8_None)
914 0 : return;
915 :
916 0 : m_nWwNumType = nT;
917 0 : SwNumRule *pNumRule = m_aANLDRules.GetNumRule(m_nWwNumType);
918 :
919 : // check for COL numbering:
920 0 : const sal_uInt8* pS12 = 0;// sprmAnld
921 0 : OUString sNumRule;
922 :
923 0 : if (m_pTableDesc)
924 : {
925 0 : sNumRule = m_pTableDesc->GetNumRuleName();
926 0 : if (!sNumRule.isEmpty())
927 : {
928 0 : pNumRule = m_rDoc.FindNumRulePtr(sNumRule);
929 0 : if (!pNumRule)
930 0 : sNumRule.clear();
931 : else
932 : {
933 : // this is ROW numbering ?
934 0 : pS12 = m_pPlcxMan->HasParaSprm(m_bVer67 ? 12 : 0xC63E); // sprmAnld
935 0 : if (pS12 && 0 != reinterpret_cast<WW8_ANLD const *>(pS12)->fNumberAcross)
936 0 : sNumRule.clear();
937 : }
938 : }
939 : }
940 :
941 0 : SwWW8StyInf * pStyInf = GetStyle(m_nAktColl);
942 0 : if (sNumRule.isEmpty() && pStyInf != NULL && pStyInf->bHasStyNumRule)
943 : {
944 0 : sNumRule = pStyInf->pFormat->GetNumRule().GetValue();
945 0 : pNumRule = m_rDoc.FindNumRulePtr(sNumRule);
946 0 : if (!pNumRule)
947 0 : sNumRule.clear();
948 : }
949 :
950 0 : if (sNumRule.isEmpty())
951 : {
952 0 : if (!pNumRule)
953 : {
954 : // #i86652#
955 0 : pNumRule = m_rDoc.GetNumRuleTable()[
956 : m_rDoc.MakeNumRule( sNumRule, 0, false,
957 0 : SvxNumberFormat::LABEL_ALIGNMENT ) ];
958 : }
959 0 : if (m_pTableDesc)
960 : {
961 0 : if (!pS12)
962 0 : pS12 = m_pPlcxMan->HasParaSprm(m_bVer67 ? 12 : 0xC63E); // sprmAnld
963 0 : if (!pS12 || !reinterpret_cast<WW8_ANLD const *>(pS12)->fNumberAcross)
964 0 : m_pTableDesc->SetNumRuleName(pNumRule->GetName());
965 : }
966 : }
967 :
968 0 : m_bAnl = true;
969 :
970 0 : sNumRule = pNumRule ? pNumRule->GetName() : OUString();
971 : // set NumRules via stack
972 0 : m_pCtrlStck->NewAttr(*m_pPaM->GetPoint(),
973 0 : SfxStringItem(RES_FLTR_NUMRULE, sNumRule));
974 :
975 0 : m_aANLDRules.SetNumRule(pNumRule, m_nWwNumType);
976 : }
977 :
978 : // NextAnlLine() is called once for every row of a
979 : // outline / numbering / bullet
980 0 : void SwWW8ImplReader::NextAnlLine(const sal_uInt8* pSprm13)
981 : {
982 0 : if (!m_bAnl)
983 0 : return;
984 :
985 0 : SwNumRule *pNumRule = m_aANLDRules.GetNumRule(m_nWwNumType);
986 :
987 : // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
988 : // sdw3
989 :
990 : // WW:10 = numberierung -> SW:0 & WW:11 = bullets -> SW:0
991 0 : if (*pSprm13 == 10 || *pSprm13 == 11)
992 : {
993 0 : m_nSwNumLevel = 0;
994 0 : if (!pNumRule->GetNumFormat(m_nSwNumLevel))
995 : {
996 : // not defined yet
997 : // sprmAnld o. 0
998 0 : const sal_uInt8* pS12 = m_pPlcxMan->HasParaSprm(m_bVer67 ? 12 : 0xC63E);
999 0 : SetAnld(pNumRule, reinterpret_cast<WW8_ANLD const *>(pS12), m_nSwNumLevel, false);
1000 0 : }
1001 : }
1002 0 : else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL ) // range WW:1..9 -> SW:0..8
1003 : {
1004 0 : m_nSwNumLevel = *pSprm13 - 1; // outline
1005 : // undefined
1006 0 : if (!pNumRule->GetNumFormat(m_nSwNumLevel))
1007 : {
1008 0 : if (m_pNumOlst) // there was a OLST
1009 : {
1010 : //Assure upper levels are set, #i9556#
1011 0 : for (sal_uInt8 nI = 0; nI < m_nSwNumLevel; ++nI)
1012 : {
1013 0 : if (!pNumRule->GetNumFormat(nI))
1014 0 : SetNumOlst(pNumRule, m_pNumOlst, nI);
1015 : }
1016 :
1017 0 : SetNumOlst(pNumRule, m_pNumOlst , m_nSwNumLevel);
1018 : }
1019 : else // no Olst -> use Anld
1020 : {
1021 : // sprmAnld
1022 0 : const sal_uInt8* pS12 = m_pPlcxMan->HasParaSprm(m_bVer67 ? 12 : 0xC63E);
1023 0 : SetAnld(pNumRule, reinterpret_cast<WW8_ANLD const *>(pS12), m_nSwNumLevel, false);
1024 : }
1025 0 : }
1026 : }
1027 : else
1028 0 : m_nSwNumLevel = 0xff; // no number
1029 :
1030 0 : SwTextNode* pNd = m_pPaM->GetNode().GetTextNode();
1031 0 : if (m_nSwNumLevel < MAXLEVEL)
1032 0 : pNd->SetAttrListLevel( m_nSwNumLevel );
1033 : else
1034 : {
1035 0 : pNd->SetAttrListLevel(0);
1036 0 : pNd->SetCountedInList( false );
1037 : }
1038 : }
1039 :
1040 0 : void SwWW8ImplReader::StopAllAnl(bool bGoBack)
1041 : {
1042 : //Of course we're not restarting, but we'll make use of our knowledge
1043 : //of the implementation to do it.
1044 0 : StopAnlToRestart(WW8_None, bGoBack);
1045 0 : }
1046 :
1047 0 : void SwWW8ImplReader::StopAnlToRestart(sal_uInt8 nNewType, bool bGoBack)
1048 : {
1049 0 : if (bGoBack)
1050 : {
1051 0 : SwPosition aTmpPos(*m_pPaM->GetPoint());
1052 0 : m_pPaM->Move(fnMoveBackward, fnGoContent);
1053 0 : m_pCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FLTR_NUMRULE);
1054 0 : *m_pPaM->GetPoint() = aTmpPos;
1055 : }
1056 : else
1057 0 : m_pCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FLTR_NUMRULE);
1058 :
1059 0 : m_aANLDRules.mpNumberingNumRule = 0;
1060 : /*
1061 : #i18816#
1062 : my take on this problem is that moving either way from an outline to a
1063 : numbering doesn't halt the outline, while the numbering is always halted
1064 : */
1065 : bool bNumberingNotStopOutline =
1066 0 : (((m_nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) ||
1067 0 : ((m_nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline)));
1068 0 : if (!bNumberingNotStopOutline)
1069 0 : m_aANLDRules.mpOutlineNumRule = 0;
1070 :
1071 0 : m_nSwNumLevel = 0xff;
1072 0 : m_nWwNumType = WW8_None;
1073 0 : m_bAnl = false;
1074 0 : }
1075 :
1076 0 : WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc& rBand )
1077 : {
1078 0 : *this = rBand;
1079 0 : if( rBand.pTCs )
1080 : {
1081 0 : pTCs = new WW8_TCell[nWwCols];
1082 0 : memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1083 : }
1084 0 : if( rBand.pSHDs )
1085 : {
1086 0 : pSHDs = new WW8_SHD[nWwCols];
1087 0 : memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1088 : }
1089 0 : if( rBand.pNewSHDs )
1090 : {
1091 0 : pNewSHDs = new sal_uInt32[nWwCols];
1092 0 : memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(sal_uInt32));
1093 : }
1094 0 : memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1095 0 : }
1096 :
1097 : // ReadDef reads the cell position and the borders of a band
1098 2146 : void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS)
1099 : {
1100 2146 : if (!bVer67)
1101 2146 : pS++;
1102 :
1103 2146 : short nLen = (sal_Int16)SVBT16ToShort( pS - 2 ); // not beautiful
1104 :
1105 2146 : sal_uInt8 nCols = *pS; // number of cells
1106 2146 : short nOldCols = nWwCols;
1107 :
1108 2146 : if( nCols > MAX_COL )
1109 2146 : return;
1110 :
1111 2146 : nWwCols = nCols;
1112 :
1113 2146 : const sal_uInt8* pT = &pS[1];
1114 2146 : nLen --;
1115 : int i;
1116 13253 : for(i=0; i<=nCols; i++, pT+=2 )
1117 11107 : nCenter[i] = (sal_Int16)SVBT16ToShort( pT ); // X-borders
1118 2146 : nLen -= 2 * ( nCols + 1 );
1119 2146 : if( nCols != nOldCols ) // different column count
1120 : {
1121 2146 : delete[] pTCs, pTCs = 0;
1122 2146 : delete[] pSHDs, pSHDs = 0;
1123 2146 : delete[] pNewSHDs, pNewSHDs = 0;
1124 : }
1125 :
1126 2146 : short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // really saved
1127 :
1128 2146 : if (!pTCs && nCols)
1129 : {
1130 : // create empty TCs
1131 2146 : pTCs = new WW8_TCell[nCols];
1132 2146 : setcelldefaults(pTCs,nCols);
1133 : }
1134 :
1135 2146 : short nColsToRead = nFileCols;
1136 2146 : if (nColsToRead > nCols)
1137 8 : nColsToRead = nCols;
1138 :
1139 2146 : if( nColsToRead )
1140 : {
1141 : // read TCs
1142 :
1143 : /*
1144 : Attention: Beginning with Ver8 there is an extra ushort per TC
1145 : added and the size of the border code is doubled.
1146 : Because of this a simple copy (pTCs[i] = *pTc;)
1147 : is not possible.
1148 : ---
1149 : Advantage: The work structure suits better.
1150 : */
1151 2146 : WW8_TCell* pAktTC = pTCs;
1152 2146 : if( bVer67 )
1153 : {
1154 0 : WW8_TCellVer6 const * pTc = reinterpret_cast<WW8_TCellVer6 const *>(pT);
1155 0 : for(i=0; i<nColsToRead; i++, ++pAktTC,++pTc)
1156 : {
1157 0 : if( i < nColsToRead )
1158 : { // TC from file ?
1159 0 : sal_uInt8 aBits1 = pTc->aBits1Ver6;
1160 0 : pAktTC->bFirstMerged = sal_uInt8( ( aBits1 & 0x01 ) != 0 );
1161 0 : pAktTC->bMerged = sal_uInt8( ( aBits1 & 0x02 ) != 0 );
1162 : pAktTC->rgbrc[ WW8_TOP ]
1163 0 : = WW8_BRC( pTc->rgbrcVer6[ WW8_TOP ] );
1164 : pAktTC->rgbrc[ WW8_LEFT ]
1165 0 : = WW8_BRC( pTc->rgbrcVer6[ WW8_LEFT ] );
1166 : pAktTC->rgbrc[ WW8_BOT ]
1167 0 : = WW8_BRC( pTc->rgbrcVer6[ WW8_BOT ] );
1168 : pAktTC->rgbrc[ WW8_RIGHT ]
1169 0 : = WW8_BRC( pTc->rgbrcVer6[ WW8_RIGHT ] );
1170 0 : if( ( pAktTC->bMerged )
1171 0 : && ( i > 0 ) )
1172 : {
1173 : // Cell merged -> remember
1174 : //bWWMergedVer6[i] = true;
1175 : pTCs[i-1].rgbrc[ WW8_RIGHT ]
1176 0 : = WW8_BRC( pTc->rgbrcVer6[ WW8_RIGHT ] );
1177 : // apply right border to previous cell
1178 : // bExist must not be set to false, because WW
1179 : // does not count this cells in text boxes....
1180 : }
1181 : }
1182 : }
1183 : }
1184 : else
1185 : {
1186 2146 : WW8_TCellVer8 const * pTc = reinterpret_cast<WW8_TCellVer8 const *>(pT);
1187 10099 : for (int k = 0; k < nColsToRead; ++k, ++pAktTC, ++pTc )
1188 : {
1189 7953 : sal_uInt16 aBits1 = SVBT16ToShort( pTc->aBits1Ver8 );
1190 7953 : pAktTC->bFirstMerged = sal_uInt8( ( aBits1 & 0x0001 ) != 0 );
1191 7953 : pAktTC->bMerged = sal_uInt8( ( aBits1 & 0x0002 ) != 0 );
1192 7953 : pAktTC->bVertical = sal_uInt8( ( aBits1 & 0x0004 ) != 0 );
1193 7953 : pAktTC->bBackward = sal_uInt8( ( aBits1 & 0x0008 ) != 0 );
1194 7953 : pAktTC->bRotateFont = sal_uInt8( ( aBits1 & 0x0010 ) != 0 );
1195 7953 : pAktTC->bVertMerge = sal_uInt8( ( aBits1 & 0x0020 ) != 0 );
1196 7953 : pAktTC->bVertRestart = sal_uInt8( ( aBits1 & 0x0040 ) != 0 );
1197 7953 : pAktTC->nVertAlign = ( ( aBits1 & 0x0180 ) >> 7 );
1198 : // note: in aBits1 there are 7 bits unused,
1199 : // followed by another 16 unused bits
1200 :
1201 7953 : pAktTC->rgbrc[ WW8_TOP ] = pTc->rgbrcVer8[ WW8_TOP ];
1202 7953 : pAktTC->rgbrc[ WW8_LEFT ] = pTc->rgbrcVer8[ WW8_LEFT ];
1203 7953 : pAktTC->rgbrc[ WW8_BOT ] = pTc->rgbrcVer8[ WW8_BOT ];
1204 7953 : pAktTC->rgbrc[ WW8_RIGHT ] = pTc->rgbrcVer8[ WW8_RIGHT ];
1205 : }
1206 : }
1207 :
1208 : // #i25071 In '97 text direction appears to be only set using TC properties
1209 : // not with sprmTTextFlow so we need to cycle through the maDirections and
1210 : // double check any non-default directions
1211 11107 : for (int k = 0; k < nCols; ++k)
1212 : {
1213 8961 : if(maDirections[k] == 4)
1214 : {
1215 8961 : if(pTCs[k].bVertical)
1216 : {
1217 8 : if(pTCs[k].bBackward)
1218 8 : maDirections[k] = 3;
1219 : else
1220 0 : maDirections[k] = 1;
1221 : }
1222 : }
1223 : }
1224 : }
1225 : }
1226 :
1227 298 : void WW8TabBandDesc::ProcessSprmTSetBRC(int nBrcVer, const sal_uInt8* pParamsTSetBRC)
1228 : {
1229 298 : if( pParamsTSetBRC && pTCs ) // set one or more cell border(s)
1230 : {
1231 298 : sal_uInt8 nitcFirst= pParamsTSetBRC[0];// first col to be changed
1232 298 : sal_uInt8 nitcLim = pParamsTSetBRC[1];// (last col to be changed)+1
1233 298 : sal_uInt8 nFlag = *(pParamsTSetBRC+2);
1234 :
1235 298 : if (nitcFirst >= nWwCols)
1236 298 : return;
1237 :
1238 298 : if (nitcLim > nWwCols)
1239 1 : nitcLim = nWwCols;
1240 :
1241 298 : bool bChangeRight = (nFlag & 0x08) != 0;
1242 298 : bool bChangeBottom = (nFlag & 0x04) != 0;
1243 298 : bool bChangeLeft = (nFlag & 0x02) != 0;
1244 298 : bool bChangeTop = (nFlag & 0x01) != 0;
1245 :
1246 298 : WW8_TCell* pAktTC = pTCs + nitcFirst;
1247 298 : WW8_BRCVer9 brcVer9;
1248 298 : if( nBrcVer == 6 )
1249 0 : brcVer9 = WW8_BRC(*reinterpret_cast<WW8_BRCVer6 const *>(pParamsTSetBRC+3));
1250 298 : else if( nBrcVer == 8 )
1251 1 : brcVer9 = *reinterpret_cast<WW8_BRC const *>(pParamsTSetBRC+3);
1252 : else
1253 297 : brcVer9 = *reinterpret_cast<WW8_BRCVer9 const *>(pParamsTSetBRC+3);
1254 :
1255 695 : for( int i = nitcFirst; i < nitcLim; ++i, ++pAktTC )
1256 : {
1257 397 : if( bChangeTop )
1258 160 : pAktTC->rgbrc[ WW8_TOP ] = brcVer9;
1259 397 : if( bChangeLeft )
1260 158 : pAktTC->rgbrc[ WW8_LEFT ] = brcVer9;
1261 397 : if( bChangeBottom )
1262 171 : pAktTC->rgbrc[ WW8_BOT ] = brcVer9;
1263 397 : if( bChangeRight )
1264 111 : pAktTC->rgbrc[ WW8_RIGHT ] = brcVer9;
1265 : }
1266 : }
1267 : }
1268 :
1269 180 : void WW8TabBandDesc::ProcessSprmTTableBorders(int nBrcVer, const sal_uInt8* pParams)
1270 : {
1271 : // sprmTTableBorders
1272 180 : if( nBrcVer == 6 )
1273 : {
1274 0 : WW8_BRCVer6 const *pVer6 = reinterpret_cast<WW8_BRCVer6 const *>(pParams);
1275 0 : for (int i = 0; i < 6; ++i)
1276 0 : aDefBrcs[i] = WW8_BRC(pVer6[i]);
1277 : }
1278 180 : else if ( nBrcVer == 8 )
1279 : {
1280 : static_assert(sizeof (WW8_BRC) == 4, "this has to match the msword size");
1281 21 : for( int i = 0; i < 6; ++i )
1282 18 : aDefBrcs[i] = reinterpret_cast<WW8_BRC const *>(pParams)[i];
1283 : }
1284 : else
1285 177 : memcpy( aDefBrcs, pParams, sizeof( aDefBrcs ) );
1286 180 : }
1287 :
1288 416 : void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol)
1289 : {
1290 : // sprmTDxaCol (opcode 0x7623) changes the width of cells
1291 : // whose index is within a certain range to be a certain value.
1292 :
1293 416 : if( nWwCols && pParamsTDxaCol ) // set one or more cell length(s)
1294 : {
1295 3 : sal_uInt8 nitcFirst= pParamsTDxaCol[0]; // first col to be changed
1296 3 : sal_uInt8 nitcLim = pParamsTDxaCol[1]; // (last col to be changed)+1
1297 3 : short nDxaCol = (sal_Int16)SVBT16ToShort( pParamsTDxaCol + 2 );
1298 :
1299 8 : for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ )
1300 : {
1301 5 : const short nOrgWidth = nCenter[i+1] - nCenter[i];
1302 5 : const short nDelta = nDxaCol - nOrgWidth;
1303 25 : for( int j = i+1; j <= nWwCols; j++ )
1304 : {
1305 20 : nCenter[j] = nCenter[j] + nDelta;
1306 : }
1307 : }
1308 : }
1309 416 : }
1310 :
1311 178 : void WW8TabBandDesc::ProcessSprmTInsert(const sal_uInt8* pParamsTInsert)
1312 : {
1313 178 : if( nWwCols && pParamsTInsert ) // set one or more cell length(s)
1314 : {
1315 2 : sal_uInt8 nitcInsert = pParamsTInsert[0]; // position at which to insert
1316 2 : if (nitcInsert >= MAX_COL) // cannot insert into cell outside max possible index
1317 178 : return;
1318 2 : sal_uInt8 nctc = pParamsTInsert[1]; // number of cells
1319 2 : sal_uInt16 ndxaCol = SVBT16ToShort( pParamsTInsert+2 );
1320 :
1321 : short nNewWwCols;
1322 2 : if (nitcInsert > nWwCols)
1323 : {
1324 0 : nNewWwCols = nitcInsert+nctc;
1325 : //if new count would be outside max possible count, clip it, and calc a new replacement
1326 : //legal nctc
1327 0 : if (nNewWwCols > MAX_COL)
1328 : {
1329 0 : nNewWwCols = MAX_COL;
1330 0 : nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nitcInsert);
1331 : }
1332 : }
1333 : else
1334 : {
1335 2 : nNewWwCols = nWwCols+nctc;
1336 : //if new count would be outside max possible count, clip it, and calc a new replacement
1337 : //legal nctc
1338 2 : if (nNewWwCols > MAX_COL)
1339 : {
1340 1 : nNewWwCols = MAX_COL;
1341 1 : nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nWwCols);
1342 : }
1343 : }
1344 :
1345 2 : WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols];
1346 2 : setcelldefaults(pTC2s, nNewWwCols);
1347 :
1348 2 : if (pTCs)
1349 : {
1350 2 : memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1351 2 : delete[] pTCs;
1352 : }
1353 2 : pTCs = pTC2s;
1354 :
1355 : //If we have to move some cells
1356 2 : if (nitcInsert <= nWwCols)
1357 : {
1358 : // adjust the left x-position of the dummy at the very end
1359 2 : nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1360 5 : for( int i = nWwCols-1; i >= nitcInsert; i--)
1361 : {
1362 : // adjust the left x-position
1363 3 : nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1364 :
1365 : // adjust the cell's borders
1366 3 : pTCs[i + nctc] = pTCs[i];
1367 : }
1368 : }
1369 :
1370 : //if itcMac is larger than full size, fill in missing ones first
1371 2 : for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1372 0 : nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1373 :
1374 : //now add in our new cells
1375 69 : for( int j = 0;j < nctc; j++)
1376 67 : nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1377 :
1378 2 : nWwCols = nNewWwCols;
1379 : }
1380 : }
1381 :
1382 0 : void WW8TabBandDesc::ProcessDirection(const sal_uInt8* pParams)
1383 : {
1384 0 : sal_uInt8 nStartCell = *pParams++;
1385 0 : sal_uInt8 nEndCell = *pParams++;
1386 0 : sal_uInt16 nCode = SVBT16ToShort(pParams);
1387 :
1388 : OSL_ENSURE(nStartCell < nEndCell, "not as I thought");
1389 : OSL_ENSURE(nEndCell < MAX_COL + 1, "not as I thought");
1390 0 : if (nStartCell > MAX_COL)
1391 0 : return;
1392 0 : if (nEndCell > MAX_COL + 1)
1393 0 : nEndCell = MAX_COL + 1;
1394 :
1395 0 : for (;nStartCell < nEndCell; ++nStartCell)
1396 0 : maDirections[nStartCell] = nCode;
1397 : }
1398 :
1399 806 : void WW8TabBandDesc::ProcessSpacing(const sal_uInt8* pParams)
1400 : {
1401 806 : sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1402 : OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1403 806 : if (nLen != 6)
1404 806 : return;
1405 806 : mbHasSpacing=true;
1406 : #if OSL_DEBUG_LEVEL > 0
1407 : sal_uInt8 nWhichCell = *pParams;
1408 : OSL_ENSURE(nWhichCell == 0, "Expected cell to be 0!");
1409 : #endif
1410 806 : ++pParams; //Skip which cell
1411 806 : ++pParams; //unknown byte
1412 :
1413 806 : sal_uInt8 nSideBits = *pParams++;
1414 : OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1415 806 : ++pParams; //unknown byte
1416 806 : sal_uInt16 nValue = SVBT16ToShort( pParams );
1417 4030 : for (int i = wwTOP; i <= wwRIGHT; i++)
1418 : {
1419 3224 : switch (nSideBits & (1 << i))
1420 : {
1421 : case 1 << wwTOP:
1422 287 : mnDefaultTop = nValue;
1423 287 : break;
1424 : case 1 << wwLEFT:
1425 311 : mnDefaultLeft = nValue;
1426 311 : break;
1427 : case 1 << wwBOTTOM:
1428 289 : mnDefaultBottom = nValue;
1429 289 : break;
1430 : case 1 << wwRIGHT:
1431 311 : mnDefaultRight = nValue;
1432 311 : break;
1433 : case 0:
1434 2026 : break;
1435 : default:
1436 : OSL_ENSURE(false, "Impossible");
1437 0 : break;
1438 : }
1439 : }
1440 : }
1441 :
1442 0 : void WW8TabBandDesc::ProcessSpecificSpacing(const sal_uInt8* pParams)
1443 : {
1444 0 : sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1445 : OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1446 0 : if (nLen != 6)
1447 0 : return;
1448 0 : sal_uInt8 nWhichCell = *pParams++;
1449 : OSL_ENSURE(nWhichCell < MAX_COL + 1, "Cell out of range in spacings");
1450 0 : if (nWhichCell >= MAX_COL + 1)
1451 0 : return;
1452 :
1453 0 : ++pParams; //unknown byte
1454 0 : sal_uInt8 nSideBits = *pParams++;
1455 : OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1456 0 : nOverrideSpacing[nWhichCell] |= nSideBits;
1457 :
1458 : OSL_ENSURE(nOverrideSpacing[nWhichCell] < 0x10,
1459 : "Unexpected value for nSideBits");
1460 : #if OSL_DEBUG_LEVEL > 0
1461 : sal_uInt8 nUnknown2 = *pParams;
1462 : OSL_ENSURE(nUnknown2 == 0x3, "Unexpected value for spacing2");
1463 : #endif
1464 0 : ++pParams;
1465 0 : sal_uInt16 nValue = SVBT16ToShort( pParams );
1466 :
1467 0 : for (int i=0; i < 4; i++)
1468 : {
1469 0 : if (nSideBits & (1 << i))
1470 0 : nOverrideValues[nWhichCell][i] = nValue;
1471 : }
1472 : }
1473 :
1474 1 : void WW8TabBandDesc::ProcessSprmTDelete(const sal_uInt8* pParamsTDelete)
1475 : {
1476 1 : if( nWwCols && pParamsTDelete ) // set one or more cell length(s)
1477 : {
1478 1 : sal_uInt8 nitcFirst= pParamsTDelete[0]; // first col to be deleted
1479 1 : if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1480 0 : return;
1481 1 : sal_uInt8 nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1
1482 1 : if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1483 0 : return;
1484 :
1485 : /*
1486 : * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1487 : * greater than or equal to itcLim to be moved
1488 : */
1489 1 : int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted
1490 :
1491 1 : if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1492 : {
1493 0 : WW8_TCell* pAktTC = pTCs + nitcFirst;
1494 0 : int i = 0;
1495 0 : while( i < nShlCnt )
1496 : {
1497 : // adjust the left x-position
1498 0 : nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1499 :
1500 : // adjust the cell's borders
1501 0 : *pAktTC = pTCs[ nitcLim + i];
1502 :
1503 0 : ++i;
1504 0 : ++pAktTC;
1505 : }
1506 : // adjust the left x-position of the dummy at the very end
1507 0 : nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1508 : }
1509 :
1510 1 : short nCellsDeleted = nitcLim - nitcFirst;
1511 : //clip delete request to available number of cells
1512 1 : if (nCellsDeleted > nWwCols)
1513 1 : nCellsDeleted = nWwCols;
1514 1 : nWwCols -= nCellsDeleted;
1515 : }
1516 : }
1517 :
1518 : // ReadShd reads the background color of a cell
1519 : // ReadDef must be called before
1520 242 : void WW8TabBandDesc::ReadShd(const sal_uInt8* pS )
1521 : {
1522 242 : sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1523 242 : if( !nLen )
1524 242 : return;
1525 :
1526 242 : if( !pSHDs )
1527 : {
1528 242 : pSHDs = new WW8_SHD[nWwCols];
1529 242 : memset( pSHDs, 0, nWwCols * sizeof( WW8_SHD ) );
1530 : }
1531 :
1532 242 : short nAnz = nLen >> 1;
1533 242 : if (nAnz > nWwCols)
1534 0 : nAnz = nWwCols;
1535 :
1536 : SVBT16 const * pShd;
1537 : int i;
1538 816 : for(i=0, pShd = reinterpret_cast<SVBT16 const *>(pS); i<nAnz; i++, pShd++ )
1539 574 : pSHDs[i].SetWWValue( *pShd );
1540 : }
1541 :
1542 242 : void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67)
1543 : {
1544 242 : sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1545 242 : if (!nLen)
1546 242 : return;
1547 :
1548 242 : if (!pNewSHDs)
1549 242 : pNewSHDs = new sal_uInt32[nWwCols];
1550 :
1551 242 : short nAnz = nLen / 10; //10 bytes each
1552 242 : if (nAnz > nWwCols)
1553 0 : nAnz = nWwCols;
1554 :
1555 242 : int i=0;
1556 1058 : while (i < nAnz)
1557 574 : pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1558 :
1559 630 : while (i < nWwCols)
1560 146 : pNewSHDs[i++] = COL_AUTO;
1561 : }
1562 :
1563 2148 : void WW8TabBandDesc::setcelldefaults(WW8_TCell *pCells, short nCols)
1564 : {
1565 2148 : memset( pCells, 0, nCols * sizeof( WW8_TCell ) );
1566 2148 : }
1567 :
1568 297 : const sal_uInt8 *HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1569 : {
1570 : const sal_uInt8 *pParams;
1571 297 : if (bVer67)
1572 0 : pParams = pPap->HasSprm(24);
1573 : else
1574 : {
1575 297 : if (0 == (pParams = pPap->HasSprm(0x244B)))
1576 282 : pParams = pPap->HasSprm(0x2416);
1577 : }
1578 297 : return pParams;
1579 : }
1580 :
1581 : enum wwTableSprm
1582 : {
1583 : sprmNil,
1584 :
1585 : sprmTTableWidth, sprmTTextFlow, sprmTFCantSplit, sprmTJc, sprmTFBiDi,
1586 : sprmTDefTable, sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft,
1587 : sprmTSetBrc, sprmTSetBrc90, sprmTDxaCol, sprmTInsert, sprmTDelete,
1588 : sprmTTableHeader, sprmTDxaGapHalf, sprmTTableBorders, sprmTTableBorders90,
1589 : sprmTDefTableNewShd, sprmTCellPadding, sprmTCellPaddingDefault
1590 : };
1591 :
1592 10512 : wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1593 : {
1594 10512 : switch (eVer)
1595 : {
1596 : case ww::eWW8:
1597 10512 : switch (nId)
1598 : {
1599 : case NS_sprm::LN_TTableWidth:
1600 355 : return sprmTTableWidth;
1601 : case NS_sprm::LN_TTextFlow:
1602 0 : return sprmTTextFlow;
1603 : case NS_sprm::LN_TTableHeader:
1604 2 : return sprmTTableHeader;
1605 : case NS_sprm::LN_TFCantSplit:
1606 110 : return sprmTFCantSplit;
1607 : case NS_sprm::LN_TJc90:
1608 134 : return sprmTJc;
1609 : case NS_sprm::LN_TFBiDi:
1610 250 : return sprmTFBiDi;
1611 : case NS_sprm::LN_TDelete:
1612 1 : return sprmTDelete;
1613 : case NS_sprm::LN_TInsert:
1614 178 : return sprmTInsert;
1615 : case NS_sprm::LN_TDxaCol:
1616 416 : return sprmTDxaCol;
1617 : case NS_sprm::LN_TDyaRowHeight:
1618 189 : return sprmTDyaRowHeight;
1619 : case NS_sprm::LN_TDxaLeft:
1620 177 : return sprmTDxaLeft;
1621 : case NS_sprm::LN_TDxaGapHalf:
1622 366 : return sprmTDxaGapHalf;
1623 : case NS_sprm::LN_TTableBorders80:
1624 182 : return sprmTTableBorders;
1625 : case NS_sprm::LN_TDefTable:
1626 295 : return sprmTDefTable;
1627 : case NS_sprm::LN_TDefTableShd80:
1628 370 : return sprmTDefTableShd;
1629 : case NS_sprm::LN_TDefTableShd:
1630 370 : return sprmTDefTableNewShd;
1631 : case NS_sprm::LN_TTableBorders:
1632 326 : return sprmTTableBorders90;
1633 : case NS_sprm::LN_TSetBrc80:
1634 1 : return sprmTSetBrc;
1635 : case NS_sprm::LN_TSetBrc:
1636 297 : return sprmTSetBrc90;
1637 : case NS_sprm::LN_TCellPadding:
1638 0 : return sprmTCellPadding;
1639 : case NS_sprm::LN_TCellPaddingDefault:
1640 806 : return sprmTCellPaddingDefault;
1641 : }
1642 5687 : break;
1643 : case ww::eWW7:
1644 : case ww::eWW6:
1645 0 : switch (nId)
1646 : {
1647 : case 182:
1648 0 : return sprmTJc;
1649 : case 183:
1650 0 : return sprmTDxaLeft;
1651 : case 184:
1652 0 : return sprmTDxaGapHalf;
1653 : case 186:
1654 0 : return sprmTTableHeader;
1655 : case 187:
1656 0 : return sprmTTableBorders;
1657 : case 189:
1658 0 : return sprmTDyaRowHeight;
1659 : case 190:
1660 0 : return sprmTDefTable;
1661 : case 191:
1662 0 : return sprmTDefTableShd;
1663 : case 193:
1664 0 : return sprmTSetBrc;
1665 : case 194:
1666 0 : return sprmTInsert;
1667 : case 195:
1668 0 : return sprmTDelete;
1669 : case 196:
1670 0 : return sprmTDxaCol;
1671 : }
1672 0 : break;
1673 : case ww::eWW1:
1674 : case ww::eWW2:
1675 0 : switch (nId)
1676 : {
1677 : case 146:
1678 0 : return sprmTJc;
1679 : case 147:
1680 0 : return sprmTDxaLeft;
1681 : case 148:
1682 0 : return sprmTDxaGapHalf;
1683 : case 153:
1684 0 : return sprmTDyaRowHeight;
1685 : case 154:
1686 0 : return sprmTDefTable;
1687 : case 155:
1688 0 : return sprmTDefTableShd;
1689 : case 157:
1690 0 : return sprmTSetBrc;
1691 : case 158:
1692 0 : return sprmTInsert;
1693 : case 159:
1694 0 : return sprmTDelete;
1695 : case 160:
1696 0 : return sprmTDxaCol;
1697 : }
1698 0 : break;
1699 : }
1700 5687 : return sprmNil;
1701 : }
1702 :
1703 74 : WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
1704 : mpOldRedlineStack(0),
1705 : pIo(pIoClass),
1706 : pFirstBand(0),
1707 : pActBand(0),
1708 : pTmpPos(0),
1709 : pTableNd(0),
1710 : pTabLines(0),
1711 : pTabLine(0),
1712 : pTabBoxes(0),
1713 : pTabBox(0),
1714 : pAktWWCell(0),
1715 : nRows(0),
1716 : nDefaultSwCols(0),
1717 : nBands(0),
1718 : nMinLeft(0),
1719 : nConvertedLeft(0),
1720 : nMaxRight(0),
1721 : nSwWidth(0),
1722 : nPreferredWidth(0),
1723 : nOrgDxaLeft(0),
1724 : bOk(true),
1725 : bClaimLineFormat(false),
1726 : eOri(text::HoriOrientation::NONE),
1727 : bIsBiDi(false),
1728 : nAktRow(0),
1729 : nAktBandRow(0),
1730 : nAktCol(0),
1731 : nRowsToRepeat(0),
1732 : pTable(0),
1733 : pParentPos(0),
1734 : pFlyFormat(0),
1735 74 : aItemSet(pIo->m_rDoc.GetAttrPool(),RES_FRMATR_BEGIN,RES_FRMATR_END-1)
1736 : {
1737 74 : pIo->m_bAktAND_fNumberAcross = false;
1738 :
1739 : static const sal_Int16 aOriArr[] =
1740 : {
1741 : text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1742 : };
1743 :
1744 74 : bool bOldVer = ww::IsSevenMinus(pIo->GetFib().GetFIBVersion());
1745 : WW8_TablePos aTabPos;
1746 :
1747 : WW8PLCFxSave1 aSave;
1748 74 : pIo->m_pPlcxMan->GetPap()->Save( aSave );
1749 :
1750 74 : WW8PLCFx_Cp_FKP* pPap = pIo->m_pPlcxMan->GetPapPLCF();
1751 :
1752 74 : eOri = text::HoriOrientation::LEFT;
1753 :
1754 74 : WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1755 :
1756 74 : wwSprmParser aSprmParser(pIo->GetFib().GetFIBVersion());
1757 :
1758 : // process pPap until end of table found
1759 : do
1760 : {
1761 297 : short nTabeDxaNew = SHRT_MAX;
1762 297 : bool bTabRowJustRead = false;
1763 297 : const sal_uInt8* pShadeSprm = 0;
1764 297 : const sal_uInt8* pNewShadeSprm = 0;
1765 297 : const sal_uInt8* pTableBorders = 0;
1766 297 : const sal_uInt8* pTableBorders90 = 0;
1767 520 : std::vector<const sal_uInt8*> aTSetBrcs, aTSetBrc90s;
1768 297 : WW8_TablePos *pTabPos = 0;
1769 :
1770 : // search end of a tab row
1771 297 : if(!(pIo->SearchRowEnd(pPap, nStartCp, pIo->m_nInTable)))
1772 : {
1773 0 : bOk = false;
1774 0 : break;
1775 : }
1776 :
1777 : // Get the SPRM chains:
1778 : // first from PAP and then from PCD (of the Piece Table)
1779 297 : WW8PLCFxDesc aDesc;
1780 297 : pPap->GetSprms( &aDesc );
1781 297 : WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1782 :
1783 891 : for (int nLoop = 0; nLoop < 2; ++nLoop)
1784 : {
1785 594 : bool bRepeatedSprm = false;
1786 : const sal_uInt8* pParams;
1787 11700 : while (aSprmIter.GetSprms() && 0 != (pParams = aSprmIter.GetAktParams()))
1788 : {
1789 10512 : sal_uInt16 nId = aSprmIter.GetAktId();
1790 10512 : wwTableSprm eSprm = GetTableSprm(nId, pIo->GetFib().GetFIBVersion());
1791 10512 : switch (eSprm)
1792 : {
1793 : case sprmTTableWidth:
1794 : {
1795 355 : const sal_uInt8 b0 = pParams[0];
1796 355 : const sal_uInt8 b1 = pParams[1];
1797 355 : const sal_uInt8 b2 = pParams[2];
1798 355 : if (b0 == 3) // Twips
1799 93 : nPreferredWidth = b2 * 0x100 + b1;
1800 : }
1801 355 : break;
1802 : case sprmTTextFlow:
1803 0 : pNewBand->ProcessDirection(pParams);
1804 0 : break;
1805 : case sprmTFCantSplit:
1806 110 : pNewBand->bCantSplit = *pParams;
1807 110 : bClaimLineFormat = true;
1808 110 : break;
1809 : case sprmTTableBorders:
1810 182 : pTableBorders = pParams; // process at end
1811 182 : break;
1812 : case sprmTTableBorders90:
1813 326 : pTableBorders90 = pParams; // process at end
1814 326 : break;
1815 : case sprmTTableHeader:
1816 2 : if (!bRepeatedSprm)
1817 : {
1818 1 : nRowsToRepeat++;
1819 1 : bRepeatedSprm = true;
1820 : }
1821 2 : break;
1822 : case sprmTJc:
1823 : // sprmTJc - Justification Code
1824 134 : if (nRows == 0)
1825 11 : eOri = aOriArr[*pParams & 0x3];
1826 134 : break;
1827 : case sprmTFBiDi:
1828 250 : bIsBiDi = SVBT16ToShort(pParams) != 0;
1829 250 : break;
1830 : case sprmTDxaGapHalf:
1831 366 : pNewBand->nGapHalf = (sal_Int16)SVBT16ToShort( pParams );
1832 366 : break;
1833 : case sprmTDyaRowHeight:
1834 189 : pNewBand->nLineHeight = (sal_Int16)SVBT16ToShort( pParams );
1835 189 : bClaimLineFormat = true;
1836 189 : break;
1837 : case sprmTDefTable:
1838 295 : pNewBand->ReadDef(bOldVer, pParams);
1839 295 : bTabRowJustRead = true;
1840 295 : break;
1841 : case sprmTDefTableShd:
1842 370 : pShadeSprm = pParams;
1843 370 : break;
1844 : case sprmTDefTableNewShd:
1845 370 : pNewShadeSprm = pParams;
1846 370 : break;
1847 : case sprmTDxaLeft:
1848 : // our Writer cannot shift single table lines
1849 : // horizontally so we have to find the smallest
1850 : // parameter (meaning the left-most position) and then
1851 : // shift the whole table to that margin (see below)
1852 : {
1853 177 : short nDxaNew = (sal_Int16)SVBT16ToShort( pParams );
1854 177 : nOrgDxaLeft = nDxaNew;
1855 177 : if( nDxaNew < nTabeDxaNew )
1856 177 : nTabeDxaNew = nDxaNew;
1857 : }
1858 177 : break;
1859 : case sprmTSetBrc:
1860 1 : aTSetBrcs.push_back(pParams); // process at end
1861 1 : break;
1862 : case sprmTSetBrc90:
1863 297 : aTSetBrc90s.push_back(pParams); // process at end
1864 297 : break;
1865 : case sprmTDxaCol:
1866 416 : pNewBand->ProcessSprmTDxaCol(pParams);
1867 416 : break;
1868 : case sprmTInsert:
1869 178 : pNewBand->ProcessSprmTInsert(pParams);
1870 178 : break;
1871 : case sprmTDelete:
1872 1 : pNewBand->ProcessSprmTDelete(pParams);
1873 1 : break;
1874 : case sprmTCellPaddingDefault:
1875 806 : pNewBand->ProcessSpacing(pParams);
1876 806 : break;
1877 : case sprmTCellPadding:
1878 0 : pNewBand->ProcessSpecificSpacing(pParams);
1879 0 : break;
1880 : default:
1881 : ;
1882 : }
1883 10512 : aSprmIter.advance();
1884 : }
1885 :
1886 594 : if( !nLoop )
1887 : {
1888 297 : pPap->GetPCDSprms( aDesc );
1889 297 : aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1890 : }
1891 : }
1892 :
1893 : // WW-Tables can contain Fly-changes. For this abort tables here
1894 : // and start again. *pPap is still before TabRowEnd, so TestApo()
1895 : // can be called with the last parameter set to false and therefore
1896 : // take effect.
1897 :
1898 297 : if (bTabRowJustRead)
1899 : {
1900 : // Some SPRMs need to be processed *after* ReadDef is called
1901 : // so they were saved up until here
1902 295 : if (pShadeSprm)
1903 242 : pNewBand->ReadShd(pShadeSprm);
1904 295 : if (pNewShadeSprm)
1905 242 : pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
1906 295 : if (pTableBorders90)
1907 177 : pNewBand->ProcessSprmTTableBorders(9, pTableBorders90);
1908 118 : else if (pTableBorders)
1909 : pNewBand->ProcessSprmTTableBorders(bOldVer ? 6 : 8,
1910 3 : pTableBorders);
1911 295 : std::vector<const sal_uInt8*>::const_iterator iter;
1912 296 : for (iter = aTSetBrcs.begin(); iter != aTSetBrcs.end(); ++iter)
1913 1 : pNewBand->ProcessSprmTSetBRC(bOldVer ? 6 : 8, *iter);
1914 592 : for (iter = aTSetBrc90s.begin(); iter != aTSetBrc90s.end(); ++iter)
1915 297 : pNewBand->ProcessSprmTSetBRC(9, *iter);
1916 : }
1917 :
1918 297 : if( nTabeDxaNew < SHRT_MAX )
1919 : {
1920 177 : short* pCenter = pNewBand->nCenter;
1921 177 : short firstDxaCenter = *pCenter;
1922 761 : for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
1923 : {
1924 : // #i30298# Use sprmTDxaLeft to adjust the left indent
1925 : // #i40461# Use dxaGapHalf during calculation
1926 : *pCenter +=
1927 584 : (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
1928 : }
1929 : }
1930 :
1931 297 : if (!pActBand)
1932 74 : pActBand = pFirstBand = pNewBand;
1933 : else
1934 : {
1935 223 : pActBand->pNextBand = pNewBand;
1936 223 : pActBand = pNewBand;
1937 : }
1938 297 : nBands++;
1939 :
1940 297 : pNewBand = new WW8TabBandDesc;
1941 :
1942 297 : nRows++;
1943 297 : pActBand->nRows++;
1944 :
1945 : //Seek our pap to its next block of properties
1946 297 : WW8PLCFxDesc aRes;
1947 297 : aRes.pMemPos = 0;
1948 297 : aRes.nStartPos = nStartCp;
1949 :
1950 297 : if (!(pPap->SeekPos(aRes.nStartPos)))
1951 : {
1952 0 : aRes.nEndPos = WW8_CP_MAX;
1953 0 : pPap->SetDirty(true);
1954 : }
1955 297 : pPap->GetSprms(&aRes);
1956 297 : pPap->SetDirty(false);
1957 :
1958 : //Are we at the end of available properties
1959 297 : if (
1960 594 : !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
1961 297 : aRes.nStartPos == WW8_CP_MAX
1962 : )
1963 : {
1964 0 : bOk = false;
1965 0 : break;
1966 : }
1967 :
1968 : //Are we still in a table cell
1969 297 : const sal_uInt8* pParams = HasTabCellSprm(pPap, bOldVer);
1970 297 : const sal_uInt8 *pLevel = pPap->HasSprm(0x6649);
1971 : // InTable
1972 297 : if (!pParams || (1 != *pParams) ||
1973 233 : (pLevel && (*pLevel <= pIo->m_nInTable)))
1974 : {
1975 : break;
1976 : }
1977 :
1978 : //Get the end of row new table positioning data
1979 224 : WW8_CP nMyStartCp=nStartCp;
1980 224 : if (pIo->SearchRowEnd(pPap, nMyStartCp, pIo->m_nInTable))
1981 224 : if (pIo->ParseTabPos(&aTabPos, pPap))
1982 7 : pTabPos = &aTabPos;
1983 :
1984 : //Move back to this cell
1985 224 : aRes.pMemPos = 0;
1986 224 : aRes.nStartPos = nStartCp;
1987 :
1988 : // PlcxMan currently points too far ahead so we need to bring
1989 : // it back to where we are trying to make a table
1990 224 : pIo->m_pPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
1991 224 : if (!(pPap->SeekPos(aRes.nStartPos)))
1992 : {
1993 0 : aRes.nEndPos = WW8_CP_MAX;
1994 0 : pPap->SetDirty(true);
1995 : }
1996 224 : pPap->GetSprms(&aRes);
1997 224 : pPap->SetDirty(false);
1998 :
1999 : //Does this row match up with the last row closely enough to be
2000 : //considered part of the same table
2001 224 : ApoTestResults aApo = pIo->TestApo(pIo->m_nInTable + 1, false, pTabPos);
2002 :
2003 : /*
2004 : ##513##, #79474# If this is not sufficient, then we should look at
2005 : sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2006 : part of this table, but instead is an absolutely positioned table
2007 : outside of this one
2008 : */
2009 224 : if (aApo.mbStopApo)
2010 1 : break;
2011 223 : if (aApo.mbStartApo)
2012 : {
2013 : //if there really is a fly here, and not a "null" fly then break.
2014 0 : WW8FlyPara *pNewFly = pIo->ConstructApo(aApo, pTabPos);
2015 0 : if (pNewFly)
2016 0 : delete pNewFly;
2017 : else
2018 0 : break;
2019 : }
2020 :
2021 446 : nStartCp = aRes.nEndPos;
2022 : }
2023 : while(true);
2024 :
2025 74 : if( bOk )
2026 : {
2027 74 : if( pActBand->nRows > 1 )
2028 : {
2029 : // last band has more than 1 cell
2030 0 : delete pNewBand;
2031 0 : pNewBand = new WW8TabBandDesc( *pActBand ); // create new
2032 0 : pActBand->nRows--; // wegen Sonderbehandlung Raender-Defaults
2033 0 : pNewBand->nRows = 1;
2034 0 : pActBand->pNextBand = pNewBand; // am Ende einschleifen
2035 0 : nBands++;
2036 0 : pNewBand = 0; // do not delete
2037 : }
2038 74 : CalcDefaults();
2039 : }
2040 74 : delete pNewBand;
2041 :
2042 297 : pIo->m_pPlcxMan->GetPap()->Restore( aSave );
2043 74 : }
2044 :
2045 148 : WW8TabDesc::~WW8TabDesc()
2046 : {
2047 74 : WW8TabBandDesc* pR = pFirstBand;
2048 445 : while(pR)
2049 : {
2050 297 : WW8TabBandDesc* pR2 = pR->pNextBand;
2051 297 : delete pR;
2052 297 : pR = pR2;
2053 : }
2054 :
2055 74 : delete pParentPos;
2056 74 : }
2057 :
2058 74 : void WW8TabDesc::CalcDefaults()
2059 : {
2060 74 : short nMinCols = SHRT_MAX;
2061 : WW8TabBandDesc* pR;
2062 :
2063 74 : nMinLeft = SHRT_MAX;
2064 74 : nMaxRight = SHRT_MIN;
2065 :
2066 : /*
2067 : If we are an honestly inline centered table, then the normal rules of
2068 : engagement for left and right margins do not apply. The multiple rows are
2069 : centered regardless of the actual placement of rows, so we cannot have
2070 : mismatched rows as is possible in other configurations.
2071 :
2072 : e.g. change the example bugdoc in word from text wrapping of none (inline)
2073 : to around (in frame (bApo)) and the table splits into two very disjoint
2074 : rows as the beginning point of each row are very different
2075 : */
2076 74 : if ((!pIo->InLocalApo()) && (eOri == text::HoriOrientation::CENTER))
2077 : {
2078 4 : for (pR = pFirstBand; pR; pR = pR->pNextBand)
2079 15 : for( short i = pR->nWwCols; i >= 0; --i)
2080 12 : pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0];
2081 : }
2082 :
2083 : // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2084 371 : for( pR = pFirstBand; pR; pR = pR->pNextBand )
2085 : {
2086 297 : if( pR->nCenter[0] < nMinLeft )
2087 74 : nMinLeft = pR->nCenter[0];
2088 :
2089 1407 : for( short i = 0; i < pR->nWwCols; i++ )
2090 : {
2091 : /*
2092 : If the margins are so large as to make the displayable
2093 : area inside them smaller than the minimum allowed then adjust the
2094 : width to fit. But only do it if the two cells are not the exact
2095 : same value, if they are then the cell does not really exist and will
2096 : be blended together into the same cell through the use of the
2097 : nTrans(late) array.
2098 : #i28333# If the nGapHalf is greater than the cell width best to ignore it
2099 : */
2100 1110 : int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2101 1110 : if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2102 : {
2103 33 : pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2;
2104 : }
2105 : }
2106 :
2107 297 : if( pR->nCenter[pR->nWwCols] > nMaxRight )
2108 82 : nMaxRight = pR->nCenter[pR->nWwCols];
2109 : }
2110 74 : nSwWidth = nMaxRight - nMinLeft;
2111 :
2112 : // If the table is right aligned we need to align all rows to the
2113 : // row that has the furthest right point
2114 :
2115 74 : if(eOri == text::HoriOrientation::RIGHT)
2116 : {
2117 141 : for( pR = pFirstBand; pR; pR = pR->pNextBand )
2118 : {
2119 131 : int adjust = nMaxRight - pR->nCenter[pR->nWwCols];
2120 591 : for( short i = 0; i < pR->nWwCols + 1; i++ )
2121 : {
2122 460 : pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2123 : }
2124 :
2125 : }
2126 : }
2127 :
2128 : // 2. pass: Detect number of writer columns. This can exceed the count
2129 : // of columns in WW by 2, because SW in constrast to WW does not provide
2130 : // fringed left and right borders and has to fill with empty boxes.
2131 : // Non exisitent cells can reduce the number of columns.
2132 :
2133 : // 3. pass: Replace border with defaults if needed
2134 74 : nConvertedLeft = nMinLeft;
2135 :
2136 74 : short nLeftMaxThickness = 0, nRightMaxThickness=0;
2137 371 : for( pR = pFirstBand ; pR; pR = pR->pNextBand )
2138 : {
2139 297 : if( !pR->pTCs )
2140 : {
2141 2 : pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2142 2 : memset( pR->pTCs, 0, pR->nWwCols * sizeof( WW8_TCell ) );
2143 : }
2144 1407 : for (int k = 0; k < pR->nWwCols; ++k)
2145 : {
2146 1110 : WW8_TCell* pT = &pR->pTCs[k];
2147 : int i, j;
2148 5550 : for( i = 0; i < 4; i ++ )
2149 : {
2150 4440 : if (pT->rgbrc[i].brcType()==0)
2151 : {
2152 : // if shadow is set, its invalid
2153 3405 : j = i;
2154 3405 : switch( i )
2155 : {
2156 : case 0:
2157 : // outer top / horizontally inside
2158 836 : j = (pR == pFirstBand) ? 0 : 4;
2159 836 : break;
2160 : case 1:
2161 : // outer left / vertically inside
2162 834 : j = k ? 5 : 1;
2163 834 : break;
2164 : case 2:
2165 : // outer bottom / horizontally inside
2166 783 : j = pR->pNextBand ? 4 : 2;
2167 783 : break;
2168 : case 3:
2169 : // outer right / vertically inside
2170 952 : j = (k == pR->nWwCols - 1) ? 3 : 5;
2171 952 : break;
2172 : }
2173 : // mangel mit Defaults ueber
2174 3405 : pT->rgbrc[i] = pR->aDefBrcs[j];
2175 : }
2176 : }
2177 : }
2178 297 : if (pR->nWwCols)
2179 : {
2180 : /*
2181 : Similar to graphics and other elements word does not totally
2182 : factor the width of the border into its calculations of size, we
2183 : do so we must adjust out widths and other dimensions to fit. It
2184 : appears that what occurs is that the last cell's right margin if
2185 : the margin width that is not calculated into winwords table
2186 : dimensions, so in that case increase the table to include the
2187 : extra width of the right margin.
2188 : */
2189 294 : if ( ! pR->pTCs[pR->nWwCols-1].rgbrc[3].fShadow() )
2190 : {
2191 293 : short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
2192 293 : DetermineBorderProperties();
2193 293 : pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
2194 293 : if (nThickness > nRightMaxThickness)
2195 59 : nRightMaxThickness = nThickness;
2196 : }
2197 :
2198 : /*
2199 : The left space of the table is in nMinLeft, but again this
2200 : does not consider the margin thickness to its left in the
2201 : placement value, so get the thickness of the left border,
2202 : half is placed to the left of the nominal left side, and
2203 : half to the right.
2204 : */
2205 294 : if ( ! pR->pTCs[0].rgbrc[1].fShadow() )
2206 : {
2207 293 : short nThickness = pR->pTCs[0].rgbrc[1].
2208 293 : DetermineBorderProperties();
2209 293 : if (nThickness > nLeftMaxThickness)
2210 60 : nLeftMaxThickness = nThickness;
2211 : }
2212 : }
2213 : }
2214 74 : nSwWidth = nSwWidth + nRightMaxThickness;
2215 74 : nMaxRight = nMaxRight + nRightMaxThickness;
2216 74 : nConvertedLeft = nMinLeft-(nLeftMaxThickness/2);
2217 :
2218 371 : for( pR = pFirstBand; pR; pR = pR->pNextBand )
2219 : {
2220 297 : pR->nSwCols = pR->nWwCols;
2221 297 : pR->bLEmptyCol = pR->nCenter[0] - nMinLeft >= MINLAY;
2222 297 : pR->bREmptyCol = (nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY;
2223 :
2224 297 : short nAddCols = short(pR->bLEmptyCol) + short(pR->bREmptyCol);
2225 : sal_uInt16 i;
2226 297 : sal_uInt16 j = ( pR->bLEmptyCol ) ? 1 : 0;
2227 1407 : for (i = 0; i < pR->nWwCols; ++i)
2228 : {
2229 1110 : pR->nTransCell[i] = (sal_Int8)j;
2230 1110 : if ( pR->nCenter[i] < pR->nCenter[i+1] )
2231 : {
2232 981 : pR->bExist[i] = true;
2233 981 : j++;
2234 : }
2235 : else
2236 : {
2237 129 : pR->bExist[i] = false;
2238 129 : nAddCols--;
2239 : }
2240 : }
2241 :
2242 : OSL_ENSURE(i,"no columns in row ?");
2243 :
2244 : /*
2245 : If the last cell was "false" then there is no valid cell following it,
2246 : so the default mapping forward wont't work. So map it (and
2247 : contiguous invalid cells backwards to the last valid cell instead.
2248 : */
2249 297 : if (i && !pR->bExist[i-1])
2250 : {
2251 2 : sal_uInt16 k=i-1;
2252 6 : while (k && !pR->bExist[k])
2253 2 : k--;
2254 4 : for (sal_uInt16 n=k+1;n<i;n++)
2255 2 : pR->nTransCell[n] = pR->nTransCell[k];
2256 : }
2257 :
2258 297 : pR->nTransCell[i++] = (sal_Int8)(j++); // Can exceed by 2 among other
2259 297 : pR->nTransCell[i] = (sal_Int8)j; // things because of bREmptyCol
2260 :
2261 297 : pR->nSwCols = pR->nSwCols + nAddCols;
2262 297 : if( pR->nSwCols < nMinCols )
2263 81 : nMinCols = pR->nSwCols;
2264 : }
2265 :
2266 : /*
2267 : #i9718#
2268 : Find the largest of the borders on cells that adjoin top bottom and remove
2269 : the val from the top and put in on the bottom cell. I can't seem to make
2270 : disjoint upper and lowers to see what happens there.
2271 : */
2272 :
2273 107 : if ((nMinLeft && !bIsBiDi && text::HoriOrientation::LEFT == eOri) ||
2274 62 : (nMinLeft != -108 && bIsBiDi && text::HoriOrientation::RIGHT == eOri)) // Word sets the first nCenter value to -108 when no indent is used
2275 46 : eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2276 :
2277 74 : nDefaultSwCols = nMinCols; // because inserting cells is cheaper than merging
2278 74 : if( nDefaultSwCols == 0 )
2279 0 : bOk = false;
2280 74 : pActBand = pFirstBand;
2281 74 : nAktBandRow = 0;
2282 : OSL_ENSURE( pActBand, "pActBand ist 0" );
2283 74 : }
2284 :
2285 74 : void WW8TabDesc::SetSizePosition(SwFrameFormat* pFrameFormat)
2286 : {
2287 74 : SwFrameFormat* pApply = pFrameFormat;
2288 74 : if (!pApply )
2289 74 : pApply = pTable->GetFrameFormat();
2290 : OSL_ENSURE(pApply,"No frame");
2291 74 : pApply->SetFormatAttr(aItemSet);
2292 74 : if (pFrameFormat)
2293 : {
2294 0 : SwFormatFrmSize aSize = pFrameFormat->GetFrmSize();
2295 0 : aSize.SetHeightSizeType(ATT_MIN_SIZE);
2296 0 : aSize.SetHeight(MINLAY);
2297 0 : pFrameFormat->SetFormatAttr(aSize);
2298 0 : pTable->GetFrameFormat()->SetFormatAttr(SwFormatHoriOrient(0,text::HoriOrientation::FULL));
2299 : }
2300 74 : }
2301 :
2302 74 : void wwSectionManager::PrependedInlineNode(const SwPosition &rPos,
2303 : const SwNode &rNode)
2304 : {
2305 : OSL_ENSURE(!maSegments.empty(),
2306 : "should not be possible, must be at least one segment");
2307 74 : if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2308 15 : maSegments.back().maStart = SwNodeIndex(rNode);
2309 74 : }
2310 :
2311 74 : void WW8TabDesc::CreateSwTable(SvxULSpaceItem* pULSpaceItem)
2312 : {
2313 74 : ::SetProgressState(pIo->m_nProgress, pIo->m_pDocShell); // Update
2314 :
2315 : // if there is already some content on the Node append new node to ensure
2316 : // that this content remains ABOVE the table
2317 74 : SwPosition* pPoint = pIo->m_pPaM->GetPoint();
2318 74 : bool bInsNode = pPoint->nContent.GetIndex() != 0;
2319 74 : bool bSetMinHeight = false;
2320 :
2321 : /*
2322 : #i8062#
2323 : Set fly anchor to its anchor pos, so that if a table starts immediately
2324 : at this position a new node will be inserted before inserting the table.
2325 : */
2326 74 : if (!bInsNode && pIo->m_pFormatOfJustInsertedApo)
2327 : {
2328 : const SwPosition* pAPos =
2329 0 : pIo->m_pFormatOfJustInsertedApo->GetAnchor().GetContentAnchor();
2330 0 : if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2331 : {
2332 0 : bInsNode = true;
2333 0 : bSetMinHeight = true;
2334 :
2335 0 : SwFormatSurround aSur(pIo->m_pFormatOfJustInsertedApo->GetSurround());
2336 0 : aSur.SetAnchorOnly(true);
2337 0 : pIo->m_pFormatOfJustInsertedApo->SetFormatAttr(aSur);
2338 : }
2339 : }
2340 :
2341 74 : if (bSetMinHeight)
2342 : {
2343 : // minimize Fontsize to minimize height growth of the header/footer
2344 : // set font size to 1 point to minimize y-growth of Hd/Ft
2345 0 : SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2346 0 : pIo->NewAttr( aSz );
2347 0 : pIo->m_pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2348 : }
2349 :
2350 74 : if (bInsNode)
2351 0 : pIo->AppendTextNode(*pPoint);
2352 :
2353 74 : pTmpPos = new SwPosition( *pIo->m_pPaM->GetPoint() );
2354 :
2355 : // The table is small: The number of columns is the lowest count of
2356 : // columns of the origin, because inserting is faster than deleting.
2357 : // The number of rows is the count of bands because (identically)
2358 : // rows of a band can be duplicated easy.
2359 : pTable = pIo->m_rDoc.InsertTable(
2360 : SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
2361 74 : *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, false, true );
2362 :
2363 : OSL_ENSURE(pTable && pTable->GetFrameFormat(), "insert table failed");
2364 74 : if (!pTable || !pTable->GetFrameFormat())
2365 74 : return;
2366 :
2367 74 : if (pULSpaceItem && pULSpaceItem->GetUpper() != 0)
2368 4 : aItemSet.Put(*pULSpaceItem);
2369 :
2370 74 : SwTableNode* pTableNode = pTable->GetTableNode();
2371 : OSL_ENSURE(pTableNode, "no table node!");
2372 74 : if (pTableNode)
2373 : {
2374 74 : pIo->m_aSectionManager.PrependedInlineNode(*pIo->m_pPaM->GetPoint(),
2375 148 : *pTableNode);
2376 : }
2377 :
2378 : // Check if the node into which the table should be inserted already
2379 : // contains a Pagedesc. If so that Pagedesc would be moved to the
2380 : // row after the table, whats wrong. So delete and
2381 : // set later to the table format.
2382 74 : if (SwTextNode *const pNd = pTmpPos->nNode.GetNode().GetTextNode())
2383 : {
2384 74 : if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2385 : {
2386 8 : SfxPoolItem *pSetAttr = 0;
2387 : const SfxPoolItem* pItem;
2388 8 : if (SfxItemState::SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2389 : {
2390 0 : pSetAttr = new SvxFormatBreakItem( *static_cast<const SvxFormatBreakItem*>(pItem) );
2391 0 : pNd->ResetAttr( RES_BREAK );
2392 : }
2393 :
2394 : // eventually set the PageDesc/Break now to the table
2395 8 : if (pSetAttr)
2396 : {
2397 0 : aItemSet.Put(*pSetAttr);
2398 0 : delete pSetAttr;
2399 : }
2400 : }
2401 : }
2402 :
2403 : // total width of table
2404 74 : if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols )
2405 : {
2406 74 : pTable->GetFrameFormat()->SetFormatAttr(SwFormatFrmSize(ATT_FIX_SIZE, nSwWidth));
2407 74 : aItemSet.Put(SwFormatFrmSize(ATT_FIX_SIZE, nSwWidth));
2408 : }
2409 :
2410 : SvxFrameDirectionItem aDirection(
2411 74 : bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
2412 74 : pTable->GetFrameFormat()->SetFormatAttr(aDirection);
2413 :
2414 74 : if (text::HoriOrientation::LEFT_AND_WIDTH == eOri)
2415 : {
2416 49 : if (!pIo->m_nInTable && pIo->InLocalApo() && pIo->m_pSFlyPara->pFlyFormat &&
2417 3 : GetMinLeft())
2418 : {
2419 : //If we are inside a frame and we have a border, the frames
2420 : //placement does not consider the tables border, which word
2421 : //displays outside the frame, so adjust here.
2422 3 : SwFormatHoriOrient aHori(pIo->m_pSFlyPara->pFlyFormat->GetHoriOrient());
2423 3 : sal_Int16 eHori = aHori.GetHoriOrient();
2424 3 : if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2425 : (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2426 : {
2427 : //With multiple table, use last table settings. Perhaps
2428 : //the maximum is what word does ?
2429 3 : aHori.SetPos(pIo->m_pSFlyPara->nXPos + GetMinLeft());
2430 3 : aHori.SetHoriOrient(text::HoriOrientation::NONE);
2431 3 : pIo->m_pSFlyPara->pFlyFormat->SetFormatAttr(aHori);
2432 3 : }
2433 : }
2434 : else
2435 : {
2436 : //If bApo is set, then this table is being placed in a floating
2437 : //frame, and the frame matches the left and right *lines* of the
2438 : //table, so the space to the left of the table isn't to be used
2439 : //inside the frame, in word the dialog involved greys out the
2440 : //ability to set the margin.
2441 43 : SvxLRSpaceItem aL( RES_LR_SPACE );
2442 : // set right to original DxaLeft (i28656)
2443 :
2444 43 : long nLeft = 0;
2445 43 : if (!bIsBiDi)
2446 38 : nLeft = GetMinLeft();
2447 : else
2448 : {
2449 5 : if (nPreferredWidth)
2450 : {
2451 2 : nLeft = pIo->m_aSectionManager.GetTextAreaWidth();
2452 2 : nLeft = nLeft - nPreferredWidth - nOrgDxaLeft;
2453 : }
2454 : else
2455 3 : nLeft = -GetMinLeft();
2456 : }
2457 :
2458 43 : aL.SetLeft(nLeft);
2459 :
2460 43 : aItemSet.Put(aL);
2461 : }
2462 : }
2463 :
2464 74 : mpOldRedlineStack = pIo->m_pRedlineStack;
2465 74 : pIo->m_pRedlineStack = new sw::util::RedlineStack(pIo->m_rDoc);
2466 : }
2467 :
2468 74 : void WW8TabDesc::UseSwTable()
2469 : {
2470 : // init global Vars
2471 74 : pTabLines = &pTable->GetTabLines();
2472 74 : nAktRow = nAktCol = nAktBandRow = 0;
2473 :
2474 74 : pTableNd = const_cast<SwTableNode*>((*pTabLines)[0]->GetTabBoxes()[0]->
2475 74 : GetSttNd()->FindTableNode());
2476 : OSL_ENSURE( pTableNd, "wo ist mein TabellenNode" );
2477 :
2478 : // #i69519# - Restrict rows to repeat to a decent value
2479 74 : if ( nRowsToRepeat == static_cast<sal_uInt16>(nRows) )
2480 0 : nRowsToRepeat = 1;
2481 :
2482 74 : pTableNd->GetTable().SetRowsToRepeat( nRowsToRepeat );
2483 : // insert extra cells if needed and something like this
2484 74 : AdjustNewBand();
2485 :
2486 74 : WW8DupProperties aDup(pIo->m_rDoc,pIo->m_pCtrlStck);
2487 74 : pIo->m_pCtrlStck->SetAttr(*pIo->m_pPaM->GetPoint(), 0, false);
2488 :
2489 : // now set the correct PaM and prepare first merger group if any
2490 74 : SetPamInCell(nAktCol, true);
2491 74 : aDup.Insert(*pIo->m_pPaM->GetPoint());
2492 :
2493 74 : pIo->m_bWasTabRowEnd = false;
2494 74 : pIo->m_bWasTabCellEnd = false;
2495 74 : }
2496 :
2497 74 : void WW8TabDesc::MergeCells()
2498 : {
2499 : short nRow;
2500 :
2501 371 : for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand)
2502 : {
2503 : // insert current box into merge group if appropriate
2504 297 : if( pActBand->pTCs )
2505 : {
2506 594 : for( short j = 0; j < pActBand->nRows; j++, nRow++ )
2507 1407 : for( short i = 0; i < pActBand->nWwCols; i++ )
2508 : {
2509 1110 : WW8SelBoxInfo* pActMGroup = 0;
2510 :
2511 : // start a new merge group if appropriate
2512 :
2513 : OSL_ENSURE(nRow < (sal_uInt16)pTabLines->size(),
2514 : "Too few lines, table ended early");
2515 1110 : if (nRow >= (sal_uInt16)pTabLines->size())
2516 0 : return;
2517 1110 : pTabLine = (*pTabLines)[ nRow ];
2518 1110 : pTabBoxes = &pTabLine->GetTabBoxes();
2519 :
2520 1110 : sal_uInt16 nCol = pActBand->nTransCell[ i ];
2521 1110 : if (!pActBand->bExist[i])
2522 129 : continue;
2523 : OSL_ENSURE(nCol < pTabBoxes->size(),
2524 : "Too few columns, table ended early");
2525 981 : if (nCol >= pTabBoxes->size())
2526 0 : return;
2527 981 : pTabBox = (*pTabBoxes)[nCol];
2528 981 : WW8_TCell& rCell = pActBand->pTCs[ i ];
2529 : // is this the left upper cell of a merge group ?
2530 :
2531 981 : bool bMerge = false;
2532 981 : if ( rCell.bVertRestart && !rCell.bMerged )
2533 11 : bMerge = true;
2534 970 : else if (rCell.bFirstMerged && pActBand->bExist[i])
2535 : {
2536 : // Some tests to avoid merging cells which previously were
2537 : // declared invalid because of sharing the exact same dimensions
2538 : // as their previous cell
2539 :
2540 : //If theres anything underneath/above we're ok.
2541 1 : if (rCell.bVertMerge || rCell.bVertRestart)
2542 0 : bMerge = true;
2543 : else
2544 : {
2545 : //If it's a hori merge only, and the only things in
2546 : //it are invalid cells then it's already taken care
2547 : //of, so don't merge.
2548 1 : for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2549 2 : if (pActBand->pTCs[ i2 ].bMerged &&
2550 1 : !pActBand->pTCs[ i2 ].bFirstMerged )
2551 : {
2552 1 : if (pActBand->bExist[i2])
2553 : {
2554 1 : bMerge = true;
2555 1 : break;
2556 : }
2557 : }
2558 : else
2559 : break;
2560 : }
2561 : }
2562 :
2563 981 : if (bMerge)
2564 : {
2565 12 : short nX1 = pActBand->nCenter[ i ];
2566 12 : short nWidth = pActBand->nWidth[ i ];
2567 :
2568 : // 2. create current merge group
2569 12 : pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2570 :
2571 : // determine size of new merge group
2572 : // before inserted the new merge group.
2573 : // Needed to correctly locked previously created merge groups.
2574 : // Calculate total width and set
2575 12 : short nSizCell = pActBand->nWidth[ i ];
2576 13 : for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2577 9 : if (pActBand->pTCs[ i2 ].bMerged &&
2578 1 : !pActBand->pTCs[ i2 ].bFirstMerged )
2579 : {
2580 1 : nSizCell = nSizCell + pActBand->nWidth[ i2 ];
2581 : }
2582 : else
2583 : break;
2584 12 : pActMGroup->nGroupWidth = nSizCell;
2585 :
2586 : // locked previously created merge groups,
2587 : // after determining the size for the new merge group.
2588 : // 1. If necessary close old merge group(s) that overlap
2589 : // the X-area of the new group
2590 : for (;;)
2591 : {
2592 : WW8SelBoxInfo* p = FindMergeGroup(
2593 15 : nX1, pActMGroup->nGroupWidth, false );
2594 15 : if (p == 0)
2595 : {
2596 12 : break;
2597 : }
2598 3 : p->bGroupLocked = true;
2599 3 : }
2600 :
2601 : // 3. push to group array
2602 12 : aMergeGroups.push_back(pActMGroup);
2603 : }
2604 :
2605 : // if necessary add the current box to a merge group
2606 : // (that can be a newly created or another group)
2607 981 : UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i );
2608 : }
2609 : }
2610 : }
2611 : }
2612 :
2613 : //There is a limbo area in word at the end of the row marker
2614 : //where properties can live in word, there is no location in
2615 : //writer equivalent, so try and park the cursor in the best
2616 : //match, see #i23022#/#i18644#
2617 288 : void WW8TabDesc::ParkPaM()
2618 : {
2619 288 : SwTableBox *pTabBox2 = 0;
2620 288 : short nRow = nAktRow + 1;
2621 288 : if (nRow < (sal_uInt16)pTabLines->size())
2622 : {
2623 220 : if (SwTableLine *pLine = (*pTabLines)[nRow])
2624 : {
2625 220 : SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2626 220 : pTabBox2 = rBoxes.empty() ? 0 : rBoxes.front();
2627 : }
2628 : }
2629 :
2630 288 : if (!pTabBox2 || !pTabBox2->GetSttNd())
2631 : {
2632 68 : MoveOutsideTable();
2633 356 : return;
2634 : }
2635 :
2636 220 : sal_uLong nSttNd = pTabBox2->GetSttIdx() + 1,
2637 220 : nEndNd = pTabBox2->GetSttNd()->EndOfSectionIndex();
2638 :
2639 220 : if (pIo->m_pPaM->GetPoint()->nNode != nSttNd)
2640 : {
2641 220 : do
2642 : {
2643 220 : pIo->m_pPaM->GetPoint()->nNode = nSttNd;
2644 : }
2645 220 : while (pIo->m_pPaM->GetNode().GetNodeType() != ND_TEXTNODE && ++nSttNd < nEndNd);
2646 :
2647 220 : pIo->m_pPaM->GetPoint()->nContent.Assign(pIo->m_pPaM->GetContentNode(), 0);
2648 220 : pIo->m_rDoc.SetTextFormatColl(*pIo->m_pPaM, const_cast<SwTextFormatColl*>(pIo->m_pDfltTextFormatColl));
2649 : }
2650 : }
2651 :
2652 144 : void WW8TabDesc::MoveOutsideTable()
2653 : {
2654 : OSL_ENSURE(pTmpPos && pIo, "I've forgotten where the table is anchored");
2655 144 : if (pTmpPos && pIo)
2656 144 : *pIo->m_pPaM->GetPoint() = *pTmpPos;
2657 144 : }
2658 :
2659 74 : void WW8TabDesc::FinishSwTable()
2660 : {
2661 74 : pIo->m_pRedlineStack->closeall(*pIo->m_pPaM->GetPoint());
2662 74 : delete pIo->m_pRedlineStack;
2663 74 : pIo->m_pRedlineStack = mpOldRedlineStack;
2664 74 : mpOldRedlineStack = 0;
2665 :
2666 74 : WW8DupProperties aDup(pIo->m_rDoc,pIo->m_pCtrlStck);
2667 74 : pIo->m_pCtrlStck->SetAttr( *pIo->m_pPaM->GetPoint(), 0, false);
2668 :
2669 74 : MoveOutsideTable();
2670 74 : delete pTmpPos, pTmpPos = 0;
2671 :
2672 74 : aDup.Insert(*pIo->m_pPaM->GetPoint());
2673 :
2674 74 : pIo->m_bWasTabRowEnd = false;
2675 74 : pIo->m_bWasTabCellEnd = false;
2676 :
2677 74 : pIo->m_aInsertedTables.InsertTable(*pTableNd, *pIo->m_pPaM);
2678 :
2679 74 : MergeCells();
2680 :
2681 : // if needed group cells together that should be merged
2682 74 : if( !aMergeGroups.empty() )
2683 : {
2684 : // process all merge groups one by one
2685 51 : for (
2686 5 : WW8MergeGroups::iterator groupIt = aMergeGroups.begin();
2687 34 : groupIt != aMergeGroups.end();
2688 : ++groupIt)
2689 : {
2690 12 : sal_uInt16 nActBoxCount = groupIt->size();
2691 :
2692 12 : if( ( 1 < nActBoxCount ) && (*groupIt)[0] )
2693 : {
2694 3 : const sal_uInt16 nRowSpan = groupIt->size();
2695 9 : for (sal_uInt16 n = 0; n < nRowSpan; ++n)
2696 : {
2697 6 : SwTableBox* pCurrentBox = (*groupIt)[n];
2698 : const long nRowSpanSet = n == 0 ?
2699 : nRowSpan :
2700 6 : ((-1) * (nRowSpan - n));
2701 6 : pCurrentBox->setRowSpan( nRowSpanSet );
2702 : }
2703 : }
2704 : }
2705 5 : pIo->m_pFormatOfJustInsertedApo = 0;
2706 5 : aMergeGroups.clear();
2707 74 : }
2708 74 : }
2709 :
2710 : // browse aMergeGroups, detect the index of the first fitting group or -1 otherwise
2711 :
2712 : // Parameter: nXcenter = center position of asking box
2713 : // nWidth = width of asking box
2714 : // bExact = flag, if box has to fit into group
2715 : // or only has to touch
2716 :
2717 18 : WW8SelBoxInfo* WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact)
2718 : {
2719 18 : if( !aMergeGroups.empty() )
2720 : {
2721 : // still valid area near the boundery
2722 13 : const short nToleranz = 4;
2723 : // box boundery
2724 13 : short nX2 = nX1 + nWidth;
2725 : // approximate group boundery
2726 : short nGrX1;
2727 : short nGrX2;
2728 :
2729 : // improvement: search backwards
2730 31 : for ( short iGr = aMergeGroups.size() - 1; iGr >= 0; --iGr )
2731 : {
2732 : // the currently inspected group
2733 24 : WW8SelBoxInfo& rActGroup = aMergeGroups[ iGr ];
2734 24 : if (!rActGroup.bGroupLocked)
2735 : {
2736 : // approximate group boundery with room (tolerance) to the *outside*
2737 18 : nGrX1 = rActGroup.nGroupXStart - nToleranz;
2738 : nGrX2 = rActGroup.nGroupXStart
2739 18 : +rActGroup.nGroupWidth + nToleranz;
2740 :
2741 : // If box fits report success
2742 :
2743 18 : if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2744 : {
2745 3 : return &rActGroup;
2746 : }
2747 :
2748 : // does the box share areas with the group?
2749 :
2750 15 : if( !bExact )
2751 : {
2752 : // successful if nX1 *or* nX2 are inside the group
2753 14 : if( ( ( nX1 > nGrX1 )
2754 9 : && ( nX1 < nGrX2 - 2*nToleranz ) )
2755 13 : || ( ( nX2 > nGrX1 + 2*nToleranz )
2756 10 : && ( nX2 < nGrX2 ) )
2757 : // or nX1 and nX2 surround the group
2758 11 : || ( ( nX1 <=nGrX1 )
2759 3 : && ( nX2 >=nGrX2 ) ) )
2760 : {
2761 3 : return &rActGroup;
2762 : }
2763 : }
2764 : }
2765 : }
2766 : }
2767 12 : return 0;
2768 : }
2769 :
2770 2688 : bool WW8TabDesc::IsValidCell(short nCol) const
2771 : {
2772 5376 : return (static_cast<size_t>(nCol) < SAL_N_ELEMENTS(pActBand->bExist)) &&
2773 5343 : pActBand->bExist[nCol] &&
2774 5343 : (sal_uInt16)nAktRow < pTabLines->size();
2775 : }
2776 :
2777 472 : bool WW8TabDesc::InFirstParaInCell() const
2778 : {
2779 : //e.g. #i19718#
2780 472 : if (!pTabBox || !pTabBox->GetSttNd())
2781 : {
2782 : OSL_FAIL("Problem with table");
2783 0 : return false;
2784 : }
2785 :
2786 472 : if (!IsValidCell(GetAktCol()))
2787 0 : return false;
2788 :
2789 472 : if (pIo->m_pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1)
2790 213 : return true;
2791 :
2792 259 : return false;
2793 : }
2794 :
2795 949 : void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol)
2796 : {
2797 : OSL_ENSURE(pActBand, "Impossible");
2798 949 : if (pActBand && pActBand->maDirections[nWwCol] == 3)
2799 : {
2800 1 : pIo->m_pCtrlStck->NewAttr(*pIo->m_pPaM->GetPoint(),
2801 2 : SvxCharRotateItem(900, false, RES_CHRATR_ROTATE));
2802 : }
2803 949 : }
2804 :
2805 1239 : void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol)
2806 : {
2807 : OSL_ENSURE(pActBand, "Impossible");
2808 1239 : if (pActBand && pActBand->maDirections[nWwCol] == 3)
2809 1 : pIo->m_pCtrlStck->SetAttr(*pIo->m_pPaM->GetPoint(), RES_CHRATR_ROTATE);
2810 1239 : }
2811 :
2812 1536 : bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2813 : {
2814 : OSL_ENSURE( pActBand, "pActBand ist 0" );
2815 1536 : if (!pActBand)
2816 0 : return false;
2817 :
2818 1536 : sal_uInt16 nCol = pActBand->transCell(nWwCol);
2819 :
2820 1536 : if ((sal_uInt16)nAktRow >= pTabLines->size())
2821 : {
2822 : OSL_ENSURE(false, "Actual row bigger than expected." );
2823 2 : if (bPam)
2824 2 : MoveOutsideTable();
2825 2 : return false;
2826 : }
2827 :
2828 1534 : pTabLine = (*pTabLines)[nAktRow];
2829 1534 : pTabBoxes = &pTabLine->GetTabBoxes();
2830 :
2831 1534 : if (nCol >= pTabBoxes->size())
2832 : {
2833 288 : if (bPam)
2834 : {
2835 : // The first paragraph in a cell with upper autospacing has upper
2836 : // spacing set to 0
2837 288 : if (
2838 0 : pIo->m_bParaAutoBefore && pIo->m_bFirstPara &&
2839 0 : !pIo->m_pWDop->fDontUseHTMLAutoSpacing
2840 : )
2841 : {
2842 0 : pIo->SetUpperSpacing(*pIo->m_pPaM, 0);
2843 : }
2844 :
2845 : // The last paragraph in a cell with lower autospacing has lower
2846 : // spacing set to 0
2847 288 : if (pIo->m_bParaAutoAfter && !pIo->m_pWDop->fDontUseHTMLAutoSpacing)
2848 0 : pIo->SetLowerSpacing(*pIo->m_pPaM, 0);
2849 :
2850 288 : ParkPaM();
2851 : }
2852 288 : return false;
2853 : }
2854 1246 : pTabBox = (*pTabBoxes)[nCol];
2855 1246 : if( !pTabBox->GetSttNd() )
2856 : {
2857 : OSL_ENSURE(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2858 0 : if (bPam)
2859 0 : MoveOutsideTable();
2860 0 : return false;
2861 : }
2862 1246 : if (bPam)
2863 : {
2864 949 : pAktWWCell = &pActBand->pTCs[ nWwCol ];
2865 :
2866 : // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2867 949 : if(pIo->m_bParaAutoBefore && pIo->m_bFirstPara && !pIo->m_pWDop->fDontUseHTMLAutoSpacing)
2868 0 : pIo->SetUpperSpacing(*pIo->m_pPaM, 0);
2869 :
2870 : // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2871 949 : if(pIo->m_bParaAutoAfter && !pIo->m_pWDop->fDontUseHTMLAutoSpacing)
2872 0 : pIo->SetLowerSpacing(*pIo->m_pPaM, 0);
2873 :
2874 : //We need to set the pPaM on the first cell, invalid
2875 : //or not so that we can collect paragraph proproties over
2876 : //all the cells, but in that case on the valid cell we do not
2877 : //want to reset the fmt properties
2878 949 : sal_uLong nSttNd = pTabBox->GetSttIdx() + 1,
2879 949 : nEndNd = pTabBox->GetSttNd()->EndOfSectionIndex();
2880 949 : if (pIo->m_pPaM->GetPoint()->nNode != nSttNd)
2881 : {
2882 727 : do
2883 : {
2884 727 : pIo->m_pPaM->GetPoint()->nNode = nSttNd;
2885 : }
2886 727 : while (pIo->m_pPaM->GetNode().GetNodeType() != ND_TEXTNODE && ++nSttNd < nEndNd);
2887 727 : pIo->m_pPaM->GetPoint()->nContent.Assign(pIo->m_pPaM->GetContentNode(), 0);
2888 : // Precautionally set now, otherwise the style is not set for cells
2889 : // that are inserted for margin balancing.
2890 727 : pIo->m_rDoc.SetTextFormatColl(*pIo->m_pPaM, const_cast<SwTextFormatColl*>(pIo->m_pDfltTextFormatColl));
2891 : // because this cells are invisible helper constructions only to simulate
2892 : // the frayed view of WW-tables we do NOT need SetTextFormatCollAndListLevel()
2893 : }
2894 :
2895 : // Better to turn Snap to Grid off for all paragraphs in tables
2896 949 : if(SwTextNode *pNd = pIo->m_pPaM->GetNode().GetTextNode())
2897 : {
2898 949 : const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_PARATR_SNAPTOGRID);
2899 949 : const SvxParaGridItem &rSnapToGrid = static_cast<const SvxParaGridItem&>(rItm);
2900 :
2901 949 : if(rSnapToGrid.GetValue())
2902 : {
2903 949 : SvxParaGridItem aGridItem( rSnapToGrid );
2904 949 : aGridItem.SetValue(false);
2905 :
2906 949 : SwPosition* pGridPos = pIo->m_pPaM->GetPoint();
2907 :
2908 949 : const sal_Int32 nEnd = pGridPos->nContent.GetIndex();
2909 949 : pGridPos->nContent.Assign(pIo->m_pPaM->GetContentNode(), 0);
2910 949 : pIo->m_pCtrlStck->NewAttr(*pGridPos, aGridItem);
2911 949 : pGridPos->nContent.Assign(pIo->m_pPaM->GetContentNode(), nEnd);
2912 949 : pIo->m_pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
2913 : }
2914 : }
2915 :
2916 949 : StartMiserableHackForUnsupportedDirection(nWwCol);
2917 : }
2918 1246 : return true;
2919 : }
2920 :
2921 52 : void WW8TabDesc::InsertCells( short nIns )
2922 : {
2923 52 : pTabLine = (*pTabLines)[nAktRow];
2924 52 : pTabBoxes = &pTabLine->GetTabBoxes();
2925 52 : pTabBox = (*pTabBoxes)[0];
2926 :
2927 104 : pIo->m_rDoc.GetNodes().InsBoxen( pTableNd, pTabLine, static_cast<SwTableBoxFormat*>(pTabBox->GetFrameFormat()),
2928 156 : const_cast<SwTextFormatColl*>(pIo->m_pDfltTextFormatColl), 0, pTabBoxes->size(), nIns );
2929 : // The third parameter contains the FrameFormat of the boxes.
2930 : // Here it is possible to optimize to save (reduce) FrameFormats.
2931 52 : }
2932 :
2933 988 : void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
2934 : {
2935 988 : if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
2936 995 : return; // faked cells -> no border
2937 :
2938 981 : SvxBoxItem aFormatBox( RES_BOX );
2939 981 : if (pActBand->pTCs) // neither Cell Border nor Default Border defined ?
2940 : {
2941 981 : WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
2942 981 : if (SwWW8ImplReader::IsBorder(pT->rgbrc))
2943 819 : SwWW8ImplReader::SetBorder(aFormatBox, pT->rgbrc);
2944 : }
2945 :
2946 981 : if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
2947 : {
2948 : aFormatBox.SetDistance(
2949 0 : pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP],
2950 0 : SvxBoxItemLine::TOP);
2951 : }
2952 : else
2953 981 : aFormatBox.SetDistance(pActBand->mnDefaultTop, SvxBoxItemLine::TOP);
2954 981 : if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM))
2955 : {
2956 : aFormatBox.SetDistance(
2957 0 : pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM],
2958 0 : SvxBoxItemLine::BOTTOM);
2959 : }
2960 : else
2961 981 : aFormatBox.SetDistance(pActBand->mnDefaultBottom,SvxBoxItemLine::BOTTOM);
2962 :
2963 : // nGapHalf for WW is a *horizontal* gap between table cell and content.
2964 : short nLeftDist =
2965 981 : pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf;
2966 : short nRightDist =
2967 981 : pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf;
2968 981 : if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
2969 : {
2970 : aFormatBox.SetDistance(
2971 0 : pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT],
2972 0 : SvxBoxItemLine::LEFT);
2973 : }
2974 : else
2975 981 : aFormatBox.SetDistance(nLeftDist, SvxBoxItemLine::LEFT);
2976 981 : if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
2977 : {
2978 : aFormatBox.SetDistance(
2979 0 : pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT],
2980 0 : SvxBoxItemLine::RIGHT);
2981 : }
2982 : else
2983 981 : aFormatBox.SetDistance(nRightDist,SvxBoxItemLine::RIGHT);
2984 :
2985 981 : pBox->GetFrameFormat()->SetFormatAttr(aFormatBox);
2986 : }
2987 :
2988 721 : void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
2989 : {
2990 721 : if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
2991 1 : return; // faked cells -> no color
2992 :
2993 720 : bool bFound=false;
2994 720 : if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
2995 : {
2996 222 : Color aColor(pActBand->pNewSHDs[nWwIdx]);
2997 222 : pBox->GetFrameFormat()->SetFormatAttr(SvxBrushItem(aColor, RES_BACKGROUND));
2998 222 : bFound = true;
2999 : }
3000 :
3001 : //If there was no new shades, or no new shade setting
3002 720 : if (pActBand->pSHDs && !bFound)
3003 : {
3004 498 : WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx];
3005 498 : if (!rSHD.GetValue()) // auto
3006 498 : return;
3007 :
3008 0 : SwWW8Shade aSh( pIo->m_bVer67, rSHD );
3009 0 : pBox->GetFrameFormat()->SetFormatAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND));
3010 : }
3011 : }
3012 :
3013 981 : SvxFrameDirection MakeDirection(sal_uInt16 nCode, bool bIsBiDi)
3014 : {
3015 981 : SvxFrameDirection eDir = FRMDIR_ENVIRONMENT;
3016 : // 1: Asian layout with rotated CJK characters
3017 : // 5: Asian layout
3018 : // 3: Western layout rotated by 90 degrees
3019 : // 4: Western layout
3020 981 : switch (nCode)
3021 : {
3022 : default:
3023 : OSL_ENSURE(eDir == 4, "unknown direction code, maybe it's a bitfield");
3024 : //fall-through
3025 : case 3:
3026 1 : eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP; // #i38158# - Consider RTL tables
3027 1 : break;
3028 : case 5:
3029 0 : eDir = FRMDIR_VERT_TOP_RIGHT;
3030 0 : break;
3031 : case 1:
3032 0 : eDir = FRMDIR_VERT_TOP_RIGHT;
3033 0 : break;
3034 : case 4:
3035 980 : eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP; // #i38158# - Consider RTL tables
3036 980 : break;
3037 : }
3038 981 : return eDir;
3039 : }
3040 :
3041 988 : void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3042 : {
3043 988 : if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols)
3044 995 : return;
3045 981 : SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR);
3046 981 : pBox->GetFrameFormat()->SetFormatAttr(aItem);
3047 : }
3048 :
3049 988 : void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3050 : {
3051 988 : if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3052 995 : return;
3053 :
3054 981 : sal_Int16 eVertOri=text::VertOrientation::TOP;
3055 :
3056 981 : if( pActBand->pTCs )
3057 : {
3058 981 : WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3059 981 : switch (pT->nVertAlign)
3060 : {
3061 : case 0:
3062 : default:
3063 902 : eVertOri = text::VertOrientation::TOP;
3064 902 : break;
3065 : case 1:
3066 79 : eVertOri = text::VertOrientation::CENTER;
3067 79 : break;
3068 : case 2:
3069 0 : eVertOri = text::VertOrientation::BOTTOM;
3070 0 : break;
3071 : }
3072 : }
3073 :
3074 981 : pBox->GetFrameFormat()->SetFormatAttr( SwFormatVertOrient(0,eVertOri) );
3075 : }
3076 :
3077 297 : void WW8TabDesc::AdjustNewBand()
3078 : {
3079 297 : if( pActBand->nSwCols > nDefaultSwCols ) // split cells
3080 52 : InsertCells( pActBand->nSwCols - nDefaultSwCols );
3081 :
3082 297 : SetPamInCell( 0, false);
3083 : OSL_ENSURE( pTabBoxes && pTabBoxes->size() == (sal_uInt16)pActBand->nSwCols,
3084 : "Falsche Spaltenzahl in Tabelle" );
3085 :
3086 297 : if( bClaimLineFormat )
3087 : {
3088 203 : pTabLine->ClaimFrameFormat(); // necessary because of cell height
3089 203 : SwFormatFrmSize aF( ATT_MIN_SIZE, 0, 0 ); // default
3090 :
3091 203 : if (pActBand->nLineHeight == 0) // 0 = Auto
3092 62 : aF.SetHeightSizeType( ATT_VAR_SIZE );
3093 : else
3094 : {
3095 141 : if (pActBand->nLineHeight < 0) // positive = min, negative = exact
3096 : {
3097 66 : aF.SetHeightSizeType(ATT_FIX_SIZE);
3098 66 : pActBand->nLineHeight = -pActBand->nLineHeight;
3099 : }
3100 141 : if (pActBand->nLineHeight < MINLAY) // invalid cell height
3101 0 : pActBand->nLineHeight = MINLAY;
3102 :
3103 141 : aF.SetHeight(pActBand->nLineHeight);// set min/exact height
3104 : }
3105 203 : pTabLine->GetFrameFormat()->SetFormatAttr(aF);
3106 : }
3107 :
3108 : //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3109 : //we can split the row
3110 297 : bool bSetCantSplit = pActBand->bCantSplit;
3111 297 : pTabLine->GetFrameFormat()->SetFormatAttr(SwFormatRowSplit(!bSetCantSplit));
3112 :
3113 : short i; // SW-Index
3114 : short j; // WW-Index
3115 : short nW; // Width
3116 297 : SwFormatFrmSize aFS( ATT_FIX_SIZE );
3117 297 : j = pActBand->bLEmptyCol ? -1 : 0;
3118 :
3119 1285 : for( i = 0; i < pActBand->nSwCols; i++ )
3120 : {
3121 : // set cell width
3122 988 : if( j < 0 )
3123 0 : nW = pActBand->nCenter[0] - nMinLeft;
3124 : else
3125 : {
3126 : //Set j to first non invalid cell
3127 1976 : while ((j < pActBand->nWwCols) && (!pActBand->bExist[j]))
3128 0 : j++;
3129 :
3130 988 : if( j < pActBand->nWwCols )
3131 981 : nW = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3132 : else
3133 7 : nW = nMaxRight - pActBand->nCenter[j];
3134 988 : pActBand->nWidth[ j ] = nW;
3135 : }
3136 :
3137 988 : SwTableBox* pBox = (*pTabBoxes)[i];
3138 : // could be reduced further by intelligent moving of FrameFormats
3139 988 : pBox->ClaimFrameFormat();
3140 :
3141 988 : SetTabBorders(pBox, j);
3142 :
3143 : // #i18128# word has only one line between adjoining vertical cells
3144 : // we have to mimick this in the filter by picking the larger of the
3145 : // sides and using that one on one side of the line (right)
3146 988 : SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrameFormat()), RES_BOX));
3147 988 : const ::editeng::SvxBorderLine *pLeftLine = aCurrentBox.GetLine(SvxBoxItemLine::LEFT);
3148 988 : int nCurrentRightLineWidth = 0;
3149 988 : if(pLeftLine)
3150 667 : nCurrentRightLineWidth = pLeftLine->GetScaledWidth();
3151 :
3152 988 : if (i != 0)
3153 : {
3154 691 : SwTableBox* pBox2 = (*pTabBoxes)[i-1];
3155 691 : SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrameFormat()), RES_BOX));
3156 691 : const ::editeng::SvxBorderLine *pRightLine = aOldBox.GetLine(SvxBoxItemLine::RIGHT);
3157 691 : int nOldBoxRightLineWidth = 0;
3158 691 : if(pRightLine)
3159 302 : nOldBoxRightLineWidth = pRightLine->GetScaledWidth();
3160 :
3161 691 : if(nOldBoxRightLineWidth>nCurrentRightLineWidth)
3162 6 : aCurrentBox.SetLine(aOldBox.GetLine(SvxBoxItemLine::RIGHT), SvxBoxItemLine::LEFT);
3163 :
3164 691 : aOldBox.SetLine(0, SvxBoxItemLine::RIGHT);
3165 691 : pBox2->GetFrameFormat()->SetFormatAttr(aOldBox);
3166 : }
3167 :
3168 988 : pBox->GetFrameFormat()->SetFormatAttr(aCurrentBox);
3169 :
3170 988 : SetTabVertAlign(pBox, j);
3171 988 : SetTabDirection(pBox, j);
3172 988 : if( pActBand->pSHDs || pActBand->pNewSHDs)
3173 721 : SetTabShades(pBox, j);
3174 988 : j++;
3175 :
3176 988 : aFS.SetWidth( nW );
3177 988 : pBox->GetFrameFormat()->SetFormatAttr( aFS );
3178 :
3179 : // skip non existing cells
3180 2105 : while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] )
3181 : {
3182 129 : pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3183 129 : j++;
3184 : }
3185 1285 : }
3186 297 : }
3187 :
3188 1239 : void WW8TabDesc::TableCellEnd()
3189 : {
3190 1239 : ::SetProgressState(pIo->m_nProgress, pIo->m_pDocShell); // Update
3191 :
3192 1239 : EndMiserableHackForUnsupportedDirection(nAktCol);
3193 :
3194 : // new line/row
3195 1239 : if( pIo->m_bWasTabRowEnd )
3196 : {
3197 : // bWasTabRowEnd will be deactivated in
3198 : // SwWW8ImplReader::ProcessSpecial()
3199 :
3200 297 : sal_uInt16 iCol = GetLogicalWWCol();
3201 297 : if (iCol < aNumRuleNames.size())
3202 : {
3203 0 : aNumRuleNames.erase(aNumRuleNames.begin() + iCol,
3204 0 : aNumRuleNames.end());
3205 : }
3206 :
3207 297 : nAktCol = 0;
3208 297 : nAktRow++;
3209 297 : nAktBandRow++;
3210 : OSL_ENSURE( pActBand , "pActBand ist 0" );
3211 297 : if( pActBand )
3212 : {
3213 297 : if( nAktRow >= nRows ) // nothing to at end of table
3214 1313 : return;
3215 :
3216 223 : bool bNewBand = nAktBandRow >= pActBand->nRows;
3217 223 : if( bNewBand )
3218 : { // new band needed ?
3219 223 : pActBand = pActBand->pNextBand;
3220 223 : nAktBandRow = 0;
3221 : OSL_ENSURE( pActBand, "pActBand ist 0" );
3222 223 : AdjustNewBand();
3223 : }
3224 : else
3225 : {
3226 0 : SwTableBox* pBox = (*pTabBoxes)[0];
3227 0 : SwSelBoxes aBoxes;
3228 0 : pIo->m_rDoc.InsertRow( SwTable::SelLineFromBox( pBox, aBoxes ) );
3229 : }
3230 : }
3231 : }
3232 : else
3233 : { // new column ( cell )
3234 942 : nAktCol++;
3235 : }
3236 1165 : SetPamInCell(nAktCol, true);
3237 :
3238 : // finish Annotated Level Numbering ?
3239 1165 : if (pIo->m_bAnl && !pIo->m_bAktAND_fNumberAcross && pActBand)
3240 0 : pIo->StopAllAnl(IsValidCell(nAktCol));
3241 : }
3242 :
3243 : // if necessary register the box for the merge group for this column
3244 981 : SwTableBox* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell& rCell,
3245 : WW8SelBoxInfo* pActGroup,
3246 : SwTableBox* pActBox,
3247 : sal_uInt16 nCol )
3248 : {
3249 : // set default for return
3250 981 : SwTableBox* pResult = 0;
3251 :
3252 : // check if the box has to be merged
3253 : // If cell is the first one to be merged, a new merge group has to be provided.
3254 : // E.g., it could be that a cell is the first one to be merged, but no
3255 : // new merge group is provided, because the potential other cell to be merged
3256 : // doesn't exist - see method <WW8TabDesc::MergeCells>.
3257 981 : if ( pActBand->bExist[ nCol ] &&
3258 3 : ( ( rCell.bFirstMerged && pActGroup ) ||
3259 977 : rCell.bMerged ||
3260 966 : rCell.bVertMerge ||
3261 : rCell.bVertRestart ) )
3262 : {
3263 : // detect appropriate merge group
3264 15 : WW8SelBoxInfo* pTheMergeGroup = 0;
3265 15 : if( pActGroup )
3266 : // assign group
3267 12 : pTheMergeGroup = pActGroup;
3268 : else
3269 : {
3270 : // find group
3271 : pTheMergeGroup = FindMergeGroup(
3272 3 : pActBand->nCenter[ nCol ], pActBand->nWidth[ nCol ], true );
3273 : }
3274 15 : if( pTheMergeGroup )
3275 : {
3276 : // add current box to merge group
3277 15 : pTheMergeGroup->push_back(pActBox);
3278 : // return target box
3279 15 : pResult = (*pTheMergeGroup)[ 0 ];
3280 : }
3281 : }
3282 981 : return pResult;
3283 : }
3284 :
3285 297 : sal_uInt16 WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3286 : {
3287 297 : sal_uInt16 nCol = 0;
3288 297 : if( pActBand && pActBand->pTCs)
3289 : {
3290 1225 : for( sal_uInt16 iCol = 1; iCol <= nAktCol && iCol <= pActBand->nWwCols; ++iCol )
3291 : {
3292 928 : if( !pActBand->pTCs[ iCol-1 ].bMerged )
3293 927 : ++nCol;
3294 : }
3295 : }
3296 297 : return nCol;
3297 : }
3298 :
3299 : // find name of numrule valid for current WW-COL
3300 0 : OUString WW8TabDesc::GetNumRuleName() const
3301 : {
3302 0 : sal_uInt16 nCol = GetLogicalWWCol();
3303 0 : if (nCol < aNumRuleNames.size())
3304 0 : return aNumRuleNames[nCol];
3305 0 : return OUString();
3306 : }
3307 :
3308 0 : void WW8TabDesc::SetNumRuleName( const OUString& rName )
3309 : {
3310 0 : sal_uInt16 nCol = GetLogicalWWCol();
3311 0 : for (sal_uInt16 nSize = static_cast< sal_uInt16 >(aNumRuleNames.size()); nSize <= nCol; ++nSize)
3312 0 : aNumRuleNames.push_back(OUString());
3313 0 : aNumRuleNames[nCol] = rName;
3314 0 : }
3315 :
3316 74 : bool SwWW8ImplReader::StartTable(WW8_CP nStartCp, SvxULSpaceItem* pULSpaceItem)
3317 : {
3318 : // Entering a table so make sure the FirstPara flag gets set
3319 74 : m_bFirstPara = true;
3320 : // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3321 : // Fussnote
3322 74 : if (m_bReadNoTable)
3323 0 : return false;
3324 :
3325 74 : if (m_pTableDesc)
3326 9 : m_aTableStack.push(m_pTableDesc);
3327 :
3328 : // #i33818# - determine absolute position object attributes,
3329 : // if possible. It's needed for nested tables.
3330 74 : WW8FlyPara* pTableWFlyPara( 0L );
3331 74 : WW8SwFlyPara* pTableSFlyPara( 0L );
3332 : // #i45301# - anchor nested table inside Writer fly frame
3333 : // only at-character, if absolute position object attributes are available.
3334 : // Thus, default anchor type is as-character anchored.
3335 74 : RndStdIds eAnchor( FLY_AS_CHAR );
3336 74 : if ( m_nInTable )
3337 : {
3338 9 : WW8_TablePos* pNestedTabPos( 0L );
3339 : WW8_TablePos aNestedTabPos;
3340 : WW8PLCFxSave1 aSave;
3341 9 : m_pPlcxMan->GetPap()->Save( aSave );
3342 9 : WW8PLCFx_Cp_FKP* pPap = m_pPlcxMan->GetPapPLCF();
3343 9 : WW8_CP nMyStartCp = nStartCp;
3344 18 : if ( SearchRowEnd( pPap, nMyStartCp, m_nInTable ) &&
3345 9 : ParseTabPos( &aNestedTabPos, pPap ) )
3346 : {
3347 0 : pNestedTabPos = &aNestedTabPos;
3348 : }
3349 9 : m_pPlcxMan->GetPap()->Restore( aSave );
3350 9 : if ( pNestedTabPos )
3351 : {
3352 0 : ApoTestResults aApo = TestApo( m_nInTable + 1, false, pNestedTabPos );
3353 0 : pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3354 0 : if ( pTableWFlyPara )
3355 : {
3356 : // <WW8SwFlyPara> constructor has changed - new 4th parameter
3357 : // containing WW8 page top margin.
3358 : pTableSFlyPara = new WW8SwFlyPara(*m_pPaM, *this, *pTableWFlyPara,
3359 0 : m_aSectionManager.GetWWPageTopMargin(),
3360 0 : m_aSectionManager.GetPageLeft(), m_aSectionManager.GetTextAreaWidth(),
3361 0 : m_nIniFlyDx, m_nIniFlyDy);
3362 :
3363 : // #i45301# - anchor nested table Writer fly frame at-character
3364 0 : eAnchor = FLY_AT_CHAR;
3365 : }
3366 : }
3367 : }
3368 :
3369 74 : m_pTableDesc = new WW8TabDesc( this, nStartCp );
3370 :
3371 74 : if( m_pTableDesc->Ok() )
3372 : {
3373 74 : int nNewInTable = m_nInTable + 1;
3374 :
3375 74 : if ((eAnchor == FLY_AT_CHAR)
3376 74 : && !m_aTableStack.empty() && !InEqualApo(nNewInTable) )
3377 : {
3378 0 : m_pTableDesc->pParentPos = new SwPosition(*m_pPaM->GetPoint());
3379 0 : SfxItemSet aItemSet(m_rDoc.GetAttrPool(),
3380 0 : RES_FRMATR_BEGIN, RES_FRMATR_END-1);
3381 : // #i33818# - anchor the Writer fly frame for the nested table at-character.
3382 : // #i45301#
3383 0 : SwFormatAnchor aAnchor( eAnchor );
3384 0 : aAnchor.SetAnchor( m_pTableDesc->pParentPos );
3385 0 : aItemSet.Put( aAnchor );
3386 : m_pTableDesc->pFlyFormat = m_rDoc.MakeFlySection( eAnchor,
3387 0 : m_pTableDesc->pParentPos, &aItemSet);
3388 : OSL_ENSURE( m_pTableDesc->pFlyFormat->GetAnchor().GetAnchorId() == eAnchor,
3389 : "Not the anchor type requested!" );
3390 0 : MoveInsideFly(m_pTableDesc->pFlyFormat);
3391 : }
3392 74 : m_pTableDesc->CreateSwTable(pULSpaceItem);
3393 74 : if (m_pTableDesc->pFlyFormat)
3394 : {
3395 0 : m_pTableDesc->SetSizePosition(m_pTableDesc->pFlyFormat);
3396 : // #i33818# - Use absolute position object attributes,
3397 : // if existing, and apply them to the created Writer fly frame.
3398 0 : if ( pTableWFlyPara && pTableSFlyPara )
3399 : {
3400 0 : WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false );
3401 0 : SwFormatAnchor aAnchor( FLY_AT_CHAR );
3402 0 : aAnchor.SetAnchor( m_pTableDesc->pParentPos );
3403 0 : aFlySet.Put( aAnchor );
3404 0 : m_pTableDesc->pFlyFormat->SetFormatAttr( aFlySet );
3405 : }
3406 : else
3407 : {
3408 : SwFormatHoriOrient aHori =
3409 0 : m_pTableDesc->pTable->GetFrameFormat()->GetHoriOrient();
3410 0 : m_pTableDesc->pFlyFormat->SetFormatAttr(aHori);
3411 0 : m_pTableDesc->pFlyFormat->SetFormatAttr( SwFormatSurround( SURROUND_NONE ) );
3412 : }
3413 : // #i33818# - The nested table doesn't have to leave
3414 : // the table cell. Thus, the Writer fly frame has to follow the text flow.
3415 0 : m_pTableDesc->pFlyFormat->SetFormatAttr( SwFormatFollowTextFlow( true ) );
3416 : }
3417 : else
3418 74 : m_pTableDesc->SetSizePosition(0);
3419 74 : m_pTableDesc->UseSwTable();
3420 : }
3421 : else
3422 0 : PopTableDesc();
3423 :
3424 : // #i33818#
3425 74 : delete pTableWFlyPara;
3426 74 : delete pTableSFlyPara;
3427 :
3428 74 : return 0 != m_pTableDesc;
3429 : }
3430 :
3431 1239 : void SwWW8ImplReader::TabCellEnd()
3432 : {
3433 1239 : if (m_nInTable && m_pTableDesc)
3434 1239 : m_pTableDesc->TableCellEnd();
3435 :
3436 1239 : m_bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3437 1239 : m_bReadTable = false;
3438 1239 : m_pTableEndPaM.reset();
3439 1239 : }
3440 :
3441 252 : void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16, const sal_uInt8* pData, short nLen)
3442 : {
3443 252 : if( ( nLen > 0 ) && ( *pData == 1 ) )
3444 126 : m_bWasTabCellEnd = true;
3445 252 : }
3446 :
3447 950 : void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm25
3448 : {
3449 950 : if( ( nLen > 0 ) && ( *pData == 1 ) )
3450 475 : m_bWasTabRowEnd = true;
3451 950 : }
3452 :
3453 74 : void SwWW8ImplReader::PopTableDesc()
3454 : {
3455 74 : if (m_pTableDesc && m_pTableDesc->pFlyFormat)
3456 : {
3457 0 : MoveOutsideFly(m_pTableDesc->pFlyFormat,*m_pTableDesc->pParentPos);
3458 : }
3459 :
3460 74 : delete m_pTableDesc;
3461 74 : if (m_aTableStack.empty())
3462 65 : m_pTableDesc = 0;
3463 : else
3464 : {
3465 9 : m_pTableDesc = m_aTableStack.top();
3466 9 : m_aTableStack.pop();
3467 : }
3468 74 : }
3469 :
3470 74 : void SwWW8ImplReader::StopTable()
3471 : {
3472 : OSL_ENSURE(m_pTableDesc, "Panic, stop table with no table!");
3473 74 : if (!m_pTableDesc)
3474 74 : return;
3475 :
3476 : // We are leaving a table so make sure the next paragraph doesn't think
3477 : // it's the first paragraph
3478 74 : m_bFirstPara = false;
3479 :
3480 74 : m_pTableDesc->FinishSwTable();
3481 74 : PopTableDesc();
3482 :
3483 74 : m_bReadTable = true;
3484 : // #i101116# - Keep PaM on table end only for nested tables
3485 74 : if ( m_nInTable > 1 )
3486 : {
3487 9 : m_pTableEndPaM.reset(new SwPaM(*m_pPaM, m_pPaM));
3488 : }
3489 : }
3490 :
3491 6949 : bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3492 : {
3493 6949 : if( !m_pTableDesc )
3494 5207 : return false;
3495 :
3496 1742 : const WW8_TCell* pCell = m_pTableDesc->GetAktWWCell();
3497 :
3498 1742 : return !m_pTableDesc->IsValidCell( m_pTableDesc->GetAktCol() )
3499 1780 : || ( pCell
3500 1707 : && ( !pCell->bFirstMerged
3501 1704 : && ( pCell->bMerged
3502 1703 : || ( pCell->bVertMerge
3503 9 : && !pCell->bVertRestart
3504 : )
3505 : )
3506 : )
3507 1742 : );
3508 : }
3509 :
3510 15 : sal_uInt16 SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex ) const
3511 : {
3512 15 : sal_uInt16 nRes = USHRT_MAX;
3513 15 : if( !m_vColl.empty() )
3514 : {
3515 0 : for(sal_uInt16 nI = 0; nI < m_pStyles->GetCount(); nI++ )
3516 0 : if( m_vColl[ nI ].bValid
3517 0 : && (nLFOIndex == m_vColl[ nI ].nLFOIndex) )
3518 0 : nRes = nI;
3519 : }
3520 15 : return nRes;
3521 : }
3522 :
3523 0 : const SwFormat* SwWW8ImplReader::GetStyleWithOrgWWName( OUString& rName ) const
3524 : {
3525 0 : SwFormat* pRet = 0;
3526 0 : if( !m_vColl.empty() )
3527 : {
3528 0 : for(sal_uInt16 nI = 0; nI < m_pStyles->GetCount(); nI++ )
3529 0 : if( m_vColl[ nI ].bValid
3530 0 : && (rName.equals( m_vColl[ nI ].GetOrgWWName())) )
3531 : {
3532 0 : pRet = m_vColl[ nI ].pFormat;
3533 0 : break;
3534 : }
3535 : }
3536 0 : return pRet;
3537 : }
3538 :
3539 : // class WW8RStyle
3540 :
3541 436 : const sal_uInt8* WW8RStyle::HasParaSprm( sal_uInt16 nId ) const
3542 : {
3543 436 : if( !pParaSprms || !nSprmsLen )
3544 0 : return 0;
3545 :
3546 436 : return maSprmParser.findSprmData(nId, pParaSprms, nSprmsLen);
3547 : }
3548 :
3549 1940 : void WW8RStyle::ImportSprms(sal_uInt8 *pSprms, short nLen, bool bPap)
3550 : {
3551 1940 : if (!nLen)
3552 1940 : return;
3553 :
3554 1940 : if( bPap )
3555 : {
3556 876 : pParaSprms = pSprms; // for HasParaSprms()
3557 876 : nSprmsLen = nLen;
3558 : }
3559 :
3560 1940 : WW8SprmIter aSprmIter(pSprms, nLen, maSprmParser);
3561 9750 : while (const sal_uInt8* pSprm = aSprmIter.GetSprms())
3562 : {
3563 7810 : pIo->ImportSprm(pSprm);
3564 7810 : aSprmIter.advance();
3565 : }
3566 :
3567 1940 : pParaSprms = 0;
3568 9750 : nSprmsLen = 0;
3569 : }
3570 :
3571 1954 : void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap)
3572 : {
3573 1954 : if (!nLen)
3574 1970 : return;
3575 :
3576 1938 : if (checkSeek(*pStStrm, nPosFc))
3577 : {
3578 1938 : sal_uInt8 *pSprms = new sal_uInt8[nLen];
3579 1938 : nLen = pStStrm->Read(pSprms, nLen);
3580 1938 : ImportSprms(pSprms, nLen, bPap);
3581 1938 : delete[] pSprms;
3582 : }
3583 : }
3584 :
3585 4342 : static inline short WW8SkipOdd(SvStream* pSt )
3586 : {
3587 4342 : if ( pSt->Tell() & 0x1 )
3588 : {
3589 : sal_uInt8 c;
3590 407 : return pSt->Read( &c, 1 );
3591 : }
3592 3935 : return 0;
3593 : }
3594 :
3595 0 : static inline short WW8SkipEven(SvStream* pSt )
3596 : {
3597 0 : if (!(pSt->Tell() & 0x1))
3598 : {
3599 : sal_uInt8 c;
3600 0 : return pSt->Read( &c, 1 );
3601 : }
3602 0 : return 0;
3603 : }
3604 :
3605 2689 : short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3606 : {
3607 2689 : if( 0 < nLen ) // Empty ?
3608 : {
3609 2689 : if (bOdd)
3610 0 : nLen = nLen - WW8SkipEven( pStStrm );
3611 : else
3612 2689 : nLen = nLen - WW8SkipOdd( pStStrm );
3613 :
3614 2689 : sal_Int16 cbUPX(0);
3615 2689 : pStStrm->ReadInt16( cbUPX );
3616 :
3617 2689 : nLen-=2;
3618 :
3619 2689 : if ( cbUPX > nLen )
3620 0 : cbUPX = nLen; // shrink cbUPX to nLen
3621 :
3622 2689 : if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3623 : {
3624 2098 : if( bPAP )
3625 : {
3626 : sal_uInt16 id;
3627 1036 : pStStrm->ReadUInt16( id );
3628 :
3629 1036 : cbUPX-= 2;
3630 1036 : nLen-= 2;
3631 : }
3632 :
3633 2098 : if( 0 < cbUPX )
3634 : {
3635 1937 : sal_Size nPos = pStStrm->Tell(); // if something is interpreted wrong,
3636 : // this should make it work again
3637 1937 : ImportSprms( nPos, cbUPX, bPAP );
3638 :
3639 1937 : if ( pStStrm->Tell() != nPos + cbUPX )
3640 0 : pStStrm->Seek( nPos+cbUPX );
3641 :
3642 1937 : nLen = nLen - cbUPX;
3643 : }
3644 : }
3645 : }
3646 2689 : return nLen;
3647 : }
3648 :
3649 1653 : void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3650 : {
3651 1653 : if( nLen <= 0 )
3652 1653 : return;
3653 1653 : if (bOdd)
3654 0 : nLen = nLen - WW8SkipEven( pStStrm );
3655 : else
3656 1653 : nLen = nLen - WW8SkipOdd( pStStrm );
3657 :
3658 1653 : if( bPara ) // Grupx.Papx
3659 1036 : nLen = ImportUPX(nLen, true, bOdd);
3660 1653 : ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3661 : }
3662 :
3663 125 : WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI)
3664 : : WW8Style(*pI->m_pTableStream, _rFib)
3665 : , maSprmParser(_rFib.GetFIBVersion())
3666 : , pIo(pI)
3667 : , pStStrm(pI->m_pTableStream)
3668 : , pStyRule(0)
3669 : , pParaSprms(0)
3670 : , nSprmsLen(0)
3671 : , nWwNumLevel(0)
3672 : , bTextColChanged(false)
3673 : , bFontChanged(false)
3674 : , bCJKFontChanged(false)
3675 : , bCTLFontChanged(false)
3676 : , bFSizeChanged(false)
3677 : , bFCTLSizeChanged(false)
3678 125 : , bWidowsChanged(false)
3679 : {
3680 125 : pIo->m_vColl.resize(cstd);
3681 125 : }
3682 :
3683 155 : void WW8RStyle::Set1StyleDefaults()
3684 : {
3685 : // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3686 155 : if (!bCJKFontChanged) // Style no CJK Font? set the default
3687 93 : pIo->SetNewFontAttr(ftcFE, true, RES_CHRATR_CJK_FONT);
3688 :
3689 155 : if (!bCTLFontChanged) // Style no CTL Font? set the default
3690 79 : pIo->SetNewFontAttr(ftcBi, true, RES_CHRATR_CTL_FONT);
3691 :
3692 : // western 2nd to make western charset conversion the default
3693 155 : if (!bFontChanged) // Style has no Font? set the default,
3694 79 : pIo->SetNewFontAttr(ftcAsci, true, RES_CHRATR_FONT);
3695 :
3696 155 : if( !pIo->m_bNoAttrImport )
3697 : {
3698 : // Style has no text color set, winword default is auto
3699 155 : if ( !bTextColChanged )
3700 94 : pIo->m_pAktColl->SetFormatAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR));
3701 :
3702 : // Style has no FontSize ? WinWord Default is 10pt for western and asian
3703 155 : if( !bFSizeChanged )
3704 : {
3705 11 : SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3706 11 : pIo->m_pAktColl->SetFormatAttr(aAttr);
3707 11 : aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3708 11 : pIo->m_pAktColl->SetFormatAttr(aAttr);
3709 : }
3710 :
3711 : // Style has no FontSize ? WinWord Default is 10pt for western and asian
3712 155 : if( !bFCTLSizeChanged )
3713 : {
3714 29 : SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3715 29 : aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3716 29 : pIo->m_pAktColl->SetFormatAttr(aAttr);
3717 : }
3718 :
3719 155 : if( !bWidowsChanged ) // Widows ?
3720 : {
3721 84 : pIo->m_pAktColl->SetFormatAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) );
3722 84 : pIo->m_pAktColl->SetFormatAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) );
3723 : }
3724 : }
3725 155 : }
3726 :
3727 1670 : bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3728 : {
3729 : SwFormat* pColl;
3730 : bool bStyExist;
3731 :
3732 1670 : if (rSI.bColl)
3733 : {
3734 : // Para-Style
3735 : sw::util::ParaStyleMapper::StyleResult aResult =
3736 1052 : pIo->m_aParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3737 1052 : pColl = aResult.first;
3738 1052 : bStyExist = aResult.second;
3739 : }
3740 : else
3741 : {
3742 : // Char-Style
3743 : sw::util::CharStyleMapper::StyleResult aResult =
3744 618 : pIo->m_aCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3745 618 : pColl = aResult.first;
3746 618 : bStyExist = aResult.second;
3747 : }
3748 :
3749 1670 : bool bImport = !bStyExist || pIo->m_bNewDoc; // import content ?
3750 :
3751 : // Do not override character styles the list import code created earlier.
3752 1670 : if (bImport && bStyExist && rSI.GetOrgWWName().startsWith("WW8Num"))
3753 139 : bImport = false;
3754 :
3755 1670 : bool bOldNoImp = pIo->m_bNoAttrImport;
3756 1670 : rSI.bImportSkipped = !bImport;
3757 :
3758 1670 : if( !bImport )
3759 139 : pIo->m_bNoAttrImport = true;
3760 : else
3761 : {
3762 1531 : if (bStyExist)
3763 : {
3764 794 : pColl->ResetAllFormatAttr(); // #i73790# - method renamed
3765 : }
3766 1531 : pColl->SetAuto(false); // suggested by JP
3767 : } // but changes the UI
3768 1670 : pIo->m_pAktColl = pColl;
3769 1670 : rSI.pFormat = pColl; // remember translation WW->SW
3770 1670 : rSI.bImportSkipped = !bImport;
3771 :
3772 : // Set Based on style
3773 1670 : sal_uInt16 j = rSI.nBase;
3774 1670 : if (j != nThisStyle && j < cstd )
3775 : {
3776 978 : SwWW8StyInf* pj = &pIo->m_vColl[j];
3777 978 : if (rSI.pFormat && pj->pFormat && rSI.bColl == pj->bColl)
3778 : {
3779 961 : rSI.pFormat->SetDerivedFrom( pj->pFormat ); // ok, set Based on
3780 961 : rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet;
3781 961 : rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet;
3782 961 : rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet;
3783 961 : rSI.n81Flags = pj->n81Flags;
3784 961 : rSI.n81BiDiFlags = pj->n81BiDiFlags;
3785 961 : if (!rSI.IsWW8BuiltInHeadingStyle())
3786 : {
3787 852 : rSI.mnWW8OutlineLevel = pj->mnWW8OutlineLevel;
3788 : }
3789 961 : rSI.bParaAutoBefore = pj->bParaAutoBefore;
3790 961 : rSI.bParaAutoAfter = pj->bParaAutoAfter;
3791 :
3792 961 : if (pj->pWWFly)
3793 0 : rSI.pWWFly = new WW8FlyPara(pIo->m_bVer67, pj->pWWFly);
3794 978 : }
3795 : }
3796 692 : else if( pIo->m_bNewDoc && bStyExist )
3797 305 : rSI.pFormat->SetDerivedFrom(0);
3798 :
3799 1670 : rSI.nFollow = nNextStyle; // remember Follow
3800 :
3801 1670 : pStyRule = 0; // recreate if necessary
3802 : bTextColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged =
3803 1670 : bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false;
3804 1670 : pIo->SetNAktColl( nThisStyle );
3805 1670 : pIo->m_bStyNormal = nThisStyle == 0;
3806 1670 : return bOldNoImp;
3807 : }
3808 :
3809 1670 : void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp)
3810 : {
3811 : // Reset attribute flags, because there are no style-ends.
3812 :
3813 1670 : pIo->m_bHasBorder = pIo->m_bSpec = pIo->m_bObj = pIo->m_bSymbol = false;
3814 1670 : pIo->m_nCharFormat = -1;
3815 :
3816 : // If Style basiert auf Nichts oder Basis ignoriert
3817 1670 : if ((rSI.nBase >= cstd || pIo->m_vColl[rSI.nBase].bImportSkipped) && rSI.bColl)
3818 : {
3819 : // If Char-Styles does not work
3820 : // -> set hard WW-Defaults
3821 155 : Set1StyleDefaults();
3822 : }
3823 :
3824 1670 : pStyRule = 0; // to be on the safe side
3825 1670 : pIo->m_bStyNormal = false;
3826 1670 : pIo->SetNAktColl( 0 );
3827 1670 : pIo->m_bNoAttrImport = bOldNoImp;
3828 : // reset the list-remember-fields, if used when reading styles
3829 1670 : pIo->m_nLFOPosition = USHRT_MAX;
3830 1670 : pIo->m_nListLevel = WW8ListManager::nMaxLevel;
3831 1670 : }
3832 :
3833 1802 : void WW8RStyle::Import1Style( sal_uInt16 nNr )
3834 : {
3835 1802 : if (nNr >= pIo->m_vColl.size())
3836 149 : return;
3837 :
3838 1802 : SwWW8StyInf &rSI = pIo->m_vColl[nNr];
3839 :
3840 1802 : if( rSI.bImported || !rSI.bValid )
3841 13 : return;
3842 :
3843 1789 : rSI.bImported = true; // set flag now to avoid endless loops
3844 :
3845 : // valid and not NUL and not yet imported
3846 :
3847 1789 : if( rSI.nBase < cstd && !pIo->m_vColl[rSI.nBase].bImported )
3848 13 : Import1Style( rSI.nBase );
3849 :
3850 1789 : pStStrm->Seek( rSI.nFilePos );
3851 :
3852 : short nSkip, cbStd;
3853 1789 : OUString sName;
3854 :
3855 3442 : boost::scoped_ptr<WW8_STD> xStd(Read1Style(nSkip, &sName, &cbStd));// read Style
3856 :
3857 1789 : if (xStd)
3858 1789 : rSI.SetOrgWWIdent( sName, xStd->sti );
3859 :
3860 : // either no Name or unused Slot or unknown Style
3861 :
3862 1789 : if ( !xStd || sName.isEmpty() || ((1 != xStd->sgc) && (2 != xStd->sgc)) )
3863 : {
3864 136 : pStStrm->SeekRel( nSkip );
3865 136 : return;
3866 : }
3867 :
3868 1653 : bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(xStd->sti), nNr, xStd->istdNext);
3869 :
3870 : // if something is interpreted wrong, this should make it work again
3871 1653 : long nPos = pStStrm->Tell();
3872 :
3873 : //Variable parts of the STD start at even byte offsets, but "inside
3874 : //the STD", which I take to meaning even in relation to the starting
3875 : //position of the STD, which matches findings in #89439#, generally it
3876 : //doesn't matter as the STSHI starts off nearly always on an even
3877 : //offset
3878 :
3879 : //Import of the Style Contents
3880 1653 : ImportGrupx(nSkip, xStd->sgc == 1, rSI.nFilePos & 1);
3881 :
3882 1653 : PostStyle(rSI, bOldNoImp);
3883 :
3884 3306 : pStStrm->Seek( nPos+nSkip );
3885 : }
3886 :
3887 1822 : void WW8RStyle::RecursiveReg(sal_uInt16 nNr)
3888 : {
3889 1822 : if (nNr >= pIo->m_vColl.size())
3890 0 : return;
3891 :
3892 1822 : SwWW8StyInf &rSI = pIo->m_vColl[nNr];
3893 1822 : if( rSI.bImported || !rSI.bValid )
3894 16 : return;
3895 :
3896 1806 : rSI.bImported = true;
3897 :
3898 1806 : if( rSI.nBase < cstd && !pIo->m_vColl[rSI.nBase].bImported )
3899 16 : RecursiveReg(rSI.nBase);
3900 :
3901 1806 : pIo->RegisterNumFormatOnStyle(nNr);
3902 :
3903 : }
3904 :
3905 : /*
3906 : After all styles are imported then we can recursively apply numbering
3907 : styles to them, and change their tab stop settings if they turned out
3908 : to have special first line indentation.
3909 : */
3910 125 : void WW8RStyle::PostProcessStyles()
3911 : {
3912 : sal_uInt16 i;
3913 : /*
3914 : Clear all imported flags so that we can recursively apply numbering
3915 : formats and use it to mark handled ones
3916 : */
3917 3825 : for (i=0; i < cstd; ++i)
3918 3700 : pIo->m_vColl[i].bImported = false;
3919 :
3920 : /*
3921 : Register the num formats and tabstop changes on the styles recursively.
3922 : */
3923 :
3924 : /*
3925 : In the same loop apply the tabstop changes required because we need to
3926 : change their location if theres a special indentation for the first line,
3927 : By avoiding making use of each styles margins during reading of their
3928 : tabstops we don't get problems with doubly adjusting tabstops that
3929 : are inheritied.
3930 : */
3931 3825 : for (i=0; i < cstd; ++i)
3932 : {
3933 3700 : if (pIo->m_vColl[i].bValid)
3934 : {
3935 1806 : RecursiveReg(i);
3936 : }
3937 : }
3938 125 : }
3939 :
3940 123 : void WW8RStyle::ScanStyles() // investigate style dependencies
3941 : { // and detect Filepos for each Style
3942 3311 : for (sal_uInt16 i = 0; i < cstd; ++i)
3943 : {
3944 : short nSkip;
3945 3188 : SwWW8StyInf &rSI = pIo->m_vColl[i];
3946 :
3947 3188 : rSI.nFilePos = pStStrm->Tell(); // remember FilePos
3948 3188 : WW8_STD* pStd = Read1Style( nSkip, 0, 0 ); // read STD
3949 3188 : rSI.bValid = (0 != pStd);
3950 3188 : if (rSI.bValid)
3951 : {
3952 1789 : rSI.nBase = pStd->istdBase; // remember Basis
3953 1789 : rSI.bColl = ( pStd->sgc == 1 ); // Para-Style
3954 : }
3955 : else
3956 1399 : rSI = SwWW8StyInf();
3957 :
3958 3188 : delete pStd;
3959 3188 : pStStrm->SeekRel( nSkip ); // skip Names and Sprms
3960 : }
3961 123 : }
3962 :
3963 93 : std::vector<sal_uInt8> ChpxToSprms(const Word2CHPX &rChpx)
3964 : {
3965 93 : std::vector<sal_uInt8> aRet;
3966 :
3967 93 : aRet.push_back(60);
3968 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBold) );
3969 :
3970 93 : aRet.push_back(61);
3971 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalic) );
3972 :
3973 93 : aRet.push_back(62);
3974 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fStrike) );
3975 :
3976 93 : aRet.push_back(63);
3977 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fOutline) );
3978 :
3979 93 : aRet.push_back(65);
3980 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fSmallCaps) );
3981 :
3982 93 : aRet.push_back(66);
3983 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fCaps) );
3984 :
3985 93 : aRet.push_back(67);
3986 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fVanish) );
3987 :
3988 93 : if (rChpx.fsFtc)
3989 : {
3990 86 : aRet.push_back(68);
3991 : SVBT16 a;
3992 86 : ShortToSVBT16(rChpx.ftc, a);
3993 86 : aRet.push_back(a[1]);
3994 86 : aRet.push_back(a[0]);
3995 : }
3996 :
3997 93 : if (rChpx.fsKul)
3998 : {
3999 6 : aRet.push_back(69);
4000 6 : aRet.push_back(rChpx.kul);
4001 : }
4002 :
4003 93 : if (rChpx.fsLid)
4004 : {
4005 1 : aRet.push_back(72);
4006 : SVBT16 a;
4007 1 : ShortToSVBT16(rChpx.lid, a);
4008 1 : aRet.push_back(a[1]);
4009 1 : aRet.push_back(a[0]);
4010 : }
4011 :
4012 93 : if (rChpx.fsIco)
4013 : {
4014 6 : aRet.push_back(73);
4015 6 : aRet.push_back(rChpx.ico);
4016 : }
4017 :
4018 93 : if (rChpx.fsHps)
4019 : {
4020 86 : aRet.push_back(74);
4021 :
4022 : SVBT16 a;
4023 86 : ShortToSVBT16(rChpx.hps, a);
4024 86 : aRet.push_back(a[0]);
4025 : }
4026 :
4027 93 : if (rChpx.fsPos)
4028 : {
4029 0 : aRet.push_back(76);
4030 0 : aRet.push_back(rChpx.hpsPos);
4031 : }
4032 :
4033 93 : aRet.push_back(80);
4034 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBoldBi) );
4035 :
4036 93 : aRet.push_back(81);
4037 93 : aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalicBi) );
4038 :
4039 93 : if (rChpx.fsFtcBi)
4040 : {
4041 0 : aRet.push_back(82);
4042 : SVBT16 a;
4043 0 : ShortToSVBT16(rChpx.fsFtcBi, a);
4044 0 : aRet.push_back(a[1]);
4045 0 : aRet.push_back(a[0]);
4046 : }
4047 :
4048 93 : if (rChpx.fsLidBi)
4049 : {
4050 0 : aRet.push_back(83);
4051 : SVBT16 a;
4052 0 : ShortToSVBT16(rChpx.lidBi, a);
4053 0 : aRet.push_back(a[1]);
4054 0 : aRet.push_back(a[0]);
4055 : }
4056 :
4057 93 : if (rChpx.fsIcoBi)
4058 : {
4059 0 : aRet.push_back(84);
4060 0 : aRet.push_back(rChpx.icoBi);
4061 : }
4062 :
4063 93 : if (rChpx.fsHpsBi)
4064 : {
4065 0 : aRet.push_back(85);
4066 : SVBT16 a;
4067 0 : ShortToSVBT16(rChpx.hpsBi, a);
4068 0 : aRet.push_back(a[1]);
4069 0 : aRet.push_back(a[0]);
4070 : }
4071 :
4072 93 : return aRet;
4073 : }
4074 :
4075 93 : Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize)
4076 : {
4077 93 : Word2CHPX aChpx;
4078 :
4079 93 : if (!nSize)
4080 1 : return aChpx;
4081 :
4082 92 : rSt.Seek(nOffset);
4083 :
4084 92 : sal_uInt8 nCount=0;
4085 :
4086 : while (true)
4087 : {
4088 : sal_uInt8 nFlags8;
4089 92 : rSt.ReadUChar( nFlags8 );
4090 92 : nCount++;
4091 :
4092 92 : aChpx.fBold = nFlags8 & 0x01;
4093 92 : aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4094 92 : aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4095 92 : aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4096 92 : aChpx.fFieldVanish = (nFlags8 & 0x10) >> 4;
4097 92 : aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4098 92 : aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4099 92 : aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4100 :
4101 92 : if (nCount >= nSize) break;
4102 92 : rSt.ReadUChar( nFlags8 );
4103 92 : nCount++;
4104 :
4105 92 : aChpx.fRMark = nFlags8 & 0x01;
4106 92 : aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4107 92 : aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4108 92 : aChpx.fObj = (nFlags8 & 0x08) >> 3;
4109 92 : aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4110 92 : aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4111 92 : aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4112 92 : aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4113 :
4114 92 : if (nCount >= nSize) break;
4115 92 : rSt.ReadUChar( nFlags8 );
4116 92 : nCount++;
4117 :
4118 92 : aChpx.fsIco = nFlags8 & 0x01;
4119 92 : aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4120 92 : aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4121 92 : aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4122 92 : aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4123 92 : aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4124 92 : aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4125 92 : aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4126 :
4127 92 : if (nCount >= nSize) break;
4128 92 : rSt.ReadUChar( nFlags8 );
4129 92 : nCount++;
4130 :
4131 92 : aChpx.fsFtcBi = nFlags8 & 0x01;
4132 92 : aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4133 92 : aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4134 :
4135 92 : if (nCount >= nSize) break;
4136 92 : rSt.ReadUInt16( aChpx.ftc );
4137 92 : nCount+=2;
4138 :
4139 92 : if (nCount >= nSize) break;
4140 88 : rSt.ReadUInt16( aChpx.hps );
4141 88 : nCount+=2;
4142 :
4143 88 : if (nCount >= nSize) break;
4144 9 : rSt.ReadUChar( nFlags8 );
4145 9 : nCount++;
4146 :
4147 9 : aChpx.qpsSpace = nFlags8 & 0x3F;
4148 9 : aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4149 9 : aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4150 :
4151 9 : if (nCount >= nSize) break;
4152 9 : rSt.ReadUChar( nFlags8 );
4153 9 : nCount++;
4154 :
4155 9 : aChpx.ico = nFlags8 & 0x1F;
4156 9 : aChpx.kul = (nFlags8 & 0xE0) >> 5;
4157 :
4158 9 : if (nCount >= nSize) break;
4159 3 : rSt.ReadUChar( aChpx.hpsPos );
4160 3 : nCount++;
4161 :
4162 3 : if (nCount >= nSize) break;
4163 3 : rSt.ReadUChar( aChpx.icoBi );
4164 3 : nCount++;
4165 :
4166 3 : if (nCount >= nSize) break;
4167 3 : rSt.ReadUInt16( aChpx.lid );
4168 3 : nCount+=2;
4169 :
4170 3 : if (nCount >= nSize) break;
4171 1 : rSt.ReadUInt16( aChpx.ftcBi );
4172 1 : nCount+=2;
4173 :
4174 1 : if (nCount >= nSize) break;
4175 1 : rSt.ReadUInt16( aChpx.hpsBi );
4176 1 : nCount+=2;
4177 :
4178 1 : if (nCount >= nSize) break;
4179 0 : rSt.ReadUInt16( aChpx.lidBi );
4180 0 : nCount+=2;
4181 :
4182 0 : if (nCount >= nSize) break;
4183 0 : rSt.ReadUInt32( aChpx.fcPic );
4184 0 : nCount+=4;
4185 :
4186 0 : break;
4187 : }
4188 :
4189 92 : rSt.SeekRel(nSize-nCount);
4190 92 : return aChpx;
4191 : }
4192 :
4193 : namespace
4194 : {
4195 : struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; };
4196 : }
4197 :
4198 2 : void WW8RStyle::ImportOldFormatStyles()
4199 : {
4200 514 : for (sal_uInt16 i=0; i < cstd; ++i)
4201 : {
4202 512 : pIo->m_vColl[i].bColl = true;
4203 : //every chain must end eventually at the null style (style code 222)
4204 512 : pIo->m_vColl[i].nBase = 222;
4205 : }
4206 :
4207 : rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4208 2 : pIo->m_pWwFib->chseTables, pIo->m_pWwFib->lid);
4209 :
4210 2 : sal_uInt16 cstcStd(0);
4211 2 : rSt.ReadUInt16( cstcStd );
4212 :
4213 2 : size_t nMaxByteCount = rSt.remainingSize();
4214 2 : sal_uInt16 cbName(0);
4215 2 : rSt.ReadUInt16(cbName);
4216 2 : if (cbName > nMaxByteCount)
4217 : {
4218 : SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4219 : << cbName << " to " << nMaxByteCount);
4220 0 : cbName = nMaxByteCount;
4221 : }
4222 2 : sal_uInt16 nByteCount = 2;
4223 2 : sal_uInt16 stcp=0;
4224 21 : while (nByteCount < cbName)
4225 : {
4226 17 : sal_uInt8 nCount(0);
4227 17 : rSt.ReadUChar( nCount );
4228 17 : nByteCount++;
4229 :
4230 17 : sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4231 17 : if (stc >=pIo->m_vColl.size())
4232 0 : continue;
4233 :
4234 17 : SwWW8StyInf &rSI = pIo->m_vColl[stc];
4235 17 : OUString sName;
4236 :
4237 17 : if (nCount != 0xFF) // undefined style
4238 : {
4239 4 : if (nCount != 0) // user style
4240 : {
4241 0 : OString aTmp = read_uInt8s_ToOString(rSt, nCount);
4242 0 : nByteCount += aTmp.getLength();
4243 0 : sName = OStringToOUString(aTmp, eStructChrSet);
4244 : }
4245 4 : rSI.bImported = true;
4246 : }
4247 :
4248 17 : if (sName.isEmpty())
4249 : {
4250 17 : ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4251 17 : if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4252 16 : sName = OUString(pStr, strlen(pStr), RTL_TEXTENCODING_ASCII_US);
4253 : }
4254 :
4255 17 : if (sName.isEmpty())
4256 1 : sName = "Unknown Style: " + OUString::number(stc);
4257 :
4258 17 : rSI.SetOrgWWIdent(sName, stc);
4259 17 : stcp++;
4260 17 : }
4261 :
4262 2 : sal_uInt16 nStyles=stcp;
4263 :
4264 2 : std::vector<pxoffset> aCHPXOffsets(stcp);
4265 2 : nMaxByteCount = rSt.remainingSize();
4266 2 : sal_uInt16 cbChpx(0);
4267 2 : rSt.ReadUInt16(cbChpx);
4268 2 : if (cbChpx > nMaxByteCount)
4269 : {
4270 : SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4271 : << cbChpx << " to " << nMaxByteCount);
4272 0 : cbChpx = nMaxByteCount;
4273 : }
4274 2 : nByteCount = 2;
4275 2 : stcp=0;
4276 4 : std::vector< std::vector<sal_uInt8> > aConvertedChpx;
4277 21 : while (nByteCount < cbChpx)
4278 : {
4279 17 : sal_uInt8 cb(0);
4280 17 : rSt.ReadUChar( cb );
4281 17 : nByteCount++;
4282 :
4283 17 : aCHPXOffsets[stcp].mnSize = 0;
4284 :
4285 17 : if (cb != 0xFF)
4286 : {
4287 2 : sal_uInt8 nRemainder = cb;
4288 :
4289 2 : aCHPXOffsets[stcp].mnOffset = rSt.Tell();
4290 2 : aCHPXOffsets[stcp].mnSize = nRemainder;
4291 :
4292 2 : Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets[stcp].mnOffset,
4293 4 : aCHPXOffsets[stcp].mnSize);
4294 2 : aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4295 :
4296 2 : nByteCount += nRemainder;
4297 : }
4298 : else
4299 15 : aConvertedChpx.push_back( std::vector<sal_uInt8>() );
4300 :
4301 17 : stcp++;
4302 17 : if (stcp == nStyles)
4303 : {
4304 2 : rSt.SeekRel(cbChpx-nByteCount);
4305 2 : nByteCount += cbChpx-nByteCount;
4306 : }
4307 : }
4308 :
4309 4 : std::vector<pxoffset> aPAPXOffsets(stcp);
4310 2 : nMaxByteCount = rSt.remainingSize();
4311 2 : sal_uInt16 cbPapx(0);
4312 2 : rSt.ReadUInt16(cbPapx);
4313 2 : if (cbPapx > nMaxByteCount)
4314 : {
4315 : SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4316 : << cbPapx << " to " << nMaxByteCount);
4317 0 : cbPapx = nMaxByteCount;
4318 : }
4319 2 : nByteCount = 2;
4320 2 : stcp=0;
4321 21 : while (nByteCount < cbPapx)
4322 : {
4323 17 : sal_uInt8 cb(0);
4324 17 : rSt.ReadUChar( cb );
4325 17 : nByteCount++;
4326 :
4327 17 : aPAPXOffsets[stcp].mnSize = 0;
4328 :
4329 17 : if (cb != 0xFF)
4330 : {
4331 2 : sal_uInt8 stc2(0);
4332 2 : rSt.ReadUChar( stc2 );
4333 2 : rSt.SeekRel(6);
4334 2 : nByteCount+=7;
4335 2 : sal_uInt8 nRemainder = cb-7;
4336 :
4337 2 : aPAPXOffsets[stcp].mnOffset = rSt.Tell();
4338 2 : aPAPXOffsets[stcp].mnSize = nRemainder;
4339 :
4340 2 : rSt.SeekRel(nRemainder);
4341 2 : nByteCount += nRemainder;
4342 : }
4343 :
4344 17 : stcp++;
4345 :
4346 17 : if (stcp == nStyles)
4347 : {
4348 2 : rSt.SeekRel(cbPapx-nByteCount);
4349 2 : nByteCount += cbPapx-nByteCount;
4350 : }
4351 : }
4352 :
4353 2 : sal_uInt16 iMac(0);
4354 2 : rSt.ReadUInt16( iMac );
4355 :
4356 2 : if (iMac > nStyles) iMac = nStyles;
4357 :
4358 19 : for (stcp = 0; stcp < iMac; ++stcp)
4359 : {
4360 17 : sal_uInt8 stcNext(0), stcBase(0);
4361 17 : rSt.ReadUChar( stcNext );
4362 17 : rSt.ReadUChar( stcBase );
4363 :
4364 17 : sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4365 :
4366 : /*
4367 : #i64557# style based on itself
4368 : every chain must end eventually at the null style (style code 222)
4369 : */
4370 17 : if (stc == stcBase)
4371 1 : stcBase = 222;
4372 :
4373 17 : SwWW8StyInf &rSI = pIo->m_vColl[stc];
4374 17 : rSI.nBase = stcBase;
4375 :
4376 17 : ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4377 :
4378 17 : if (eSti == ww::stiNil)
4379 0 : continue;
4380 :
4381 17 : rSI.bValid = true;
4382 :
4383 17 : if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4384 1 : pIo->m_vColl[stc].bColl = false;
4385 :
4386 17 : bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4387 :
4388 34 : ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4389 34 : true);
4390 :
4391 17 : if (aConvertedChpx[stcp].size() > 0)
4392 2 : ImportSprms(&(aConvertedChpx[stcp][0]),
4393 2 : static_cast< short >(aConvertedChpx[stcp].size()),
4394 4 : false);
4395 :
4396 17 : PostStyle(rSI, bOldNoImp);
4397 2 : }
4398 2 : }
4399 :
4400 123 : void WW8RStyle::ImportNewFormatStyles()
4401 : {
4402 123 : ScanStyles(); // Scan Based On
4403 :
4404 3311 : for (sal_uInt16 i = 0; i < cstd; ++i) // import Styles
4405 3188 : if (pIo->m_vColl[i].bValid)
4406 1789 : Import1Style( i );
4407 123 : }
4408 :
4409 125 : void WW8RStyle::ImportStyles()
4410 : {
4411 125 : if (pIo->m_pWwFib->GetFIBVersion() <= ww::eWW2)
4412 2 : ImportOldFormatStyles();
4413 : else
4414 123 : ImportNewFormatStyles();
4415 125 : }
4416 :
4417 125 : void WW8RStyle::Import()
4418 : {
4419 125 : pIo->m_pDfltTextFormatColl = pIo->m_rDoc.GetDfltTextFormatColl();
4420 : pIo->m_pStandardFormatColl =
4421 125 : pIo->m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, false);
4422 :
4423 125 : if( pIo->m_nIniFlags & WW8FL_NO_STYLES )
4424 125 : return;
4425 :
4426 125 : ImportStyles();
4427 :
4428 3825 : for (sal_uInt16 i = 0; i < cstd; ++i)
4429 : {
4430 : // Follow chain
4431 3700 : SwWW8StyInf* pi = &pIo->m_vColl[i];
4432 3700 : sal_uInt16 j = pi->nFollow;
4433 3700 : if( j < cstd )
4434 : {
4435 3700 : SwWW8StyInf* pj = &pIo->m_vColl[j];
4436 3700 : if ( j != i // rational Index ?
4437 2269 : && pi->pFormat // Format ok ?
4438 239 : && pj->pFormat // Derived-Format ok ?
4439 238 : && pi->bColl // only possible for paragraph templates (WW)
4440 237 : && pj->bColl ){ // identical Typ ?
4441 : static_cast<SwTextFormatColl*>(pi->pFormat)->SetNextTextFormatColl(
4442 237 : *static_cast<SwTextFormatColl*>(pj->pFormat) ); // ok, register
4443 : }
4444 : }
4445 : }
4446 :
4447 : // Missing special handling for default character template
4448 : // "Absatz-Standardschriftart" ( Style-ID 65 ).
4449 : // That is empty by default ( WW6 dt and US ) and not changeable
4450 : // via WW-UI so this does not matter.
4451 : // This could be done by:
4452 : // if( bNew ) rDoc.SetDefault( pDefCharFormat->GetAttrSet() );
4453 :
4454 : // for e.g. tables an always valid Std-Style is necessary
4455 :
4456 500 : if( pIo->StyleExists(0) && !pIo->m_vColl.empty() &&
4457 375 : pIo->m_vColl[0].pFormat && pIo->m_vColl[0].bColl && pIo->m_vColl[0].bValid )
4458 125 : pIo->m_pDfltTextFormatColl = static_cast<SwTextFormatColl*>(pIo->m_vColl[0].pFormat);
4459 : else
4460 0 : pIo->m_pDfltTextFormatColl = pIo->m_rDoc.GetDfltTextFormatColl();
4461 :
4462 : // set Hyphenation flag on BASIC para-style
4463 125 : if (pIo->m_bNewDoc && pIo->m_pStandardFormatColl)
4464 : {
4465 125 : if (pIo->m_pWDop->fAutoHyphen
4466 125 : && SfxItemState::SET != pIo->m_pStandardFormatColl->GetItemState(
4467 0 : RES_PARATR_HYPHENZONE, false) )
4468 : {
4469 0 : SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE);
4470 0 : aAttr.GetMinLead() = 2;
4471 0 : aAttr.GetMinTrail() = 2;
4472 0 : aAttr.GetMaxHyphens() = 0;
4473 :
4474 0 : pIo->m_pStandardFormatColl->SetFormatAttr( aAttr );
4475 : }
4476 :
4477 : /*
4478 : Word defaults to ltr not from environment like writer. Regardless of
4479 : the page/sections rtl setting the standard style lack of rtl still
4480 : means ltr
4481 : */
4482 125 : if (SfxItemState::SET != pIo->m_pStandardFormatColl->GetItemState(RES_FRAMEDIR,
4483 125 : false))
4484 : {
4485 : pIo->m_pStandardFormatColl->SetFormatAttr(
4486 82 : SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR));
4487 : }
4488 : }
4489 :
4490 : // we do not read styles anymore:
4491 125 : pIo->m_pAktColl = 0;
4492 : }
4493 :
4494 351 : rtl_TextEncoding SwWW8StyInf::GetCharSet() const
4495 : {
4496 351 : if ((pFormat) && (pFormat->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4497 0 : return eRTLFontSrcCharSet;
4498 351 : return eLTRFontSrcCharSet;
4499 : }
4500 :
4501 311 : rtl_TextEncoding SwWW8StyInf::GetCJKCharSet() const
4502 : {
4503 311 : if ((pFormat) && (pFormat->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4504 0 : return eRTLFontSrcCharSet;
4505 311 : return eCJKFontSrcCharSet;
4506 60 : }
4507 :
4508 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|