xref: /AOO42X/main/sw/source/filter/rtf/rtffly.cxx (revision b1c5455db1639c48e26c568e4fa7ee78ca5d60ee)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_sw.hxx"
24 
25 #include <hintids.hxx>
26 #include <tools/list.hxx>
27 #include <tools/cachestr.hxx>
28 #include <svtools/rtftoken.h>
29 #include <svl/itemiter.hxx>
30 #include <editeng/prntitem.hxx>
31 #include <editeng/opaqitem.hxx>
32 #include <editeng/protitem.hxx>
33 #include <editeng/ulspitem.hxx>
34 #include <editeng/lrspitem.hxx>
35 #include <editeng/boxitem.hxx>
36 #include <editeng/frmdiritem.hxx>
37 #include <fmtfsize.hxx>
38 #include <fmtanchr.hxx>
39 #include <fmtpdsc.hxx>
40 #include <fmtsrnd.hxx>
41 #include <fmtclds.hxx>
42 #include <fmtcntnt.hxx>
43 #include <frmatr.hxx>
44 #include <doc.hxx>
45 #include <pam.hxx>
46 #include <ndtxt.hxx>
47 #include <shellio.hxx>
48 #include <swparrtf.hxx>
49 #include <grfatr.hxx>
50 #include <paratr.hxx>
51 #include <rtf.hxx>
52 #include <ndgrf.hxx>
53 #include <pagedesc.hxx>
54 #include <swtable.hxx>
55 #include <txtflcnt.hxx>
56 #include <fmtflcnt.hxx>
57 #include <fltini.hxx>
58 #include <unoframe.hxx>
59 #include <deque>
60 #include <map>
61 #include <utility>
62 #include <fmtwrapinfluenceonobjpos.hxx>
63 #include <editeng/brshitem.hxx>
64 #include <fmtfollowtextflow.hxx>
65 #include "dcontact.hxx"
66 #include <drawdoc.hxx>
67 
68 using namespace ::com::sun::star;
69 
70 #define ANCHOR(p)   ((SwFmtAnchor*)p)
71 
72 // steht in shellio.hxx
73 extern SwCntntNode* GoNextNds( SwNodeIndex * pIdx, sal_Bool bChk );
74 
SV_IMPL_PTRARR(SwFlySaveArr,SwFlySave *) const75 SV_IMPL_PTRARR( SwFlySaveArr, SwFlySave* )
76 
77 inline const SwFmtFrmSize GetFrmSize(const SfxItemSet& rSet, sal_Bool bInP=sal_True)
78 {
79     return (const SwFmtFrmSize&)rSet.Get(RES_FRM_SIZE,bInP);
80 }
81 
SwFlySave(const SwPaM & rPam,SfxItemSet & rSet)82 SwFlySave::SwFlySave(const SwPaM& rPam, SfxItemSet& rSet)
83     : aFlySet(rSet), nSttNd(rPam.GetPoint()->nNode), nEndNd(nSttNd), nEndCnt(0),
84      nPageWidth(ATT_MIN_SIZE), nDropLines(0), nDropAnchor(0)
85 {
86 }
87 
IsEqualFly(const SwPaM & rPos,SfxItemSet & rSet)88 int SwFlySave::IsEqualFly( const SwPaM& rPos, SfxItemSet& rSet )
89 {
90     if( rSet.Count() != aFlySet.Count() || nDropAnchor )
91         return sal_False;
92 
93     // nur TextNodes zusammenfassen
94     if( nSttNd == nEndNd && nEndNd.GetNode().IsNoTxtNode() )
95         return sal_False;
96 
97     // teste auf gleiche / naechste Position
98     if( rPos.GetPoint()->nNode.GetIndex() == nEndNd.GetIndex() )
99     {
100         if( 1 < (rPos.GetPoint()->nContent.GetIndex() - nEndCnt) )
101             return sal_False;
102     }
103     else if( rPos.GetPoint()->nContent.GetIndex() )
104         return sal_False;
105     else
106     {
107         SwNodeIndex aIdx( nEndNd );
108         SwCntntNode *const pCNd = aIdx.GetNode().GetCntntNode();
109         if( !GoNextNds( &aIdx, sal_True ) ||
110             aIdx.GetIndex() != rPos.GetPoint()->nNode.GetIndex() ||
111             ( pCNd && pCNd->Len() != nEndCnt ))
112         {
113             return sal_False;
114         }
115     }
116 
117     if( rSet.Count() )
118     {
119         SfxItemIter aIter( rSet );
120         const SfxPoolItem *pItem, *pCurr = aIter.GetCurItem();
121         while( sal_True )
122         {
123             if( SFX_ITEM_SET != aFlySet.GetItemState( pCurr->Which(),
124                 sal_False, &pItem ) ||
125                 // Ankerattribute gesondert behandeln
126                 ( RES_ANCHOR == pCurr->Which()
127                     ? (ANCHOR(pCurr)->GetAnchorId() != ANCHOR(pItem)->GetAnchorId() ||
128                        ANCHOR(pCurr)->GetPageNum() != ANCHOR(pItem)->GetPageNum())
129                     : *pItem != *pCurr ))
130                         return sal_False;
131 
132             if( aIter.IsAtEnd() )
133                 break;
134             pCurr = aIter.NextItem();
135         }
136     }
137     return sal_True;
138 }
139 
SetFlySize(const SwTableNode & rTblNd)140 void SwFlySave::SetFlySize( const SwTableNode& rTblNd )
141 {
142     // sollte der Fly kleiner als diese Tabelle sein, dann
143     // korrigiere diesen (nur bei abs. Angaben!)
144     SwTwips nWidth = rTblNd.GetTable().GetFrmFmt()->GetFrmSize().GetWidth();
145     const SwFmtFrmSize& rSz = GetFrmSize( aFlySet );
146     if( nWidth > rSz.GetWidth() )
147         aFlySet.Put( SwFmtFrmSize( rSz.GetHeightSizeType(), nWidth, rSz.GetHeight() ));
148 }
149 
lcl_HasBreakAttrs(const SwCntntNode & rNd)150 sal_Bool lcl_HasBreakAttrs( const SwCntntNode& rNd )
151 {
152     sal_Bool bRet = sal_False;
153     const SfxItemSet& rSet = rNd.GetSwAttrSet();
154     const SfxPoolItem* pItem;
155     if( SFX_ITEM_SET == rSet.GetItemState( RES_BREAK, sal_True, &pItem ) &&
156         SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak() )
157         bRet = sal_True;
158     else if( SFX_ITEM_SET == rSet.GetItemState( RES_PAGEDESC, sal_True, &pItem )&&
159          0 != ((SwFmtPageDesc*)pItem)->GetPageDesc() )
160         bRet = sal_True;
161     return bRet;
162 }
163 
164 
lcl_CpyBreakAttrs(SwCntntNode * pSrcNd,SwCntntNode * pDstNd,SwNodeIndex * pNewIdx)165 void lcl_CpyBreakAttrs( SwCntntNode* pSrcNd, SwCntntNode* pDstNd,
166                         SwNodeIndex* pNewIdx )
167 {
168     const SfxItemSet* pSet;
169     if( pSrcNd && pDstNd && 0 != ( pSet = pSrcNd->GetpSwAttrSet() ) )
170     {
171         const SfxPoolItem *pDescItem, *pBreakItem;
172 
173         if( SFX_ITEM_SET != pSet->GetItemState( RES_BREAK,
174                                         sal_False, &pBreakItem ) )
175             pBreakItem = 0;
176 
177         if( SFX_ITEM_SET != pSet->GetItemState( RES_PAGEDESC,
178                                         sal_False, &pDescItem ) )
179             pDescItem = 0;
180 
181         if( pDescItem || pBreakItem )
182         {
183             if( lcl_HasBreakAttrs( *pDstNd ))
184             {
185                 SwPosition aPos( *pDstNd, SwIndex( pDstNd ));
186                 aPos.nNode--;
187                 pDstNd->GetDoc()->AppendTxtNode( aPos );
188                 if( pNewIdx )
189                     *pNewIdx = aPos.nNode;
190 
191                 SwCntntNode* pOldNd = pDstNd;
192                 pDstNd = aPos.nNode.GetNode().GetCntntNode();
193                 pDstNd->ChgFmtColl( pOldNd->GetFmtColl() );
194                 if( pDstNd->HasSwAttrSet() )
195                 {
196                     SfxItemSet aSet( *pDstNd->GetpSwAttrSet() );
197                     aSet.ClearItem( RES_BREAK );
198                     aSet.ClearItem( RES_PAGEDESC );
199                     pDstNd->SetAttr( aSet );
200                 }
201             }
202             if( pBreakItem )
203             {
204                 pDstNd->SetAttr( *pBreakItem );
205                 pSrcNd->ResetAttr( RES_BREAK );
206             }
207             if( pDescItem )
208             {
209                 pDstNd->SetAttr( *pDescItem );
210                 pSrcNd->ResetAttr( RES_PAGEDESC );
211             }
212         }
213     }
214 }
215 
SetFlysInDoc()216 void SwRTFParser::SetFlysInDoc()
217 {
218     // !! von Oben abarbeiten, CntntPos ist kein Index !
219     SwNodes & rNds = pDoc->GetNodes();
220     typedef std::pair<SwFlyFrmFmt*, SwFmtAnchor> frameEntry;
221     typedef std::deque<frameEntry> rtfframesAtIndex;
222     typedef std::map<const SwNode*, rtfframesAtIndex> rtfFmtMap;
223     rtfFmtMap aPrevFmts;
224 
225     SwFrmFmt* pParent = pDoc->GetFrmFmtFromPool( RES_POOLFRM_FRAME );
226     for( sal_uInt16 n = 0; n < aFlyArr.Count(); ++n )
227     {
228         SwFlySave* pFlySave = aFlyArr[ n ];
229 
230         ASSERT( !pFlySave->nSttNd.GetNode().FindFlyStartNode(),
231                 "Content vom Fly steht in einem Fly" );
232         ASSERT( pFlySave->nSttNd.GetIndex() <= pFlySave->nEndNd.GetIndex(),
233                 "Fly hat falschen Bereich" );
234 
235 
236 
237         //JP 21.09.98: wenn ein DropCap ist, dann Text im Node belassen, am
238         //              Absatz das Absatz Attribut setzen. Ggfs noch die
239         //              FontSize zuruecksetzen, damit das DropCap nicht zu
240         //              gro? wird.
241         if( pFlySave->nDropAnchor )
242         {
243             SwTxtNode* pSttNd = pFlySave->nSttNd.GetNode().GetTxtNode();
244             SwTxtNode* pEndNd = pFlySave->nEndNd.GetNode().GetTxtNode();
245             if( pSttNd && pEndNd &&
246                 pSttNd->GetIndex() + 1 == pEndNd->GetIndex()
247                 && pSttNd->GetTxt().Len()>0 /* #i38227# leave drop caps with no content as fly frames */ )
248             {
249                 sal_uLong nPos = pSttNd->GetIndex();
250                 SwDoc * pDoc1 = pSttNd->GetDoc();
251 
252                 sal_Bool bJoined;
253                 {
254                     SwPaM aTmp( *pSttNd, pSttNd->GetTxt().Len(), *pEndNd, 0 );
255                     bJoined = pDoc1->DeleteAndJoin( aTmp );
256                 }
257 
258                 SwTxtNode * pNd = (pDoc1->GetNodes()[nPos])->GetTxtNode();
259 
260                 if( bJoined && pNd != NULL)
261                 {
262                     SwFmtDrop aDropCap;
263                     aDropCap.GetLines() = (sal_uInt8)pFlySave->nDropLines;
264                     aDropCap.GetChars() = 1;
265 
266                     SwIndex aIdx( pEndNd );
267                     pNd->RstTxtAttr( aIdx, 1, RES_CHRATR_FONTSIZE );
268                     pNd->SetAttr( aDropCap );
269                 }
270                 delete pFlySave;
271                 continue;
272             }
273         }
274 
275         // liegt Ende und Start vom Naechsten im gleichen Node, dann muss
276         // gesplittet werden
277         if (((static_cast<size_t>(n) + 1) < aFlyArr.Count()) &&
278             pFlySave->nEndCnt &&
279             pFlySave->nEndNd == aFlyArr[ n + 1 ]->nSttNd )
280         {
281             SwCntntNode *const pCNd = pFlySave->nEndNd.GetNode().GetCntntNode();
282             if( pCNd )
283             {
284                 SwPosition aPos( pFlySave->nEndNd,
285                                 SwIndex( pCNd, pFlySave->nEndCnt ));
286                 pDoc->SplitNode( aPos, false );
287                 pFlySave->nEndNd--;
288             }
289             else
290                 pFlySave->nEndCnt = 0;
291         }
292 
293         // verschiebe den Inhalt von diesem Anchor in den Auto-TextBereich
294         // und erzeuge dadurch den richtigen SwG-Rahmen
295         SwNodeRange aRg(pFlySave->nSttNd, 0, pFlySave->nEndNd, 0);
296         //Make a new section, unless there is no content at all
297         const bool bMakeEmptySection = aRg.aStart < aRg.aEnd || ((aRg.aStart == aRg.aEnd) && pFlySave->nEndCnt);
298 
299         {
300             // Nur TextNodes koennen in Tabellen stehen !!
301             const SwNode* pNd = &pFlySave->nSttNd.GetNode();
302             if( pNd->IsNoTxtNode() )
303             {
304                 // die Size muss noch korrigiert werden!
305                 nAktPageDesc = 0;       // Standart PageDesc
306                 if( SFX_ITEM_SET != pFlySave->aFlySet.GetItemState(
307                     RES_FRM_SIZE, sal_False ) )
308                     _SetPictureSize( *(SwNoTxtNode*)pNd, aRg.aStart,
309                                     pFlySave->aFlySet );
310                 if( 0 != ( pNd = pNd->FindTableNode() ) )
311                     pFlySave->SetFlySize( *(SwTableNode*)pNd );
312             }
313             else
314             {
315                 // Take care for table nodes
316                 pNd = pNd->GetNodes()[ pNd->GetIndex() - 2 ]->GetTableNode();
317                 if( pNd ) // if the table starts immediately before aRg -> expand aRg
318                     aRg.aStart = *pNd;
319 
320                 if( bMakeEmptySection )
321                 {
322                     pNd = &aRg.aEnd.GetNode();
323                     sal_uLong nSectEnd = pNd->EndOfSectionIndex()+1;
324 
325                     if (!pNd->IsTableNode() && 0 !=(pNd = pNd->FindTableNode())
326                         && (pNd->GetIndex() >= aRg.aStart.GetNode().GetIndex()) )
327                     {
328                         const SwNode* pTblBxNd;
329 
330                         // Ende der Tabelle ist hinter dieser Box ??
331                         if( pNd->EndOfSectionIndex() == nSectEnd )
332                             aRg.aEnd = nSectEnd+1;
333                         // is the end in the first box of the table, then
334                         // move before the table (Bug 67663)
335                         // but the range must not become emtpy, i.e. aStart==aEnd
336                         // because otherwise we will get a crash (126506) later on
337                         else if( 0 != ( pTblBxNd = aRg.aEnd.GetNode().
338                                                 FindTableBoxStartNode()) &&
339                                  pTblBxNd->GetIndex() - 1 == pNd->GetIndex() &&
340                                  &aRg.aStart.GetNode() != pNd )
341                             aRg.aEnd = *pNd;
342                         else
343                         {
344                             // Tabelle ist noch groesser, also splitte sie hier.
345                             rNds.SplitTable( aRg.aEnd, sal_True );
346                             aRg.aEnd = pNd->EndOfSectionIndex() + 1;
347                         }
348                     }
349                 }
350             }
351         }
352 
353         // vorm verschieben muss sich der Index auf die alte Position
354         // gemerkt werden, der Index wird mit verschoben !!!
355 
356         SwNodeIndex aTmpIdx( rNds.GetEndOfAutotext() );
357         SwStartNode* pSttNd = bMakeEmptySection
358                 ? rNds.MakeEmptySection( aTmpIdx, SwFlyStartNode )
359                 : rNds.MakeTextSection( aTmpIdx, SwFlyStartNode,
360                         (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
361 
362         // das ist die Verankerungs-Position (fuers Layout!)
363         pFlySave->nSttNd = aRg.aStart.GetIndex()-1;
364         if( bMakeEmptySection )
365         {
366             // check: the move does not clear the surrounded section. If all
367             // nodes moved away, then create a new TxtNode
368             {
369                 // i76403: an empty selection is not a good idea
370                 if( aRg.aStart == aRg.aEnd && aRg.aStart.GetNode().GetTxtNode() )
371                     aRg.aEnd++;
372                 SwNodeIndex aPrev( aRg.aStart, -1 );
373                 if( aPrev.GetNode().IsStartNode() &&
374                     aPrev.GetNode().EndOfSectionNode() == &aRg.aEnd.GetNode())
375                 {
376                     // create new txtnode, because the section does never be empty
377                     pDoc->GetNodes().MakeTxtNode( aRg.aEnd,
378                             (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
379                     aRg.aEnd--;
380                 }
381             }
382             aTmpIdx = *pSttNd->EndOfSectionNode();
383             pDoc->MoveNodeRange( aRg, aTmpIdx,
384                 IDocumentContentOperations::DOC_MOVEDEFAULT );
385         }
386 
387         // patch from cmc for #i52542#
388         if (pSttNd->GetIndex() + 1 == pSttNd->EndOfSectionIndex())
389         {
390             ASSERT(sal_False, "nothing in this frame, not legal");
391             delete pFlySave;
392             continue;
393         }
394 
395         pFlySave->aFlySet.Put( SwFmtCntnt( pSttNd ));
396 
397         CalculateFlySize( pFlySave->aFlySet, pFlySave->nSttNd,
398                           pFlySave->nPageWidth );
399 
400                 // THIS >>>>>
401         // if the section only contains one Node and this has a
402         // border or background, then put it to the frame
403         // Not in our own RTF-Format!
404                 // <<<<< DOES NOT MAKE SENSE TO ME (flr)
405         // #102781#. Added support for transparent frames.
406         if( pSttNd->GetIndex() + 1 != pSttNd->EndOfSectionIndex() &&
407             !bSwPageDesc )
408         {
409             SwCntntNode* pSrcNd = pDoc->GetNodes()[ pSttNd->GetIndex() + 1 ]->GetCntntNode();
410             SfxItemSet aTmpSet( pDoc->GetAttrPool(),
411                                     RES_BACKGROUND, RES_BOX );
412             const SvxBrushItem* pBackgroundBrush = (const SvxBrushItem*)pFlySave->aFlySet.GetItem(RES_BACKGROUND, sal_False);
413             if( pSrcNd && pSrcNd->HasSwAttrSet() )
414                 aTmpSet.Put( *pSrcNd->GetpSwAttrSet() );
415             if (pBackgroundBrush)
416             {
417                 aTmpSet.Put(*pBackgroundBrush, RES_BACKGROUND);
418             }
419             else
420             {
421                 pBackgroundBrush = (const SvxBrushItem*)aTmpSet.GetItem(RES_BACKGROUND, sal_False);
422                 if (pBackgroundBrush)
423                 {
424                     Color& rBackgroundColor = const_cast<SvxBrushItem*>(pBackgroundBrush)->GetColor();
425                     rBackgroundColor.SetTransparency(0xFE);
426                 }
427                 else
428                 {
429                     Color aColor = Color(0xff, 0xff, 0xff);
430                     aColor.SetTransparency( 0xFE);
431                     SvxBrushItem aBrush(aColor, RES_BACKGROUND);
432                     aTmpSet.Put(aBrush, RES_BACKGROUND);
433                 }
434             }
435             // #117914# Topic 6.
436             pFlySave->aFlySet.Put( aTmpSet );
437             if( pSrcNd && pSrcNd->HasSwAttrSet() )
438             {
439                 pSrcNd->ResetAttr( RES_BACKGROUND, RES_BOX );
440             }
441         }
442 
443         SwFlyFrmFmt* pFmt = pDoc->MakeFlyFrmFmt( aEmptyStr, pParent );
444         pFmt->SetFmtAttr( pFlySave->aFlySet );
445         const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
446         if (FLY_AS_CHAR != rAnchor.GetAnchorId())
447         {
448             // korrigiere noch den Absatz, ist immer der vorhergehende !
449             // JP 20.09.95: wenn es diesen gibt! (DocAnfang!)
450 
451             //JP 02.08.99: that is wrong. The anchor is ever the NEXT!
452             //JP 05.08.99: there are an Bug in the ExportFilter which will
453             //              be fixed in the Version 517 - by SWG-Export
454             //              the fly will be after the paragraph - but in RTF
455             //              the flys will be before the paragraph.
456             if( !bSwPageDesc || 5430 < GetVersionNo() )
457                 pFlySave->nSttNd++;
458 
459 //            if( !pFlySave->nSttNd.GetNode().IsCntntNode() )
460             {
461                 // Seitenumbrueche in den Bodybereich verschieben!
462                 SwCntntNode* pSrcNd = aRg.aStart.GetNode().GetCntntNode();
463                 SwCntntNode* pDstNd = pFlySave->nSttNd.GetNode().GetCntntNode();
464                 if( !pDstNd )
465                     pDstNd = pDoc->GetNodes().GoNext( &pFlySave->nSttNd );
466 
467                 ::lcl_CpyBreakAttrs( pSrcNd, pDstNd, &pFlySave->nSttNd );
468             }
469 
470             const SwNodeIndex aSttNd(*pSttNd);
471             SwNodeIndex aEndNd(*pSttNd->EndOfSectionNode());
472             aEndNd--;
473 
474             SwPosition aPos( pFlySave->nSttNd );
475             SwFmtAnchor aAnchor(rAnchor);
476             aAnchor.SetAnchor(&aPos);
477 
478             const SwNode *pCurrentAnchor = &(pFlySave->nSttNd.GetNode());
479             aPrevFmts[pCurrentAnchor].push_back(frameEntry(pFmt, aAnchor));
480 
481             while (aEndNd > aSttNd)
482             {
483                 typedef rtfframesAtIndex::iterator myIter;
484                 rtfframesAtIndex &rDeque = aPrevFmts[&(aEndNd.GetNode())];
485                 myIter aEnd = rDeque.end();
486                 for (myIter aIter = rDeque.begin(); aIter != aEnd; ++aIter)
487                 {
488                     aIter->second.SetAnchor(&aPos);
489                     // --> OD 2004-06-30 #i27767# - push on front to keep order
490                     // of objects for the correct object positioning
491                     //aPrevFmts[pCurrentAnchor].push_back(*aIter);
492                     aPrevFmts[pCurrentAnchor].push_front(*aIter);
493                 }
494                 rDeque.clear();
495                 aEndNd--;
496            }
497         }
498 
499         // --> OD, FLR 2006-02-16 #131205#
500         // Create draw contact object, which also creates a <SdrObject> instance,
501         // in order to set the order number.
502         // The order number is assumed to be the order of the text flow.
503         SwFlyDrawContact* pContact =
504                 new SwFlyDrawContact( pFmt,
505                                       pFmt->GetDoc()->GetOrCreateDrawModel() );
506         pContact->GetMaster()->SetOrdNum( n );
507         // <--
508 
509         delete pFlySave;
510     }
511 
512     typedef rtfFmtMap::reverse_iterator myriter;
513     myriter aEnd = aPrevFmts.rend();
514     for(myriter aIter = aPrevFmts.rbegin(); aIter != aEnd; ++aIter)
515     {
516         rtfframesAtIndex &rDeque = aIter->second;
517         typedef rtfframesAtIndex::iterator myIter;
518         myIter aQEnd = rDeque.end();
519         for (myIter aQIter = rDeque.begin(); aQIter != aQEnd; ++aQIter)
520         {
521             frameEntry &rEntry = *aQIter;
522             SwFlyFrmFmt *pFrm = rEntry.first;
523             SwFmtAnchor &rAnchor = rEntry.second;
524             pFrm->SetFmtAttr(rAnchor);
525         }
526     }
527 
528     aFlyArr.Remove(0, aFlyArr.Count());
529 }
530 
531 // clips the text box to the min or max position if it is outside our min or max boundary
GetSafePos(long nPos)532 long SwRTFParser::GetSafePos(long nPos)
533 {
534     if(nPos > SHRT_MAX)
535         nPos = SHRT_MAX;
536     else if(nPos < SHRT_MIN)
537         nPos = SHRT_MIN;
538 
539     return nPos;
540 }
541 
ReadFly(int nToken,SfxItemSet * pSet)542 void SwRTFParser::ReadFly( int nToken, SfxItemSet* pSet )
543 {
544     // ein Set fuer die FrmFmt-Attribute
545     SfxItemSet aSet( pDoc->GetAttrPool(), RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
546     if( !IsNewDoc() )
547         Reader::ResetFrmFmtAttrs( aSet );
548 
549     // der Fly beginnt immer in einem neuen Absatz
550     if( pPam->GetPoint()->nContent.GetIndex() )
551         InsertPara();
552 
553     // RTF-Defaults setzen:
554     // --> OD 2004-06-24 #i27767#
555     SwFmtAnchor aAnchor( FLY_AT_PARA );
556 
557     SwFmtHoriOrient aHori( 0, text::HoriOrientation::LEFT, text::RelOrientation::FRAME );
558     SwFmtVertOrient aVert( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME );
559     // <--
560     SvxFrameDirectionItem aFrmDir( FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
561 
562     sal_uInt16 nCols = USHRT_MAX, nColSpace = USHRT_MAX, nAktCol = 0;
563     SvUShorts aColumns;
564 
565     sal_Bool bChkDropCap = 0 == pSet;
566     sal_uInt16 nDropCapLines = 0, nDropCapAnchor = 0;
567     int nNumOpenBrakets = GetOpenBrakets();
568 
569     if( !pSet )
570     {
571         pSet = &aSet;
572     }
573     else
574     {
575         // die Werte aus dem uebergebenen!
576         aAnchor = (SwFmtAnchor&)pSet->Get( RES_ANCHOR );
577         aHori = (SwFmtHoriOrient&)pSet->Get( RES_HORI_ORIENT );
578         aVert = (SwFmtVertOrient&)pSet->Get( RES_VERT_ORIENT );
579     }
580 
581     // dann sammel mal alle Attribute zusammen
582     int bWeiter = sal_True;
583     int nAppliedProps=0;
584     do {
585         sal_uInt16 nVal = sal_uInt16(nTokenValue);
586         /*
587         #i5263#
588         Assume that a property genuinely contributes towards creating a frame,
589         and if turns out to be a non contributing one reduce the count.
590         */
591         ++nAppliedProps;
592         switch( nToken )
593         {
594         case RTF_ABSW:
595             {
596                 SwFmtFrmSize aSz( ATT_MIN_SIZE, nTokenValue, 0 );
597                 const SfxPoolItem* pItem;
598                 if( SFX_ITEM_SET == pSet->GetItemState( RES_FRM_SIZE, sal_True,
599                     &pItem ))
600                 {
601                     aSz.SetHeightSizeType( ((SwFmtFrmSize*)pItem)->GetHeightSizeType() );
602                     aSz.SetHeight( ((SwFmtFrmSize*)pItem)->GetHeight() );
603                 }
604                 if( MINFLY > nTokenValue )  nTokenValue = MINFLY;
605                 aSet.Put( aSz );
606             }
607             break;
608         case RTF_ABSH:
609             {
610                 SwFmtFrmSize aSz( ATT_MIN_SIZE, 0, MINFLY );
611                 const SfxPoolItem* pItem;
612                 if( SFX_ITEM_SET == pSet->GetItemState( RES_FRM_SIZE, sal_True,
613                     &pItem ))
614                 {
615                     aSz.SetWidth( ((SwFmtFrmSize*)pItem)->GetWidth() );
616                 }
617 
618                 if( 0 > nTokenValue )
619                 {
620                     nTokenValue = -nTokenValue;
621                     aSz.SetHeightSizeType( ATT_FIX_SIZE );
622                 }
623                 if( MINFLY > nTokenValue )  nTokenValue = MINFLY;
624                 aSz.SetHeight( nTokenValue );
625                 aSet.Put( aSz );
626             }
627             break;
628 
629         case RTF_NOWRAP:
630             {
631                 pSet->Put( SwFmtSurround( SURROUND_NONE ));
632             }
633             break;
634         case RTF_DXFRTEXT:
635                 {
636                     SvxULSpaceItem aUL( RES_UL_SPACE );
637                     SvxLRSpaceItem aLR( RES_LR_SPACE );
638                     aUL.SetUpper( nVal );   aUL.SetLower( nVal );
639                     aLR.SetLeft( nVal );    aLR.SetRight( nVal );
640                     pSet->Put( aUL );
641                     pSet->Put( aLR );
642                 }
643                 break;
644 
645         case RTF_DFRMTXTX:
646                 {
647                     SvxLRSpaceItem aLR( RES_LR_SPACE );
648                     aLR.SetLeft( nVal );    aLR.SetRight( nVal );
649                     pSet->Put( aLR );
650                 }
651                 break;
652         case RTF_DFRMTXTY:
653                 {
654                     SvxULSpaceItem aUL( RES_UL_SPACE );
655                     aUL.SetUpper( nVal );   aUL.SetLower( nVal );
656                     pSet->Put( aUL );
657                 }
658                 break;
659 
660         case RTF_POSNEGX:
661         case RTF_POSX:      aHori.SetHoriOrient( text::HoriOrientation::NONE );
662                             aHori.SetPos( GetSafePos((long)nTokenValue) );
663                             break;
664         case RTF_POSXC:     aHori.SetHoriOrient( text::HoriOrientation::CENTER );     break;
665         case RTF_POSXI:     aHori.SetHoriOrient( text::HoriOrientation::LEFT );
666                             aHori.SetPosToggle( sal_True );
667                             break;
668         case RTF_POSXO:     aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
669                             aHori.SetPosToggle( sal_True );
670                             break;
671         case RTF_POSXL:     aHori.SetHoriOrient( text::HoriOrientation::LEFT );       break;
672         case RTF_POSXR:     aHori.SetHoriOrient( text::HoriOrientation::RIGHT );      break;
673 
674         case RTF_POSNEGY:
675         case RTF_POSY:      aVert.SetVertOrient( text::VertOrientation::NONE );
676                             aVert.SetPos( GetSafePos((long)nTokenValue) );
677                             break;
678         case RTF_POSYT:     aVert.SetVertOrient( text::VertOrientation::TOP );    break;
679         case RTF_POSYB:     aVert.SetVertOrient( text::VertOrientation::BOTTOM ); break;
680         case RTF_POSYC:     aVert.SetVertOrient( text::VertOrientation::CENTER ); break;
681 
682         case RTF_PHMRG:     aHori.SetRelationOrient( text::RelOrientation::PAGE_PRINT_AREA ); break;
683         case RTF_PVMRG:     aVert.SetRelationOrient( text::RelOrientation::PAGE_PRINT_AREA ); break;
684         case RTF_PHPG:      aHori.SetRelationOrient( text::RelOrientation::PAGE_FRAME ); break;
685         case RTF_PVPG:      aVert.SetRelationOrient( text::RelOrientation::PAGE_FRAME );break;
686         case RTF_PHCOL:     aHori.SetRelationOrient( text::RelOrientation::FRAME ); break;
687         case RTF_PVPARA:    aVert.SetRelationOrient( text::RelOrientation::FRAME ); break;
688 
689         case RTF_POSYIL:
690             break;
691         case RTF_ABSLOCK:
692             /*
693             #i5263#
694             Not sufficient to make a frame at least word won't do it with just
695             an abslock
696             */
697             --nAppliedProps;
698             break;
699         case RTF_FRMTXLRTB:
700             aFrmDir.SetValue( FRMDIR_HORI_LEFT_TOP );
701             break;
702         case RTF_FRMTXTBRL:
703             aFrmDir.SetValue( FRMDIR_HORI_RIGHT_TOP );
704             break;
705         case RTF_FRMTXLRTBV:
706             aFrmDir.SetValue( FRMDIR_VERT_TOP_LEFT );
707             break;
708         case RTF_FRMTXTBRLV:
709             aFrmDir.SetValue( FRMDIR_VERT_TOP_RIGHT );
710             break;
711 
712         case RTF_DROPCAPLI:                         // Dropcaps !!
713                 if( bChkDropCap )
714                 {
715                     nDropCapLines = sal_uInt16( nTokenValue );
716                     if( !nDropCapAnchor )
717                         nDropCapAnchor = 1;
718                 }
719                 break;
720         case RTF_DROPCAPT:
721                 if( bChkDropCap )
722                 {
723                     nDropCapAnchor = sal_uInt16( nTokenValue );
724                     if( !nDropCapLines )
725                         nDropCapLines = 3;
726                 }
727                 break;
728 
729 
730         // fuer die "alten" Writer - haben die Spaltigkeit falsch heraus-
731         // geschrieben
732         case RTF_COLS:          nCols = sal_uInt16( nTokenValue );      break;
733         case RTF_COLSX:         nColSpace = sal_uInt16( nTokenValue );  break;
734         case RTF_COLNO:
735             nAktCol = sal_uInt16( nTokenValue );
736             if( RTF_COLW == GetNextToken() )
737             {
738                 sal_uInt16 nWidth = sal_uInt16( nTokenValue ), nSpace = 0;
739                 if( RTF_COLSR == GetNextToken() )
740                     nSpace = sal_uInt16( nTokenValue );
741                 else
742                     SkipToken( -1 );        // wieder zurueck
743 
744                 if( --nAktCol == ( aColumns.Count() / 2 ) )
745                 {
746                     aColumns.Insert( nWidth + nSpace, aColumns.Count() );
747                     aColumns.Insert( nSpace, aColumns.Count() );
748                 }
749             }
750             break;
751 
752         case '{':
753             {
754                 short nSkip = 0;
755                 if( RTF_IGNOREFLAG != ( nToken = GetNextToken() ))
756                 {
757                     if( RTF_SHADINGDEF == (nToken & ~0xff) )
758                     {
759                         ReadBackgroundAttr( nToken, aSet );
760                         GetNextToken();     // Klammer ueberlesen
761                     }
762                     else
763                         nSkip = -1;
764                 }
765                 else if( RTF_APOCTL ==
766                     ((nToken = GetNextToken() ) & ~(0xff | RTF_SWGDEFS)) )
767                 {
768                     bReadSwFly = true;      // alles kommt in den akt. Fly
769                     SvxLRSpaceItem aLR( RES_LR_SPACE );
770                     SvxULSpaceItem aUL( RES_UL_SPACE );
771                     nCols = USHRT_MAX;      // neu aufsetzen
772                     nColSpace = USHRT_MAX;
773                     do {
774                     nVal = sal_uInt16(nTokenValue);
775                     switch( nToken )
776                     {
777                     // Swg-Frame-Tokens
778                     case RTF_FLYPRINT:
779                         {
780                             pSet->Put( SvxPrintItem( RES_PRINT, sal_False ));
781                         }
782                         break;
783                     case RTF_FLYOPAQUE:
784                         {
785                             pSet->Put( SvxOpaqueItem( RES_OPAQUE, sal_False ));
786                         }
787                         break;
788 
789                     case RTF_FLYPRTCTD:
790                         {
791                             RTFProtect aP( (sal_uInt8)nTokenValue );
792                             SvxProtectItem aProtectItem( RES_PROTECT );
793                             aProtectItem.SetCntntProtect( aP.GetCntnt() );
794                             aProtectItem.SetSizeProtect( aP.GetSize() );
795                             aProtectItem.SetPosProtect( aP.GetPos() );
796                             pSet->Put( aProtectItem );
797                         }
798                         break;
799 
800                     case RTF_FLYMAINCNT:
801                         {
802                             RTFSurround aMC( (sal_uInt8)nTokenValue );
803                             SwFmtSurround aSurr( (SwSurround)aMC.GetOrder());
804                             if( aMC.GetGoldCut() )
805                                 aSurr.SetSurround( SURROUND_IDEAL );
806                             pSet->Put( aSurr );
807                         }
808                         break;
809                     case RTF_FLYVERT:
810                         {
811                             RTFVertOrient aVO( nVal );
812                             aVert.SetVertOrient( aVO.GetOrient() );
813                             aVert.SetRelationOrient( aVO.GetRelation() );
814                         }
815                         break;
816                     case RTF_FLYHORZ:
817                         {
818                             RTFHoriOrient aHO( nVal );
819                             aHori.SetHoriOrient( aHO.GetOrient() );
820                             aHori.SetRelationOrient( aHO.GetRelation() );
821                         }
822                         break;
823                     case RTF_FLYOUTLEFT:        aLR.SetLeft( nVal );        break;
824                     case RTF_FLYOUTRIGHT:       aLR.SetRight( nVal );       break;
825                     case RTF_FLYOUTUPPER:       aUL.SetUpper( nVal );       break;
826                     case RTF_FLYOUTLOWER:       aUL.SetLower( nVal );       break;
827                     case RTF_FLYANCHOR:
828                             switch( GetNextToken() )
829                             {
830                             case RTF_FLY_PAGE:
831                                 aAnchor.SetType( FLY_AT_PAGE );
832                                 aAnchor.SetPageNum( sal_uInt16(nTokenValue));
833                                 aAnchor.SetAnchor( 0 );
834                                 break;
835 
836                             case RTF_FLY_CNTNT:
837                                 {
838                                     SwNodeIndex aIdx( pPam->GetPoint()->nNode );
839                                     pDoc->GetNodes().GoPrevious( &aIdx );
840                                     SwPosition aPos( aIdx );
841                                     aAnchor.SetType( FLY_AT_PARA );
842                                     aAnchor.SetAnchor( &aPos );
843                                 }
844                                 break;
845 
846 // JP 26.09.94: die Bindung an die Spalte gibt es nicht mehr !!
847 //                          case RTF_FLY_COLUMN:
848                             }
849                             break;
850                     case RTF_COLS:  nCols = sal_uInt16( nTokenValue );      break;
851                     case RTF_COLSX: nColSpace = sal_uInt16( nTokenValue );  break;
852                     case RTF_COLNO:
853                         nAktCol = sal_uInt16( nTokenValue );
854                         if( RTF_COLW == GetNextToken() )
855                         {
856                             sal_uInt16 nWidth = sal_uInt16( nTokenValue ), nSpace = 0;
857                             if( RTF_COLSR == GetNextToken() )
858                                 nSpace = sal_uInt16( nTokenValue );
859                             else
860                                 SkipToken( -1 );        // wieder zurueck
861 
862                             if( --nAktCol == ( aColumns.Count() / 2 ) )
863                             {
864                                 aColumns.Insert( nWidth + nSpace, aColumns.Count() );
865                                 aColumns.Insert( nSpace, aColumns.Count() );
866                             }
867                         }
868                         break;
869 
870                     case '{':
871                         if( RTF_BRDBOX == ( nToken = GetNextToken() ) )
872                             ReadBorderAttr( nToken, aSet );
873                         else if( RTF_SHADINGDEF == (nToken & ~0xff ) )
874                             ReadBackgroundAttr( nToken, aSet );
875                         else if( RTF_IGNOREFLAG == nToken )
876                         {
877                             int bSkipGrp = sal_True;
878                             switch( nToken = GetNextToken() )
879                             {
880                             case RTF_SHADOW:
881                             case RTF_BRDBOX:
882                                 ReadAttr( SkipToken( -2 ), &aSet );
883                                 bSkipGrp = sal_False;
884                                 break;
885 
886                             case RTF_BRDRT:
887                             case RTF_BRDRB:
888                             case RTF_BRDRR:
889                             case RTF_BRDRL:
890                                 bSkipGrp = sal_False;
891                                 ReadBorderAttr( SkipToken( -2 ), aSet );
892                                 break;
893                             }
894 
895                                 // keine weitere Klammer mehr ueberlesen!!!
896                             if( !bSkipGrp )
897                                 break;
898 
899                             SkipGroup();
900                         }
901                         else
902                             SkipGroup();
903                         GetNextToken();     // Klammer ueberlesen
904                         break;
905                     }
906                     } while( IsParserWorking() &&
907                                 '}' != ( nToken = GetNextToken() ));
908 
909                     if( aUL.GetUpper() || aUL.GetLower() )
910                         pSet->Put( aUL );
911                     if( aLR.GetLeft() || aLR.GetRight() )
912                         pSet->Put( aLR );
913                 }
914                 else if( RTF_BRDBOX == nToken )
915                     ReadBorderAttr( nToken, aSet );
916                 else if( RTF_SHADOW == nToken )
917                     ReadAttr( SkipToken( -2 ), &aSet );
918                 else if( RTF_SHADINGDEF == (nToken & ~0xff ) )
919                     ReadBackgroundAttr( nToken, aSet );
920                 else if( RTF_UNKNOWNCONTROL == nToken )
921                     SkipGroup();
922                 else
923                     nSkip = -2;
924 
925                 if( nSkip )
926                 {
927                     nToken = SkipToken( nSkip );
928                     bWeiter = sal_False;
929                 }
930             }
931             break;
932 
933         default:
934             --nAppliedProps; //Not sufficient to make a frame
935             bWeiter = sal_False;
936         }
937 
938         if( bWeiter )
939             nToken = GetNextToken();
940     } while( bWeiter && IsParserWorking() );
941 
942     pSet->Put( aAnchor );
943     pSet->Put( aHori );
944     pSet->Put( aVert );
945 
946     // --> OD 2004-06-30 #i27767# - set wrapping style influence
947     // --> OD 2004-10-18 #i35017# - constant name has changed
948     pSet->Put( SwFmtWrapInfluenceOnObjPos(
949                     text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ));
950     // <--
951 
952     SwFmtFollowTextFlow aFollowTextFlow( sal_False );
953     pSet->Put( aFollowTextFlow );
954 
955     if( !( aFrmDir == pSet->Get( RES_FRAMEDIR )) )
956         pSet->Put( aFrmDir );
957 
958     if( nCols && USHRT_MAX != nCols )
959     {
960         SwFmtCol aCol;
961         if( USHRT_MAX == nColSpace )
962             nColSpace = 720;
963 
964         sal_uLong nWidth = USHRT_MAX;
965         aCol.Init( nCols, nColSpace, sal_uInt16( nWidth ) );
966         if( nCols == ( aColumns.Count() / 2 ) )
967         {
968             for( sal_uInt16 n = 0, i = 0; n < aColumns.Count(); n += 2, ++i )
969             {
970                 SwColumn* pCol = aCol.GetColumns()[ i ];
971                 sal_uLong nTmp = aColumns[ n ];
972                 nTmp *= USHRT_MAX;
973                 nTmp /= nWidth;
974                 pCol->SetWishWidth( sal_uInt16(nTmp) );
975 /*
976     JP 07.07.95: der Dialog kennt nur eine Breite fuer alle Spalten
977                  darum hier nicht weiter beachten
978                 nTmp = aColumns[ n+1 ];
979                 if( nTmp )
980                     pCol->SetRight( sal_uInt16(nTmp) );
981                 else
982                     pCol->SetRight( 0 );
983                 pCol->SetLeft( 0 );
984 */
985             }
986         }
987         pSet->Put( aCol );
988     }
989 
990     if( pSet != &aSet )         // wurde der Set uebergeben, dann wars das
991         return ;
992 
993     // ein neues FlyFormat anlegen oder das alte benutzen ?
994     // (teste ob es die selben Attribute besitzt!)
995     SwFlySave* pFlySave = 0;
996     sal_uInt16 nFlyArrCnt = aFlyArr.Count();
997     /*
998     #i5263#
999     There were not enough frame properties found to actually justify creating
1000     an absolutely positioned frame.
1001     */
1002     if (nAppliedProps)
1003     {
1004         if( !nFlyArrCnt ||
1005             !( pFlySave = aFlyArr[ nFlyArrCnt-1 ])->IsEqualFly( *pPam, aSet ))
1006         {
1007             pFlySave = new SwFlySave( *pPam, aSet );
1008             Size aPgSize;
1009             GetPageSize( aPgSize );
1010             pFlySave->nPageWidth = aPgSize.Width();
1011 
1012             if( nDropCapAnchor )
1013             {
1014                 pFlySave->nDropAnchor = nDropCapAnchor;
1015                 pFlySave->nDropLines = nDropCapLines;
1016             }
1017             if (nFlyArrCnt >0){
1018                 SwFlySave* pFlySavePrev = aFlyArr[nFlyArrCnt-1];
1019                 if (pFlySave->nSttNd.GetIndex() < pFlySavePrev->nEndNd.GetIndex())
1020                 {
1021                     pFlySavePrev->nEndNd=pFlySave->nSttNd;
1022                 }
1023             }
1024             aFlyArr.Insert(  pFlySave, nFlyArrCnt++ );
1025             // --> OD 2008-12-22 #i83368# - reset
1026             mbReadCellWhileReadSwFly = false;
1027             // <--
1028         }
1029     }
1030 
1031     SetPardTokenRead( sal_False );
1032     const SwTableNode* pTblNd = pPam->GetNode()->FindTableNode();
1033 
1034     while( !IsPardTokenRead() && IsParserWorking() )
1035     {
1036         if( RTF_PARD == nToken || nNumOpenBrakets > GetOpenBrakets() )
1037             break;
1038 
1039         NextToken( nToken );
1040 
1041         if( !IsPardTokenRead() )
1042         {
1043             // #102781#. Added support for transparent frames.
1044             if (nToken == RTF_CBPAT && nFlyArrCnt > 0)
1045             {
1046                 sal_uInt16 _index=sal_uInt16(nTokenValue);
1047                 const Color& rColor = GetColor(_index);
1048                 SvxBrushItem aBrush(rColor, RES_BACKGROUND);
1049                 SwFlySave* pFS = aFlyArr[nFlyArrCnt-1];
1050                 pFS->aFlySet.Put(aBrush, RES_BACKGROUND);
1051             }
1052 
1053             nToken = GetNextToken();
1054 
1055             // BUG 22036: kommt zwischen Fly-Attributen ein unbekanntes,
1056             //              dann erzeuge nie 2 FlyFrames, sondern fasse
1057             //              beide zusammen !!!
1058             while( RTF_APOCTL == ( nToken & ~(0xff | RTF_SWGDEFS) ))
1059             {
1060                 if( RTF_FLY_INPARA == nToken )
1061                     break;
1062 
1063                 if( RTF_IGNOREFLAG == SkipToken( -1 ) )
1064                 {
1065                     if( '{' == SkipToken( -1 ) )
1066                         nToken = '{';
1067                     else
1068                         SkipToken( 2 );
1069                 }
1070                 else
1071                     SkipToken( 1 );
1072 
1073                 ReadFly( nToken, pFlySave ? &pFlySave->aFlySet : 0);
1074                 nToken = GetNextToken();
1075             }
1076         }
1077     }
1078 
1079     /*
1080     #i5263#
1081     There were enough frame properties found to actually justify creating
1082     an absolutely positioned frame.
1083     */
1084     if (!nAppliedProps)
1085     {
1086         bReadSwFly = false;
1087         SkipToken( -1 );
1088         return;
1089     }
1090 
1091     if( pTblNd && !pPam->GetPoint()->nContent.GetIndex() &&
1092         pTblNd->EndOfSectionIndex() + 1 ==
1093             pPam->GetPoint()->nNode.GetIndex() )
1094     {
1095         // nicht mehr in der Tabelle, sondern dahinter ?
1096         // Dann aber wieder zurueck in die Tabelle
1097         pPam->Move( fnMoveBackward );
1098     }
1099     else
1100         pTblNd = 0;
1101 
1102     // wurde garnichts eingefuegt?
1103     if( !pTblNd &&
1104         pPam->GetPoint()->nNode == pFlySave->nSttNd &&
1105         !pPam->GetPoint()->nContent.GetIndex() )
1106     {
1107 //      // dann erzeuge mindestens einen leeren TextNode
1108 //      pDoc->AppendTxtNode(*pPam);
1109         // dann zerstoere den FlySave wieder.
1110         aFlyArr.DeleteAndDestroy( --nFlyArrCnt );
1111 
1112     }
1113     else
1114     {
1115         sal_Bool bMovePaM = 0 != pTblNd;
1116 
1117         pFlySave->nEndNd = pPam->GetPoint()->nNode;
1118         pFlySave->nEndCnt = pPam->GetPoint()->nContent.GetIndex();
1119 
1120         if( bMovePaM )
1121             pPam->Move( fnMoveForward );
1122 
1123         pTblNd = pFlySave->nSttNd.GetNode().FindTableNode();
1124         if( pTblNd && !pFlySave->nEndCnt &&
1125             pTblNd == pFlySave->nEndNd.GetNode().FindTableNode() )
1126         {
1127             // dann teste mal, ob das \pard nicht zu spaet kam und
1128             // eigentlich in die vorherige Zelle gehoert
1129             const SwStartNode* pSttBoxNd = pFlySave->nSttNd.GetNode().
1130                                             FindTableBoxStartNode(),
1131                             * pEndBoxNd = pFlySave->nEndNd.GetNode().
1132                                             FindTableBoxStartNode();
1133             if( pSttBoxNd && pEndBoxNd &&
1134                 bMovePaM ? ( pSttBoxNd == pEndBoxNd )
1135                          : ( pSttBoxNd->EndOfSectionIndex() + 1 ==
1136                                 pEndBoxNd->GetIndex() &&
1137                                 pEndBoxNd->GetIndex() + 1 ==
1138                                 pFlySave->nEndNd.GetIndex() ))
1139             {
1140                 // dann gehoert das Ende in die vorherige Box!
1141                 SwPosition aPos( *pPam->GetPoint() );
1142                 pPam->GetPoint()->nNode = *pSttBoxNd->EndOfSectionNode();
1143                 pPam->Move( fnMoveBackward, fnGoNode );
1144 
1145                 DelLastNode();
1146 
1147                 pPam->GetPoint()->nNode = *pSttBoxNd->EndOfSectionNode();
1148                 pPam->Move( fnMoveBackward, fnGoNode );
1149 
1150                 pFlySave->nEndNd = pPam->GetPoint()->nNode;
1151                 pFlySave->nEndCnt = pPam->GetPoint()->nContent.GetIndex();
1152 
1153                 *pPam->GetPoint() = aPos;
1154             }
1155         }
1156         else if( !bReadSwFly && !pFlySave->nEndCnt &&
1157             pFlySave->nSttNd.GetIndex() + 1 == pFlySave->nEndNd.GetIndex() &&
1158             pFlySave->nSttNd.GetNode().IsTxtNode() )
1159         {
1160 
1161             SwTxtNode* pTxtNd = pFlySave->nSttNd.GetNode().GetTxtNode();
1162             SwTxtFlyCnt* pFlyCnt = 0;
1163             if( 1 == pTxtNd->GetTxt().Len() &&
1164                 0 != (pFlyCnt = static_cast<SwTxtFlyCnt*>(
1165                         pTxtNd->GetTxtAttrForCharAt(0, RES_TXTATR_FLYCNT))) &&
1166                 pFlyCnt->GetFlyCnt().GetFrmFmt() )
1167             {
1168                 // then move the content into the surrounded fly
1169                 SwFrmFmt* pFlyFmt = pFlyCnt->GetFlyCnt().GetFrmFmt();
1170                 const SwNodeIndex* pFlySNd = pFlyFmt->GetCntnt().GetCntntIdx();
1171                 SwNodeRange aRg( *pFlySNd, 1,
1172                                  *pFlySNd->GetNode().EndOfSectionNode(), 0 );
1173 
1174                 // merge the itemsets
1175                 SwFmtFrmSize aSz1( (SwFmtFrmSize&)pFlyFmt->GetAttrSet().
1176                                                 Get( RES_FRM_SIZE ));
1177                 SwFmtFrmSize aSz2( (SwFmtFrmSize&)pFlySave->aFlySet.
1178                                                 Get( RES_FRM_SIZE ));
1179                 // if
1180                 if( !aRg.aStart.GetNode().IsNoTxtNode() ||
1181                     !aSz1.GetHeight() || !aSz1.GetWidth() ||
1182                     !aSz2.GetHeight() || !aSz2.GetWidth() ||
1183                     ( aSz1.GetHeight() == aSz2.GetHeight() &&
1184                       aSz1.GetWidth() == aSz2.GetWidth() ) )
1185                 {
1186                     SfxItemSet aDiffs( pFlyFmt->GetAttrSet() );
1187                     aDiffs.ClearItem( RES_ANCHOR );
1188                     aDiffs.ClearItem( RES_FRM_SIZE );
1189                     aDiffs.ClearItem( RES_CNTNT );
1190                     aDiffs.Differentiate( pFlySave->aFlySet );
1191                     pFlySave->aFlySet.Put( aDiffs );
1192 
1193                     sal_Bool bSet = sal_False;
1194                     if( aSz1.GetHeight() && !aSz2.GetHeight() )
1195                     {
1196                         bSet = sal_True;
1197                         aSz2.SetHeight( aSz1.GetHeight() );
1198                     }
1199                     if( aSz1.GetWidth() && !aSz2.GetWidth() )
1200                     {
1201                         bSet = sal_True;
1202                         aSz2.SetWidth( aSz1.GetWidth() );
1203                     }
1204                     if( bSet )
1205                         pFlySave->aFlySet.Put( aSz2 );
1206 
1207                     // move any PageBreak/Desc Attr to the next Para
1208                     {
1209                         SwCntntNode* pSrcNd = pFlySave->nSttNd.GetNode().GetCntntNode();
1210                         SwCntntNode* pDstNd = pFlySave->nEndNd.GetNode().GetCntntNode();
1211 
1212                         ::lcl_CpyBreakAttrs( pSrcNd, pDstNd, &pFlySave->nEndNd );
1213                     }
1214 
1215                     // create new txtnode, because the section does never be empty
1216                     pDoc->GetNodes().MakeTxtNode( aRg.aStart,
1217                                 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
1218 
1219                     SwNodeIndex aTmp( pFlySave->nSttNd, +1 );
1220                     pDoc->MoveNodeRange( aRg, aTmp,
1221                             IDocumentContentOperations::DOC_MOVEDEFAULT );
1222 
1223                     // now delete the redundant txtnode
1224                     pDoc->GetNodes().Delete( pFlySave->nSttNd, 1 );
1225                 }
1226             }
1227         }
1228     }
1229 
1230     bReadSwFly = false;
1231     SkipToken( -1 );
1232 }
1233 
1234 
InsPicture(const String & rGrfNm,const Graphic * pGrf,const SvxRTFPictureType * pPicType)1235 void SwRTFParser::InsPicture( const String& rGrfNm, const Graphic* pGrf,
1236                                 const SvxRTFPictureType* pPicType )
1237 {
1238     // kennzeichen fuer Swg-Dokumente:
1239     // (dann ist das FlyFmt fuer die Grafik!)
1240     SwGrfNode * pGrfNd;
1241     // --> OD 2008-12-22 #i83368#
1242     // Assure that graphic node is enclosed by fly frame node.
1243 //    if( bReadSwFly )
1244     if ( bReadSwFly && !mbReadCellWhileReadSwFly )
1245     // <--
1246     {
1247         OSL_ENSURE(aFlyArr.Count(),
1248             "SwRTFParser::InsPicture: fly array empty.");
1249         if (aFlyArr.Count())
1250         {
1251             // erzeuge nur einen normalen GrafikNode und ersetze diesen gegen
1252             // den vorhandenen Textnode
1253             SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
1254             pGrfNd = pDoc->GetNodes().MakeGrfNode( rIdx,
1255                         rGrfNm, aEmptyStr,    // Name der Graphic !!
1256                         pGrf,
1257                         (SwGrfFmtColl*)pDoc->GetDfltGrfFmtColl() );
1258 
1259             if( pGrfAttrSet )
1260                 pGrfNd->SetAttr( *pGrfAttrSet );
1261 
1262             SwFlySave* pFlySave = aFlyArr[ aFlyArr.Count()-1 ];
1263             pFlySave->nSttNd = rIdx.GetIndex() - 1;
1264 
1265             if( 1 < aFlyArr.Count() )
1266             {
1267                 pFlySave = aFlyArr[ aFlyArr.Count() - 2 ];
1268                 if( pFlySave->nEndNd == rIdx )
1269                     pFlySave->nEndNd = rIdx.GetIndex() - 1;
1270             }
1271         }
1272     }
1273     else
1274     {
1275         // wenn normale RTF-Grafik, dann steht diese im Textfluss !
1276         SwAttrSet aFlySet( pDoc->GetAttrPool(), RES_OPAQUE, /*RES_OPAQUE,
1277                                                 RES_VERT_ORIENT,*/ RES_ANCHOR );
1278         const SwPosition* pPos = pPam->GetPoint();
1279 
1280         SwFmtAnchor aAnchor( FLY_AS_CHAR );
1281         aAnchor.SetAnchor( pPos );
1282         aFlySet.Put( aAnchor );
1283         aFlySet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP ));
1284 
1285         if (pDoc->IsInHeaderFooter(pPos->nNode))
1286         {
1287             SvxOpaqueItem aOpaqueItem(RES_OPAQUE, sal_False);
1288             SwFmtSurround aSurroundItem(SURROUND_THROUGHT);
1289             aFlySet.Put(aOpaqueItem);
1290             aFlySet.Put(aSurroundItem);
1291         }
1292 
1293         SwFlyFrmFmt* pFlyFmt = pDoc->Insert( *pPam,
1294                     rGrfNm, aEmptyStr,      // Name der Graphic !!
1295                     pGrf,
1296                     &aFlySet,               // Attribute fuer den FlyFrm
1297                     pGrfAttrSet, NULL );            // Attribute fuer die Grafik
1298 
1299         pGrfNd = pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx()->
1300                                             GetIndex()+1 ]->GetGrfNode();
1301 
1302         _SetPictureSize( *pGrfNd, pPos->nNode,
1303                         (SfxItemSet&)pFlyFmt->GetAttrSet(),
1304                         pPicType );
1305         if( pPicType )
1306         {
1307             PictPropertyNameValuePairs::const_iterator aIt = pPicType->aPropertyPairs.begin();
1308             PictPropertyNameValuePairs::const_iterator aEnd = pPicType->aPropertyPairs.end();
1309             while( aIt != aEnd)
1310             {
1311                 if( aIt->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "wzDescription") ))
1312                 {
1313                     SwXFrame::GetOrCreateSdrObject( pFlyFmt );
1314                     pDoc->SetFlyFrmDescription( *(pFlyFmt), aIt->second );
1315                 }
1316                 else if( aIt->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "wzName") ))
1317                 {
1318                     SwXFrame::GetOrCreateSdrObject( pFlyFmt );
1319                     pDoc->SetFlyFrmTitle( *(pFlyFmt), aIt->second );
1320                 }
1321                 ++aIt;
1322             }
1323         }
1324 
1325     }
1326 
1327     if( pGrfAttrSet )
1328         DELETEZ( pGrfAttrSet );
1329 }
1330 
_SetPictureSize(const SwNoTxtNode & rNd,const SwNodeIndex & rAnchor,SfxItemSet & rSet,const SvxRTFPictureType * pPicType)1331 void SwRTFParser::_SetPictureSize( const SwNoTxtNode& rNd,
1332                                     const SwNodeIndex& rAnchor,
1333                                     SfxItemSet& rSet,
1334                                     const SvxRTFPictureType* pPicType )
1335 {
1336     Size aSize( ((SwNoTxtNode&)rNd).GetTwipSize() );
1337     if( pPicType )
1338     {
1339         if( rNd.IsGrfNode() )
1340         {
1341             if( SvxRTFPictureType::WIN_METAFILE != pPicType->eStyle &&
1342                 pPicType->nGoalWidth && pPicType->nGoalHeight )
1343             {
1344                 aSize.Width() = pPicType->nGoalWidth;
1345                 aSize.Height() =pPicType->nGoalHeight;
1346             }
1347             else if( SvxRTFPictureType::MAC_QUICKDRAW == pPicType->eStyle )
1348             {
1349                 // IMMER auf 72 DPI bezogen, also 1pt == 20 Twip !!
1350                 aSize.Width() = pPicType->nWidth * 20;
1351                 aSize.Height() = pPicType->nHeight * 20;
1352             }
1353             else
1354             {
1355                 // von 100TH_MM nach TWIP umrechenen!
1356                 // #117879# when \picwgoal resp \pichgoal are present, then use them.
1357                 //          The values of \picwgoal and \picwgoal are already given in twips.
1358                 aSize.Width() = (pPicType->nGoalWidth?pPicType->nGoalWidth:(pPicType->nWidth*144)/254);
1359                 aSize.Height() = (pPicType->nGoalHeight?pPicType->nGoalHeight:(pPicType->nHeight*144)/254);
1360             }
1361             ((SwGrfNode&)rNd).SetTwipSize( aSize );
1362         }
1363 
1364         if( 100 != pPicType->nScalX )
1365             aSize.Width() = (((long)pPicType->nScalX) * ( aSize.Width() -
1366                         ( pPicType->nCropL + pPicType->nCropR ))) / 100L;
1367 
1368         if( 100 != pPicType->nScalY )
1369             aSize.Height() = (((long)pPicType->nScalY) * ( aSize.Height() -
1370                         ( pPicType->nCropT + pPicType->nCropB ))) / 100L;
1371     }
1372 
1373     //steht der Fly etwa in einer Tabelle ?
1374     const SwNode* pAnchorNd = & rAnchor.GetNode();
1375     const SwTableNode* pTblNd = pAnchorNd->FindTableNode();
1376     if( pTblNd )
1377     {
1378         // Box feststellen:
1379         const SwTableBox* pBox = pTblNd->GetTable().GetTblBox(
1380                                 pAnchorNd->StartOfSectionIndex() );
1381         if( pBox )
1382         {
1383             long nBoxWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1384             if( aSize.Width() > nBoxWidth )
1385                 aSize.Width() = nBoxWidth;
1386         }
1387     }
1388 
1389     //JP 8.11.2001: bug 94450 - if no size exist, then the size is set by
1390     //              the swapin of the graphic.
1391     SwGrfNode* pGrfNd;
1392     if( !aSize.Width() && !aSize.Height() &&
1393         0 != (pGrfNd = (SwGrfNode*)rNd.GetGrfNode() ) && pGrfNd->IsGrfLink() )
1394         pGrfNd->SetChgTwipSize( sal_True );
1395 
1396         // min. Werte einhalten !!
1397     if( aSize.Width() < MINFLY )
1398         aSize.Width() = MINFLY;
1399     if( aSize.Height() < MINFLY)
1400         aSize.Height() = MINFLY;
1401 
1402     if( pPicType )
1403     {
1404         sal_Bool bChg = sal_False;
1405         SwCropGrf aCrop;
1406 
1407 /*
1408  JP 28.07.99: Bug 67800 - no crop by MAC_QUICKDRAW. At time i dont know why
1409                             it has been coded. But this has used for any
1410                             RTF-File, but i dont found them.
1411         if( SvxRTFPictureType::MAC_QUICKDRAW == pPicType->eStyle )
1412         {
1413             // evt. ein wenig Croppen ??
1414             // IMMER auf 72 DPI bezogen, also 1pt == 20 Twip !!
1415             long nTmp = pPicType->nWidth * 20;
1416             if( nTmp != aSize.Width() )
1417             {
1418                 // in der Breite (also rechts) croppen
1419                 aCrop.Right() = nTmp - aSize.Width();
1420                 aSize.Width() = nTmp;
1421                 bChg = sal_True;
1422             }
1423 
1424             nTmp = pPicType->nHeight * 20;
1425             if( nTmp != aSize.Height() )
1426             {
1427                 // in der Hoehe (also unten) croppen
1428                 aCrop.Bottom() = nTmp - aSize.Height();
1429                 aSize.Height() = nTmp;
1430                 bChg = sal_True;
1431             }
1432         }
1433 */
1434         if( pPicType->nCropT )
1435         {
1436             aCrop.SetTop( pPicType->nCropT );
1437             bChg = sal_True;
1438         }
1439         if( pPicType->nCropB )
1440         {
1441             aCrop.SetBottom( pPicType->nCropB );
1442             bChg = sal_True;
1443         }
1444         if( pPicType->nCropL )
1445         {
1446             aCrop.SetLeft( pPicType->nCropL );
1447             bChg = sal_True;
1448         }
1449         if( pPicType->nCropR )
1450         {
1451             aCrop.SetRight( pPicType->nCropR );
1452             bChg = sal_True;
1453         }
1454 
1455         if( bChg )
1456         {
1457             // dann mal an die CropWerte an die GrafikSize anpassen.
1458             ((SwNoTxtNode&)rNd).SetAttr( aCrop );
1459         }
1460     }
1461     rSet.Put( SwFmtFrmSize( ATT_FIX_SIZE, aSize.Width(), aSize.Height() ));
1462 }
1463 
GetPageSize(Size & rSize)1464 void SwRTFParser::GetPageSize( Size& rSize )
1465 {
1466     ASSERT(!maSegments.empty(), "not possible");
1467     if (maSegments.empty())
1468     {
1469         rSize.Width() = 12240 - 1800 - 1800;
1470         rSize.Height() = 15840 - 1440 - 1440;
1471         return;
1472     }
1473 
1474     const rtfSection &rSect = maSegments.back();
1475 
1476     rSize.Width() = rSect.maPageInfo.mnPgwsxn - rSect.maPageInfo.mnMarglsxn - rSect.maPageInfo.mnMargrsxn;
1477     rSize.Height() = rSect.maPageInfo.mnPghsxn - rSect.maPageInfo.mnMargtsxn - rSect.maPageInfo.mnMargbsxn;
1478 
1479     long nCols = rSect.NoCols();
1480     if (1 < nCols)
1481     {
1482         rSize.Width() /= nCols;
1483         rSize.Height() /= nCols;
1484     }
1485 }
1486 
ReadBitmapData()1487 void SwRTFParser::ReadBitmapData()
1488 {
1489     Graphic aGrf;
1490     SvxRTFPictureType aPicType;
1491     if( ReadBmpData( aGrf, aPicType ) )
1492         InsPicture( aEmptyStr, &aGrf, &aPicType );
1493 }
1494 
1495 #ifdef READ_OLE_OBJECT
ReadOLEData()1496 void SwRTFParser::ReadOLEData()
1497 {
1498     SvCacheStream aTmpFile( 0xA000 );
1499     Graphic aGrf;
1500     SvxRTFPictureType aPicType, aOleType;
1501 
1502     int nToken, bValidOle = sal_True, bWeiter = sal_True;
1503     int nOpenBrakets = 1;       // die erste wurde schon vorher erkannt !!
1504 
1505     String* pStr = 0;
1506     String sObjClass, sObjName, sObjData;
1507 
1508     while( nOpenBrakets && IsParserWorking() && bWeiter && bValidOle )
1509     {
1510         nToken = GetNextToken();
1511         sal_uInt16 nVal = sal_uInt16( nTokenValue );
1512         switch( nToken )
1513         {
1514         case '}':       --nOpenBrakets; pStr = 0; break;
1515         case '{':
1516             {
1517                 if( RTF_IGNOREFLAG != GetNextToken() )
1518                     nToken = SkipToken( -1 );
1519                 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
1520                     nToken = SkipToken( -2 );
1521                 else
1522                 {
1523                     // gleich herausfiltern
1524                     ReadUnknownData();
1525                     nToken = GetNextToken();
1526                     if( '}' != nToken )
1527                         eState = SVPAR_ERROR;
1528                     break;
1529                 }
1530                 ++nOpenBrakets;
1531             }
1532             break;
1533 
1534         case RTF_OBJECT:
1535         case RTF_OBJEMB:        // default ist embedded
1536         case RTF_LINKSELF:      // ??
1537         case RTF_OBJLOCK:       // ??
1538         case RTF_OBJUPDATE:     // ??
1539         case RTF_OBJTIME:       // ??
1540         case RTF_OBJSETSIZE:
1541         case RTF_OBJALIGN:
1542         case RTF_OBJTRANSY:
1543         case RTF_OBJATTPH:
1544             break;
1545 
1546         case RTF_OBJLINK:       // ?? welche Daten sind das ??
1547         case RTF_OBJAUTLINK:    // ??       -""-            ??
1548         case RTF_OBJSUB:
1549         case RTF_OBJPUB:
1550         case RTF_OBJICEMB:
1551         case RTF_OBJOCX:
1552         case RTF_OBJHTML:
1553         case RTF_OBJALIAS:
1554         case RTF_OBJSECT:
1555             bValidOle = sal_False;      // diese Typen koennen wir nicht
1556             break;
1557 
1558         case RTF_OBJCLASS:
1559             // Daten lesen
1560             pStr = &sObjClass;
1561             break;
1562 
1563         case RTF_OBJNAME:
1564             // Daten lesen
1565             pStr = &sObjName;
1566             break;
1567 
1568         case RTF_OBJDATA:
1569             pStr = &sObjData;
1570             break;
1571 
1572         case RTF_RESULT:
1573             {
1574                 // hier weitermachen, wenn das OLE-Object ungueltig ist
1575                 bWeiter = sal_False;
1576             }
1577             break;
1578         case RTF_RSLTBMP:           // diese sollten wir ignorieren
1579         case RTF_RSLTMERGE:
1580         case RTF_RSLTPICT:
1581         case RTF_RSLTRTF:
1582         case RTF_RSLTTXT:
1583             break;
1584 
1585         case RTF_OBJW:          aOleType.nWidth = nVal; break;
1586         case RTF_OBJH:          aOleType.nHeight = nVal; break;
1587         case RTF_OBJCROPT:      aOleType.nCropT = (short)nTokenValue; break;
1588         case RTF_OBJCROPB:      aOleType.nCropB = (short)nTokenValue; break;
1589         case RTF_OBJCROPL:      aOleType.nCropL = (short)nTokenValue; break;
1590         case RTF_OBJCROPR:      aOleType.nCropR = (short)nTokenValue; break;
1591         case RTF_OBJSCALEX:     aOleType.nScalX = nVal; break;
1592         case RTF_OBJSCALEY:     aOleType.nScalY = nVal; break;
1593 
1594         case RTF_TEXTTOKEN:
1595             if( 1 < nOpenBrakets && pStr )
1596             {
1597                 if( pStr == &sObjData )
1598                 {
1599                     xub_StrLen nHexLen = HexToBin( aToken );
1600                     if( STRING_NOTFOUND != nHexLen )
1601                         bValidOle = sal_False;
1602                     else
1603                     {
1604                         aTmpFile.Write( (sal_Char*)aToken.GetBuffer(), nHexLen );
1605                         bValidOle = 0 == aTmpFile.GetError();
1606                     }
1607                 }
1608                 else
1609                     *pStr += aToken;
1610             }
1611             break;
1612         }
1613     }
1614 
1615     if( bValidOle )
1616     {
1617         bValidOle = sal_False;      // erstmal
1618     }
1619 
1620     if( !bWeiter )      // dann stehen wir noch im Result
1621     {
1622         // ist das Ole-Object Ok?
1623         // -> dann solange SkipGroup rufen, bis zur letzten
1624         //      schliessenden Klammer
1625         // ansonsten alle Token verarbeiten, bis zur letzten
1626         //      schliessenden Klammer
1627 
1628         bWeiter = sal_True;
1629         while( nOpenBrakets && IsParserWorking() && bWeiter )
1630         {
1631             switch( nToken = GetNextToken() )
1632             {
1633             case '}':       --nOpenBrakets; break;
1634             case '{':       ++nOpenBrakets;  break;
1635             }
1636             if( nOpenBrakets && !bValidOle )
1637                 NextToken( nToken );
1638         }
1639     }
1640 
1641     if( !bValidOle && '}' != nToken )
1642         SkipGroup();
1643 
1644     SkipToken( -1 );        // die schliesende Klammer wird "oben" ausgewertet
1645 }
1646 #endif
1647 
1648 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
1649