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 "dcontact.hxx"
21 : #include "dflyobj.hxx"
22 : #include "pam.hxx"
23 : #include <portab.hxx>
24 : #include "flyfrm.hxx"
25 : #include "rootfrm.hxx"
26 : #include "frmfmt.hxx"
27 : #include "viewsh.hxx"
28 : #include "textboxhelper.hxx"
29 :
30 : #include <vcl/outdev.hxx>
31 : #include <editeng/lrspitem.hxx>
32 : #include <editeng/ulspitem.hxx>
33 : #include <fmtanchr.hxx>
34 : #include <fmtflcnt.hxx>
35 : #include <fmtornt.hxx>
36 : #include <frmatr.hxx>
37 : #include "flyfrms.hxx"
38 : #include "txatbase.hxx"
39 : #include "porfly.hxx"
40 : #include "porlay.hxx"
41 : #include "inftxt.hxx"
42 :
43 : #include <sortedobjs.hxx>
44 :
45 : /**
46 : * class SwFlyPortion => we expect a frame-locale SwRect!
47 : */
48 :
49 57 : void SwFlyPortion::Paint( const SwTextPaintInfo& ) const
50 : {
51 57 : }
52 :
53 472 : bool SwFlyPortion::Format( SwTextFormatInfo &rInf )
54 : {
55 : OSL_ENSURE( Fix() >= rInf.X(), "SwFlyPortion::Format" );
56 :
57 : // tabs must be expanded
58 472 : if( rInf.GetLastTab() )
59 0 : rInf.GetLastTab()->FormatEOL( rInf );
60 :
61 472 : rInf.GetLast()->FormatEOL( rInf );
62 472 : PrtWidth( static_cast<sal_uInt16>(Fix() - rInf.X() + PrtWidth()) );
63 472 : if( !Width() )
64 : {
65 : OSL_ENSURE( Width(), "+SwFlyPortion::Format: a fly is a fly is a fly" );
66 0 : Width(1);
67 : }
68 :
69 : // resetting
70 472 : rInf.SetFly( 0 );
71 472 : rInf.Width( rInf.RealWidth() );
72 472 : rInf.GetParaPortion()->SetFly( true );
73 :
74 : // trailing blank:
75 1262 : if( rInf.GetIdx() < rInf.GetText().getLength() && 1 < rInf.GetIdx()
76 191 : && !rInf.GetRest()
77 191 : && ' ' == rInf.GetChar( rInf.GetIdx() )
78 0 : && ' ' != rInf.GetChar( rInf.GetIdx() - 1 )
79 472 : && ( !rInf.GetLast() || !rInf.GetLast()->IsBreakPortion() ) )
80 : {
81 0 : SetBlankWidth( rInf.GetTextSize(OUString(' ')).Width() );
82 0 : SetLen( 1 );
83 : }
84 :
85 472 : const sal_uInt16 nNewWidth = static_cast<sal_uInt16>(rInf.X() + PrtWidth());
86 472 : if( rInf.Width() <= nNewWidth )
87 : {
88 167 : Truncate();
89 167 : if( nNewWidth > rInf.Width() )
90 : {
91 0 : PrtWidth( nNewWidth - rInf.Width() );
92 0 : SetFixWidth( PrtWidth() );
93 : }
94 167 : return true;
95 : }
96 305 : return false;
97 : }
98 :
99 2200 : bool SwFlyCntPortion::Format( SwTextFormatInfo &rInf )
100 : {
101 2200 : bool bFull = rInf.Width() < rInf.X() + PrtWidth();
102 :
103 2200 : if( bFull )
104 : {
105 : // If the line is full, and the character-bound frame is at
106 : // the beginning of a line
107 : // If it is not possible to side step into a Fly
108 : // "Begin of line" criteria ( ! rInf.X() ) has to be extended.
109 : // KerningPortions at beginning of line, e.g., for grid layout
110 : // must be considered.
111 292 : const SwLinePortion* pLastPor = rInf.GetLast();
112 292 : const sal_uInt16 nLeft = ( pLastPor &&
113 584 : ( pLastPor->IsKernPortion() ||
114 292 : pLastPor->IsErgoSumPortion() ) ) ?
115 0 : pLastPor->Width() :
116 292 : 0;
117 :
118 292 : if( nLeft == rInf.X() && ! rInf.GetFly() )
119 : {
120 173 : Width( rInf.Width() );
121 173 : bFull = false; // so that notes can still be placed in this line
122 : }
123 : else
124 : {
125 119 : if( !rInf.GetFly() )
126 115 : rInf.SetNewLine( true );
127 119 : Width(0);
128 119 : SetAscent(0);
129 119 : SetLen(0);
130 119 : if( rInf.GetLast() )
131 119 : rInf.GetLast()->FormatEOL( rInf );
132 :
133 119 : return bFull;
134 : }
135 : }
136 :
137 2081 : rInf.GetParaPortion()->SetFly( true );
138 2081 : return bFull;
139 : }
140 :
141 : //TODO: improve documentation
142 : /** move character-bound objects inside the given area
143 : *
144 : * This allows moving those objects from Master to Follow, or vice versa.
145 : *
146 : * @param pNew
147 : * @param nStart
148 : * @param nEnd
149 : */
150 1976 : void SwTextFrm::MoveFlyInCnt( SwTextFrm *pNew, sal_Int32 nStart, sal_Int32 nEnd )
151 : {
152 1976 : SwSortedObjs *pObjs = 0L;
153 1976 : if ( 0 != (pObjs = GetDrawObjs()) )
154 : {
155 164 : for ( size_t i = 0; GetDrawObjs() && i < pObjs->size(); ++i )
156 : {
157 : // Consider changed type of <SwSortedList> entries
158 100 : SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
159 100 : const SwFormatAnchor& rAnch = pAnchoredObj->GetFrameFormat().GetAnchor();
160 100 : if (rAnch.GetAnchorId() == FLY_AS_CHAR)
161 : {
162 91 : const SwPosition* pPos = rAnch.GetContentAnchor();
163 91 : const sal_Int32 nIdx = pPos->nContent.GetIndex();
164 91 : if ( nIdx >= nStart && nEnd > nIdx )
165 : {
166 64 : if ( pAnchoredObj->ISA(SwFlyFrm) )
167 : {
168 38 : RemoveFly( static_cast<SwFlyFrm*>(pAnchoredObj) );
169 38 : pNew->AppendFly( static_cast<SwFlyFrm*>(pAnchoredObj) );
170 : }
171 26 : else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) )
172 : {
173 26 : RemoveDrawObj( *pAnchoredObj );
174 26 : pNew->AppendDrawObj( *pAnchoredObj );
175 : }
176 64 : --i;
177 : }
178 : }
179 : }
180 : }
181 1976 : }
182 :
183 276 : sal_Int32 SwTextFrm::CalcFlyPos( SwFrameFormat* pSearch )
184 : {
185 276 : SwpHints* pHints = GetTextNode()->GetpSwpHints();
186 : OSL_ENSURE( pHints, "CalcFlyPos: Why me?" );
187 276 : if( !pHints )
188 0 : return COMPLETE_STRING;
189 276 : SwTextAttr* pFound = NULL;
190 1157 : for ( size_t i = 0; i < pHints->Count(); ++i )
191 : {
192 881 : SwTextAttr *pHt = pHints->GetTextHint( i );
193 881 : if( RES_TXTATR_FLYCNT == pHt->Which() )
194 : {
195 499 : SwFrameFormat* pFrameFormat = pHt->GetFlyCnt().GetFrameFormat();
196 499 : if( pFrameFormat == pSearch )
197 276 : pFound = pHt;
198 : }
199 : }
200 : OSL_ENSURE( pHints, "CalcFlyPos: Not Found!" );
201 276 : if( !pFound )
202 0 : return COMPLETE_STRING;
203 276 : return pFound->GetStart();
204 : }
205 :
206 7684 : void SwFlyCntPortion::Paint( const SwTextPaintInfo &rInf ) const
207 : {
208 7684 : if( bDraw )
209 : {
210 7562 : if( !static_cast<SwDrawContact*>(pContact)->GetAnchorFrm() )
211 : {
212 : // No direct positioning of the drawing object is needed
213 2 : SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(pContact);
214 2 : pDrawContact->ConnectToLayout();
215 : }
216 : }
217 : else
218 : {
219 : // Baseline output
220 : // Re-paint everything at a CompletePaint call
221 122 : SwRect aRepaintRect( rInf.GetPaintRect() );
222 :
223 122 : if ( rInf.GetTextFrm()->IsRightToLeft() )
224 0 : rInf.GetTextFrm()->SwitchLTRtoRTL( aRepaintRect );
225 :
226 122 : if ( rInf.GetTextFrm()->IsVertical() )
227 0 : rInf.GetTextFrm()->SwitchHorizontalToVertical( aRepaintRect );
228 :
229 366 : if( (GetFlyFrm()->IsCompletePaint() ||
230 237 : GetFlyFrm()->Frm().IsOver( aRepaintRect )) &&
231 115 : SwFlyFrm::IsPaint( const_cast<SwVirtFlyDrawObj*>(GetFlyFrm()->GetVirtDrawObj()),
232 230 : GetFlyFrm()->getRootFrm()->GetCurrShell() ))
233 : {
234 115 : SwRect aRect( GetFlyFrm()->Frm() );
235 115 : if( !GetFlyFrm()->IsCompletePaint() )
236 115 : aRect._Intersection( aRepaintRect );
237 :
238 : // GetFlyFrm() may change the layout mode at the output device.
239 : {
240 115 : SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
241 115 : GetFlyFrm()->Paint( aRect );
242 : }
243 : ((SwTextPaintInfo&)rInf).GetRefDev()->SetLayoutMode(
244 115 : rInf.GetOut()->GetLayoutMode() );
245 :
246 : // As the OutputDevice might be anything, the font must be re-selected.
247 : // Being in const method should not be a problem.
248 115 : ((SwTextPaintInfo&)rInf).SelectFont();
249 :
250 : OSL_ENSURE( ! rInf.GetVsh() || rInf.GetVsh()->GetOut() == rInf.GetOut(),
251 : "SwFlyCntPortion::Paint: Outdev has changed" );
252 115 : if( rInf.GetVsh() )
253 115 : ((SwTextPaintInfo&)rInf).SetOut( rInf.GetVsh()->GetOut() );
254 : }
255 : }
256 7684 : }
257 :
258 : /**
259 : * Use the dimensions of pFly->OutRect()
260 : */
261 1342 : SwFlyCntPortion::SwFlyCntPortion( const SwTextFrm& rFrm,
262 : SwFlyInCntFrm *pFly, const Point &rBase,
263 : long nLnAscent, long nLnDescent,
264 : long nFlyAsc, long nFlyDesc,
265 : objectpositioning::AsCharFlags nFlags ) :
266 : pContact( pFly ),
267 : bDraw( false ),
268 : bMax( false ),
269 1342 : nAlign( 0 )
270 : {
271 : OSL_ENSURE( pFly, "SwFlyCntPortion::SwFlyCntPortion: no SwFlyInCntFrm!" );
272 1342 : nLineLength = 1;
273 1342 : nFlags |= AS_CHAR_ULSPACE | AS_CHAR_INIT;
274 1342 : SetBase( rFrm, rBase, nLnAscent, nLnDescent, nFlyAsc, nFlyDesc, nFlags );
275 1342 : SetWhichPor( POR_FLYCNT );
276 1342 : }
277 :
278 858 : SwFlyCntPortion::SwFlyCntPortion( const SwTextFrm& rFrm,
279 : SwDrawContact *pDrawContact, const Point &rBase,
280 : long nLnAscent, long nLnDescent,
281 : long nFlyAsc, long nFlyDesc,
282 : objectpositioning::AsCharFlags nFlags ) :
283 : pContact( pDrawContact ),
284 : bDraw( true ),
285 : bMax( false ),
286 858 : nAlign( 0 )
287 : {
288 : OSL_ENSURE( pDrawContact, "SwFlyCntPortion::SwFlyCntPortion: no SwDrawContact!" );
289 858 : if( !pDrawContact->GetAnchorFrm() )
290 : {
291 : // No direct positioning needed any more
292 94 : pDrawContact->ConnectToLayout();
293 :
294 : // Move object to visible layer
295 94 : pDrawContact->MoveObjToVisibleLayer( pDrawContact->GetMaster() );
296 : }
297 858 : nLineLength = 1;
298 858 : nFlags |= AS_CHAR_ULSPACE | AS_CHAR_INIT;
299 :
300 858 : SetBase( rFrm, rBase, nLnAscent, nLnDescent, nFlyAsc, nFlyDesc, nFlags );
301 :
302 858 : SetWhichPor( POR_FLYCNT );
303 858 : }
304 :
305 : /**
306 : * After setting the RefPoints, the ascent needs to be recalculated
307 : * because it is dependent on RelPos
308 : *
309 : * @param rBase CAUTION: needs to be an absolute value!
310 : */
311 7116 : void SwFlyCntPortion::SetBase( const SwTextFrm& rFrm, const Point &rBase,
312 : long nLnAscent, long nLnDescent,
313 : long nFlyAsc, long nFlyDesc,
314 : objectpositioning::AsCharFlags nFlags )
315 : {
316 : // Use new class to position object
317 : // Determine drawing object
318 7116 : SdrObject* pSdrObj = 0L;
319 7116 : if( bDraw )
320 : {
321 : // Determine drawing object ('master' or 'virtual') by frame
322 2501 : pSdrObj = GetDrawContact()->GetDrawObjectByAnchorFrm( rFrm );
323 2501 : if ( !pSdrObj )
324 : {
325 : OSL_FAIL( "SwFlyCntPortion::SetBase(..) - No drawing object found by <GetDrawContact()->GetDrawObjectByAnchorFrm( rFrm )>" );
326 0 : pSdrObj = GetDrawContact()->GetMaster();
327 : }
328 :
329 : // Call <SwAnchoredDrawObject::MakeObjPos()> to assure that flag at
330 : // the <DrawFrameFormat> and at the <SwAnchoredDrawObject> instance are
331 : // correctly set
332 2501 : if ( pSdrObj )
333 : {
334 2501 : GetDrawContact()->GetAnchoredObj( pSdrObj )->MakeObjPos();
335 : }
336 : }
337 : else
338 : {
339 4615 : pSdrObj = GetFlyFrm()->GetVirtDrawObj();
340 : }
341 :
342 7116 : if (!pSdrObj)
343 7116 : return;
344 :
345 : // position object
346 : objectpositioning::SwAsCharAnchoredObjectPosition aObjPositioning(
347 : *pSdrObj,
348 : rBase, nFlags,
349 7116 : nLnAscent, nLnDescent, nFlyAsc, nFlyDesc );
350 :
351 : // Scope of local variable <aObjPosInProgress>
352 : {
353 7116 : SwObjPositioningInProgress aObjPosInProgress( *pSdrObj );
354 7116 : aObjPositioning.CalcPosition();
355 : }
356 :
357 7116 : SwFrameFormat* pShape = FindFrameFormat(pSdrObj);
358 7116 : const SwFormatAnchor& rAnchor(pShape->GetAnchor());
359 7116 : if (rAnchor.GetAnchorId() == FLY_AS_CHAR)
360 : {
361 : // This is an inline draw shape, see if it has a textbox.
362 7116 : SwFrameFormat* pTextBox = SwTextBoxHelper::findTextBox(pShape);
363 7116 : if (pTextBox)
364 : {
365 : // It has, so look up its text rectangle, and adjust the position
366 : // of the textbox accordingly.
367 87 : Rectangle aTextRectangle = SwTextBoxHelper::getTextRectangle(pShape);
368 :
369 87 : SwFormatHoriOrient aHori(pTextBox->GetHoriOrient());
370 87 : aHori.SetHoriOrient(css::text::HoriOrientation::NONE);
371 87 : sal_Int32 nLeft = aTextRectangle.getX() - rFrm.Frm().Left();
372 87 : aHori.SetPos(nLeft);
373 :
374 174 : SwFormatVertOrient aVert(pTextBox->GetVertOrient());
375 87 : aVert.SetVertOrient(css::text::VertOrientation::NONE);
376 87 : sal_Int32 nTop = aTextRectangle.getY() - rFrm.Frm().Top() - nFlyAsc;
377 87 : aVert.SetPos(nTop);
378 :
379 87 : pTextBox->LockModify();
380 87 : pTextBox->SetFormatAttr(aHori);
381 87 : pTextBox->SetFormatAttr(aVert);
382 174 : pTextBox->UnlockModify();
383 : }
384 : }
385 :
386 7116 : SetAlign( aObjPositioning.GetLineAlignment() );
387 :
388 7116 : aRef = aObjPositioning.GetAnchorPos();
389 7116 : if( nFlags & AS_CHAR_ROTATE )
390 0 : SvXSize( aObjPositioning.GetObjBoundRectInclSpacing().SSize() );
391 : else
392 7116 : SvLSize( aObjPositioning.GetObjBoundRectInclSpacing().SSize() );
393 7116 : if( Height() )
394 : {
395 : // GetRelPosY returns the relative position to baseline (if 0, the
396 : // upper border of the FlyCnt if on the baseline of a line)
397 7116 : SwTwips nRelPos = aObjPositioning.GetRelPosY();
398 7116 : if ( nRelPos < 0 )
399 : {
400 4882 : nAscent = static_cast<sal_uInt16>(-nRelPos);
401 4882 : if( nAscent > Height() )
402 54 : Height( nAscent );
403 : }
404 : else
405 : {
406 2234 : nAscent = 0;
407 2234 : Height( Height() + static_cast<sal_uInt16>(nRelPos) );
408 : }
409 : }
410 : else
411 : {
412 0 : Height( 1 );
413 0 : nAscent = 0;
414 7116 : }
415 : }
416 :
417 0 : sal_Int32 SwFlyCntPortion::GetFlyCrsrOfst( const sal_uInt16 nOfst,
418 : const Point &rPoint, SwPosition *pPos, SwCrsrMoveState* pCMS ) const
419 : {
420 : // As the FlyCnt are not attached to the side, their GetCrsrOfst() will
421 : // not be called.
422 : // In order to reduce management overhead for the layout page, the paragraph
423 : // calls the FlyFrm's GetCrsrOfst() only when needed
424 0 : Point aPoint( rPoint );
425 0 : if( !pPos || bDraw || !( GetFlyFrm()->GetCrsrOfst( pPos, aPoint, pCMS ) ) )
426 0 : return SwLinePortion::GetCrsrOfst( nOfst );
427 : else
428 0 : return 0;
429 : }
430 :
431 29 : sal_Int32 SwFlyCntPortion::GetCrsrOfst( const sal_uInt16 nOfst ) const
432 : {
433 : // OSL_FAIL("SwFlyCntPortion::GetCrsrOfst: use GetFlyCrsrOfst()");
434 29 : return SwLinePortion::GetCrsrOfst( nOfst );
435 177 : }
436 :
437 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|