1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <dcontact.hxx>
21 #include <dflyobj.hxx>
25 #include <rootfrm.hxx>
28 #include <textboxhelper.hxx>
29 #include <IDocumentState.hxx>
31 #include <sal/log.hxx>
32 #include <fmtanchr.hxx>
33 #include <fmtflcnt.hxx>
34 #include <flyfrms.hxx>
35 #include <txatbase.hxx>
40 #include <sortedobjs.hxx>
41 #include <officecfg/Office/Common.hxx>
42 #include <PostItMgr.hxx>
45 * class SwFlyPortion => we expect a frame-locale SwRect!
48 void SwFlyPortion::Paint( const SwTextPaintInfo
& ) const
52 bool SwFlyPortion::Format( SwTextFormatInfo
&rInf
)
54 OSL_ENSURE( GetFix() >= rInf
.X(), "SwFlyPortion::Format" );
56 // tabs must be expanded
57 if( rInf
.GetLastTab() )
58 rInf
.GetLastTab()->FormatEOL( rInf
);
60 rInf
.GetLast()->FormatEOL( rInf
);
61 PrtWidth( o3tl::narrowing
<sal_uInt16
>(GetFix() - rInf
.X() + PrtWidth()) );
64 OSL_ENSURE( Width(), "+SwFlyPortion::Format: a fly is a fly is a fly" );
69 rInf
.SetFly( nullptr );
70 rInf
.Width( rInf
.RealWidth() );
71 rInf
.GetParaPortion()->SetFly();
74 if( rInf
.GetIdx() < TextFrameIndex(rInf
.GetText().getLength())
75 && TextFrameIndex(1) < rInf
.GetIdx()
77 && ' ' == rInf
.GetChar( rInf
.GetIdx() )
78 && ' ' != rInf
.GetChar(rInf
.GetIdx() - TextFrameIndex(1))
79 && ( !rInf
.GetLast() || !rInf
.GetLast()->IsBreakPortion() ) )
81 SetBlankWidth( rInf
.GetTextSize(OUString(' ')).Width() );
82 SetLen(TextFrameIndex(1));
85 const sal_uInt16 nNewWidth
= o3tl::narrowing
<sal_uInt16
>(rInf
.X() + PrtWidth());
86 if( rInf
.Width() <= nNewWidth
)
89 if( nNewWidth
> rInf
.Width() )
91 PrtWidth( nNewWidth
- rInf
.Width() );
92 SetFixWidth( PrtWidth() );
99 bool SwFlyCntPortion::Format( SwTextFormatInfo
&rInf
)
101 bool bFull
= rInf
.Width() < rInf
.X() + PrtWidth();
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 const SwLinePortion
* pLastPor
= rInf
.GetLast();
112 const auto nLeft
= ( pLastPor
&&
113 ( pLastPor
->IsKernPortion() ||
114 pLastPor
->IsErgoSumPortion() ) ) ?
118 if( nLeft
== rInf
.X() && ! rInf
.GetFly() )
120 Width( rInf
.Width() );
121 bFull
= false; // so that notes can still be placed in this line
126 rInf
.SetNewLine( true );
129 SetLen(TextFrameIndex(0));
131 rInf
.GetLast()->FormatEOL( rInf
);
137 rInf
.GetParaPortion()->SetFly();
141 //TODO: improve documentation
142 /** move character-bound objects inside the given area
144 * This allows moving those objects from Master to Follow, or vice versa.
150 void SwTextFrame::MoveFlyInCnt(SwTextFrame
*pNew
,
151 TextFrameIndex
const nStart
, TextFrameIndex
const nEnd
)
153 SwSortedObjs
*pObjs
= GetDrawObjs();
154 if ( nullptr == pObjs
)
157 for ( size_t i
= 0; GetDrawObjs() && i
< pObjs
->size(); ++i
)
159 // Consider changed type of <SwSortedList> entries
160 SwAnchoredObject
* pAnchoredObj
= (*pObjs
)[i
];
161 const SwFormatAnchor
& rAnch
= pAnchoredObj
->GetFrameFormat().GetAnchor();
162 if (rAnch
.GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
164 const SwPosition
* pPos
= rAnch
.GetContentAnchor();
165 TextFrameIndex
const nIndex(MapModelToViewPos(*pPos
));
166 if (nStart
<= nIndex
&& nIndex
< nEnd
)
168 if ( auto pFlyFrame
= pAnchoredObj
->DynCastFlyFrame() )
170 RemoveFly( pFlyFrame
);
171 pNew
->AppendFly( pFlyFrame
);
173 else if ( dynamic_cast< const SwAnchoredDrawObject
*>( pAnchoredObj
) != nullptr )
175 RemoveDrawObj( *pAnchoredObj
);
176 pNew
->AppendDrawObj( *pAnchoredObj
);
184 TextFrameIndex
SwTextFrame::CalcFlyPos( SwFrameFormat
const * pSearch
)
186 sw::MergedAttrIter
iter(*this);
187 for (SwTextAttr
const* pHt
= iter
.NextAttr(); pHt
; pHt
= iter
.NextAttr())
189 if( RES_TXTATR_FLYCNT
== pHt
->Which() )
191 SwFrameFormat
* pFrameFormat
= pHt
->GetFlyCnt().GetFrameFormat();
192 if( pFrameFormat
== pSearch
)
194 return TextFrameIndex(pHt
->GetStart());
198 OSL_ENSURE(false, "CalcFlyPos: Not Found!");
199 return TextFrameIndex(COMPLETE_STRING
);
202 void sw::FlyContentPortion::Paint(const SwTextPaintInfo
& rInf
) const
205 // Re-paint everything at a CompletePaint call
206 SwRect
aRepaintRect(rInf
.GetPaintRect());
208 if(rInf
.GetTextFrame()->IsRightToLeft())
209 rInf
.GetTextFrame()->SwitchLTRtoRTL(aRepaintRect
);
211 if(rInf
.GetTextFrame()->IsVertical())
212 rInf
.GetTextFrame()->SwitchHorizontalToVertical(aRepaintRect
);
214 if(!((m_pFly
->IsCompletePaint() ||
215 m_pFly
->getFrameArea().Overlaps(aRepaintRect
)) &&
216 SwFlyFrame::IsPaint(m_pFly
->GetVirtDrawObj(), m_pFly
->getRootFrame()->GetCurrShell())))
219 SwRect
aRect(m_pFly
->getFrameArea());
220 if(!m_pFly
->IsCompletePaint())
221 aRect
.Intersection_(aRepaintRect
);
223 // GetFlyFrame() may change the layout mode at the output device.
225 SwLayoutModeModifier
aLayoutModeModifier(*rInf
.GetOut());
226 m_pFly
->PaintSwFrame(const_cast<vcl::RenderContext
&>(*rInf
.GetOut()), aRect
);
228 // track changes: cross out the image, if it is deleted
229 const SwFrame
*pFrame
= m_pFly
->Lower();
230 if ( GetAuthor() != std::string::npos
&& IsDeleted() && pFrame
)
232 SwRect
aPaintRect( pFrame
->GetPaintArea() );
234 const AntialiasingFlags
nFormerAntialiasing( rInf
.GetOut()->GetAntialiasing() );
235 const bool bIsAntiAliasing
= officecfg::Office::Common::Drawinglayer::AntiAliasing::get();
236 if ( bIsAntiAliasing
)
237 const_cast<vcl::RenderContext
&>(*rInf
.GetOut()).SetAntialiasing(AntialiasingFlags::Enable
);
238 tools::Long startX
= aPaintRect
.Left( ), endX
= aPaintRect
.Right();
239 tools::Long startY
= aPaintRect
.Top( ), endY
= aPaintRect
.Bottom();
240 const_cast<vcl::RenderContext
&>(*rInf
.GetOut()).SetLineColor(
241 SwPostItMgr::GetColorAnchor(GetAuthor()) );
242 const_cast<vcl::RenderContext
&>(*rInf
.GetOut()).DrawLine(Point(startX
, startY
), Point(endX
, endY
));
243 const_cast<vcl::RenderContext
&>(*rInf
.GetOut()).DrawLine(Point(startX
, endY
), Point(endX
, startY
));
244 if ( bIsAntiAliasing
)
245 const_cast<vcl::RenderContext
&>(*rInf
.GetOut()).SetAntialiasing(nFormerAntialiasing
);
248 const_cast<SwTextPaintInfo
&>(rInf
).GetRefDev()->SetLayoutMode(rInf
.GetOut()->GetLayoutMode());
250 // As the OutputDevice might be anything, the font must be re-selected.
251 // Being in const method should not be a problem.
252 const_cast<SwTextPaintInfo
&>(rInf
).SelectFont();
254 assert(rInf
.GetVsh());
255 SAL_WARN_IF(rInf
.GetVsh()->GetOut() != rInf
.GetOut(), "sw.core", "SwFlyCntPortion::Paint: Outdev has changed");
257 const_cast<SwTextPaintInfo
&>(rInf
).SetOut(rInf
.GetVsh()->GetOut());
260 void sw::DrawFlyCntPortion::Paint(const SwTextPaintInfo
&) const
262 if(!m_pContact
->GetAnchorFrame())
264 // No direct positioning of the drawing object is needed
265 m_pContact
->ConnectToLayout();
270 * Use the dimensions of pFly->OutRect()
272 SwFlyCntPortion::SwFlyCntPortion()
275 , m_nAuthor(std::string::npos
)
276 , m_eAlign(sw::LineAlign::NONE
)
278 mnLineLength
= TextFrameIndex(1);
279 SetWhichPor(PortionType::FlyCnt
);
282 sw::FlyContentPortion::FlyContentPortion(SwFlyInContentFrame
* pFly
)
285 SAL_WARN_IF(!pFly
, "sw.core", "SwFlyCntPortion::SwFlyCntPortion: no SwFlyInContentFrame!");
288 sw::DrawFlyCntPortion::DrawFlyCntPortion(SwFrameFormat
const & rFormat
)
289 : m_pContact(nullptr)
291 rFormat
.CallSwClientNotify(sw::CreatePortionHint(&m_pContact
));
295 sw::FlyContentPortion
* sw::FlyContentPortion::Create(const SwTextFrame
& rFrame
, SwFlyInContentFrame
* pFly
, const Point
& rBase
, tools::Long nLnAscent
, tools::Long nLnDescent
, tools::Long nFlyAsc
, tools::Long nFlyDesc
, AsCharFlags nFlags
)
297 auto pNew(new sw::FlyContentPortion(pFly
));
298 pNew
->SetBase(rFrame
, rBase
, nLnAscent
, nLnDescent
, nFlyAsc
, nFlyDesc
, nFlags
| AsCharFlags::UlSpace
| AsCharFlags::Init
);
302 sw::DrawFlyCntPortion
* sw::DrawFlyCntPortion::Create(const SwTextFrame
& rFrame
, SwFrameFormat
const & rFormat
, const Point
& rBase
, tools::Long nLnAscent
, tools::Long nLnDescent
, tools::Long nFlyAsc
, tools::Long nFlyDesc
, AsCharFlags nFlags
)
304 auto pNew(new DrawFlyCntPortion(rFormat
));
305 pNew
->SetBase(rFrame
, rBase
, nLnAscent
, nLnDescent
, nFlyAsc
, nFlyDesc
, nFlags
| AsCharFlags::UlSpace
| AsCharFlags::Init
);
309 sw::DrawFlyCntPortion::~DrawFlyCntPortion() {};
310 sw::FlyContentPortion::~FlyContentPortion() {};
312 SdrObject
* sw::FlyContentPortion::GetSdrObj(const SwTextFrame
&)
314 return m_pFly
->GetVirtDrawObj();
317 SdrObject
* sw::DrawFlyCntPortion::GetSdrObj(const SwTextFrame
& rFrame
)
320 // Determine drawing object ('master' or 'virtual') by frame
321 pSdrObj
= m_pContact
->GetDrawObjectByAnchorFrame(rFrame
);
324 SAL_WARN("sw.core", "SwFlyCntPortion::SetBase(..) - No drawing object found by <GetDrawContact()->GetDrawObjectByAnchorFrame( rFrame )>");
325 pSdrObj
= m_pContact
->GetMaster();
328 // Call <SwAnchoredDrawObject::MakeObjPos()> to assure that flag at
329 // the <DrawFrameFormat> and at the <SwAnchoredDrawObject> instance are
332 m_pContact
->GetAnchoredObj(pSdrObj
)->MakeObjPos();
337 * After setting the RefPoints, the ascent needs to be recalculated
338 * because it is dependent on RelPos
340 * @param rBase CAUTION: needs to be an absolute value!
342 void SwFlyCntPortion::SetBase( const SwTextFrame
& rFrame
, const Point
&rBase
,
343 tools::Long nLnAscent
, tools::Long nLnDescent
,
344 tools::Long nFlyAsc
, tools::Long nFlyDesc
,
347 // Use new class to position object
348 // Determine drawing object
349 SdrObject
* pSdrObj
= GetSdrObj(rFrame
);
354 objectpositioning::SwAsCharAnchoredObjectPosition
aObjPositioning(
357 nLnAscent
, nLnDescent
, nFlyAsc
, nFlyDesc
);
359 // Scope of local variable <aObjPosInProgress>
361 SwObjPositioningInProgress
aObjPosInProgress( *pSdrObj
);
362 aObjPositioning
.CalcPosition();
365 if (auto pFormat
= FindFrameFormat(pSdrObj
))
367 if (pFormat
->GetOtherTextBoxFormats()
368 && pFormat
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
370 // TODO: Improve security with moving this sync call to other place,
371 // where it works for typing but not during layout calc.
372 const bool bModified
= pFormat
->GetDoc()->getIDocumentState().IsEnableSetModified();
373 pFormat
->GetDoc()->getIDocumentState().SetEnableSetModified(false);
374 SwTextBoxHelper::synchronizeGroupTextBoxProperty(SwTextBoxHelper::changeAnchor
, pFormat
,
375 pFormat
->FindRealSdrObject());
376 SwTextBoxHelper::synchronizeGroupTextBoxProperty(SwTextBoxHelper::syncTextBoxSize
,
377 pFormat
, pFormat
->FindRealSdrObject());
378 pFormat
->GetDoc()->getIDocumentState().SetEnableSetModified(bModified
);
382 SetAlign( aObjPositioning
.GetLineAlignment() );
384 m_aRef
= aObjPositioning
.GetAnchorPos();
385 if( nFlags
& AsCharFlags::Rotate
)
386 SvXSize( aObjPositioning
.GetObjBoundRectInclSpacing().SSize() );
388 SvLSize( aObjPositioning
.GetObjBoundRectInclSpacing().SSize() );
391 // GetRelPosY returns the relative position to baseline (if 0, the
392 // upper border of the FlyCnt if on the baseline of a line)
393 SwTwips nRelPos
= aObjPositioning
.GetRelPosY();
397 if( mnAscent
> Height() )
403 Height( Height() + o3tl::narrowing
<sal_uInt16
>(nRelPos
) );
413 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */