summaryrefslogtreecommitdiffstats
path: root/sw/source/core/text/porfly.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/porfly.cxx')
-rw-r--r--sw/source/core/text/porfly.cxx423
1 files changed, 423 insertions, 0 deletions
diff --git a/sw/source/core/text/porfly.cxx b/sw/source/core/text/porfly.cxx
new file mode 100644
index 0000000000..14d1bf6eaa
--- /dev/null
+++ b/sw/source/core/text/porfly.cxx
@@ -0,0 +1,423 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dcontact.hxx>
+#include <dflyobj.hxx>
+#include <pam.hxx>
+#include "portab.hxx"
+#include <flyfrm.hxx>
+#include <rootfrm.hxx>
+#include <frmfmt.hxx>
+#include <viewsh.hxx>
+#include <textboxhelper.hxx>
+#include <IDocumentState.hxx>
+
+#include <sal/log.hxx>
+#include <fmtanchr.hxx>
+#include <fmtflcnt.hxx>
+#include <flyfrms.hxx>
+#include <txatbase.hxx>
+#include "porfly.hxx"
+#include "porlay.hxx"
+#include "inftxt.hxx"
+
+#include <sortedobjs.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <PostItMgr.hxx>
+
+/**
+ * class SwFlyPortion => we expect a frame-locale SwRect!
+ */
+
+void SwFlyPortion::Paint( const SwTextPaintInfo& ) const
+{
+}
+
+bool SwFlyPortion::Format( SwTextFormatInfo &rInf )
+{
+ OSL_ENSURE( GetFix() >= rInf.X(), "SwFlyPortion::Format" );
+
+ // tabs must be expanded
+ if( rInf.GetLastTab() )
+ rInf.GetLastTab()->FormatEOL( rInf );
+
+ rInf.GetLast()->FormatEOL( rInf );
+
+ SetBlankWidth(0);
+ if (auto blankWidth = rInf.GetLast()->ExtraBlankWidth())
+ {
+ // Swallow previous blank width
+ SetBlankWidth(blankWidth);
+ rInf.GetLast()->ExtraBlankWidth(0);
+ rInf.X(rInf.X() - blankWidth); // Step back
+ }
+
+ PrtWidth( o3tl::narrowing<sal_uInt16>(GetFix() - rInf.X() + PrtWidth()) );
+ if( !Width() )
+ {
+ OSL_ENSURE( Width(), "+SwFlyPortion::Format: a fly is a fly is a fly" );
+ Width(1);
+ }
+
+ // resetting
+ rInf.SetFly( nullptr );
+ rInf.Width( rInf.RealWidth() );
+ rInf.GetParaPortion()->SetFly();
+
+ // trailing blank:
+ if( rInf.GetIdx() < TextFrameIndex(rInf.GetText().getLength())
+ && TextFrameIndex(1) < rInf.GetIdx()
+ && !rInf.GetRest()
+ && ' ' == rInf.GetChar( rInf.GetIdx() )
+ && ' ' != rInf.GetChar(rInf.GetIdx() - TextFrameIndex(1))
+ && ( !rInf.GetLast() || !rInf.GetLast()->IsBreakPortion() ) )
+ {
+ SetBlankWidth(GetBlankWidth() + rInf.GetTextSize(OUString(' ')).Width());
+ SetLen(TextFrameIndex(1));
+ }
+
+ const sal_uInt16 nNewWidth = o3tl::narrowing<sal_uInt16>(rInf.X() + PrtWidth());
+ if( rInf.Width() <= nNewWidth )
+ {
+ Truncate();
+ if( nNewWidth > rInf.Width() )
+ {
+ PrtWidth( nNewWidth - rInf.Width() );
+ SetFixWidth( PrtWidth() );
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SwFlyCntPortion::Format( SwTextFormatInfo &rInf )
+{
+ bool bFull = rInf.Width() < rInf.X() + PrtWidth();
+
+ if( bFull )
+ {
+ // If the line is full, and the character-bound frame is at
+ // the beginning of a line
+ // If it is not possible to side step into a Fly
+ // "Begin of line" criteria ( ! rInf.X() ) has to be extended.
+ // KerningPortions at beginning of line, e.g., for grid layout
+ // must be considered.
+ const SwLinePortion* pLastPor = rInf.GetLast();
+ const auto nLeft = ( pLastPor &&
+ ( pLastPor->IsKernPortion() ||
+ pLastPor->IsErgoSumPortion() ) ) ?
+ pLastPor->Width() :
+ 0;
+
+ if( nLeft == rInf.X() && ! rInf.GetFly() )
+ {
+ Width( rInf.Width() );
+ bFull = false; // so that notes can still be placed in this line
+ }
+ else
+ {
+ if( !rInf.GetFly() )
+ rInf.SetNewLine( true );
+ Width(0);
+ SetAscent(0);
+ SetLen(TextFrameIndex(0));
+ if( rInf.GetLast() )
+ rInf.GetLast()->FormatEOL( rInf );
+
+ return bFull;
+ }
+ }
+
+ rInf.GetParaPortion()->SetFly();
+ return bFull;
+}
+
+//TODO: improve documentation
+/** move character-bound objects inside the given area
+ *
+ * This allows moving those objects from Master to Follow, or vice versa.
+ *
+ * @param pNew
+ * @param nStart
+ * @param nEnd
+ */
+void SwTextFrame::MoveFlyInCnt(SwTextFrame *pNew,
+ TextFrameIndex const nStart, TextFrameIndex const nEnd)
+{
+ SwSortedObjs *pObjs = GetDrawObjs();
+ if ( nullptr == pObjs )
+ return;
+
+ for ( size_t i = 0; GetDrawObjs() && i < pObjs->size(); ++i )
+ {
+ // Consider changed type of <SwSortedList> entries
+ SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
+ const SwFormatAnchor& rAnch = pAnchoredObj->GetFrameFormat().GetAnchor();
+ if (rAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+ {
+ const SwPosition* pPos = rAnch.GetContentAnchor();
+ TextFrameIndex const nIndex(MapModelToViewPos(*pPos));
+ if (nStart <= nIndex && nIndex < nEnd)
+ {
+ if ( auto pFlyFrame = pAnchoredObj->DynCastFlyFrame() )
+ {
+ RemoveFly( pFlyFrame );
+ pNew->AppendFly( pFlyFrame );
+ }
+ else if ( dynamic_cast< const SwAnchoredDrawObject *>( pAnchoredObj ) != nullptr )
+ {
+ RemoveDrawObj( *pAnchoredObj );
+ pNew->AppendDrawObj( *pAnchoredObj );
+ }
+ --i;
+ }
+ }
+ }
+}
+
+TextFrameIndex SwTextFrame::CalcFlyPos( SwFrameFormat const * pSearch )
+{
+ sw::MergedAttrIter iter(*this);
+ for (SwTextAttr const* pHt = iter.NextAttr(); pHt; pHt = iter.NextAttr())
+ {
+ if( RES_TXTATR_FLYCNT == pHt->Which() )
+ {
+ SwFrameFormat* pFrameFormat = pHt->GetFlyCnt().GetFrameFormat();
+ if( pFrameFormat == pSearch )
+ {
+ return TextFrameIndex(pHt->GetStart());
+ }
+ }
+ }
+ OSL_ENSURE(false, "CalcFlyPos: Not Found!");
+ return TextFrameIndex(COMPLETE_STRING);
+}
+
+void sw::FlyContentPortion::Paint(const SwTextPaintInfo& rInf) const
+{
+ // Baseline output
+ // Re-paint everything at a CompletePaint call
+ SwRect aRepaintRect(rInf.GetPaintRect());
+
+ if(rInf.GetTextFrame()->IsRightToLeft())
+ rInf.GetTextFrame()->SwitchLTRtoRTL(aRepaintRect);
+
+ if(rInf.GetTextFrame()->IsVertical())
+ rInf.GetTextFrame()->SwitchHorizontalToVertical(aRepaintRect);
+
+ if(!((m_pFly->IsCompletePaint() ||
+ m_pFly->getFrameArea().Overlaps(aRepaintRect)) &&
+ SwFlyFrame::IsPaint(m_pFly->GetVirtDrawObj(), m_pFly->getRootFrame()->GetCurrShell())))
+ return;
+
+ SwRect aRect(m_pFly->getFrameArea());
+ if(!m_pFly->IsCompletePaint())
+ aRect.Intersection_(aRepaintRect);
+
+ // GetFlyFrame() may change the layout mode at the output device.
+ {
+ SwLayoutModeModifier aLayoutModeModifier(*rInf.GetOut());
+ m_pFly->PaintSwFrame(const_cast<vcl::RenderContext&>(*rInf.GetOut()), aRect);
+
+ // track changes: cross out the image, if it is deleted
+ const SwFrame *pFrame = m_pFly->Lower();
+ if ( GetAuthor() != std::string::npos && IsDeleted() && pFrame )
+ {
+ SwRect aPaintRect( pFrame->GetPaintArea() );
+
+ const AntialiasingFlags nFormerAntialiasing( rInf.GetOut()->GetAntialiasing() );
+ const bool bIsAntiAliasing = officecfg::Office::Common::Drawinglayer::AntiAliasing::get();
+ if ( bIsAntiAliasing )
+ const_cast<vcl::RenderContext&>(*rInf.GetOut()).SetAntialiasing(AntialiasingFlags::Enable);
+ tools::Long startX = aPaintRect.Left( ), endX = aPaintRect.Right();
+ tools::Long startY = aPaintRect.Top( ), endY = aPaintRect.Bottom();
+ const_cast<vcl::RenderContext&>(*rInf.GetOut()).SetLineColor(
+ SwPostItMgr::GetColorAnchor(GetAuthor()) );
+ const_cast<vcl::RenderContext&>(*rInf.GetOut()).DrawLine(Point(startX, startY), Point(endX, endY));
+ const_cast<vcl::RenderContext&>(*rInf.GetOut()).DrawLine(Point(startX, endY), Point(endX, startY));
+ if ( bIsAntiAliasing )
+ const_cast<vcl::RenderContext&>(*rInf.GetOut()).SetAntialiasing(nFormerAntialiasing);
+ }
+ }
+ const_cast<SwTextPaintInfo&>(rInf).GetRefDev()->SetLayoutMode(rInf.GetOut()->GetLayoutMode());
+
+ // As the OutputDevice might be anything, the font must be re-selected.
+ // Being in const method should not be a problem.
+ const_cast<SwTextPaintInfo&>(rInf).SelectFont();
+
+ assert(rInf.GetVsh());
+ SAL_WARN_IF(rInf.GetVsh()->GetOut() != rInf.GetOut(), "sw.core", "SwFlyCntPortion::Paint: Outdev has changed");
+ if(rInf.GetVsh())
+ const_cast<SwTextPaintInfo&>(rInf).SetOut(rInf.GetVsh()->GetOut());
+}
+
+void sw::DrawFlyCntPortion::Paint(const SwTextPaintInfo&) const
+{
+ if(!m_pContact->GetAnchorFrame())
+ {
+ // No direct positioning of the drawing object is needed
+ m_pContact->ConnectToLayout();
+ }
+}
+
+/**
+ * Use the dimensions of pFly->OutRect()
+ */
+SwFlyCntPortion::SwFlyCntPortion()
+ : m_bMax(false)
+ , m_bDeleted(false)
+ , m_nAuthor(std::string::npos)
+ , m_eAlign(sw::LineAlign::NONE)
+{
+ mnLineLength = TextFrameIndex(1);
+ SetWhichPor(PortionType::FlyCnt);
+}
+
+sw::FlyContentPortion::FlyContentPortion(SwFlyInContentFrame* pFly)
+ : m_pFly(pFly)
+{
+ SAL_WARN_IF(!pFly, "sw.core", "SwFlyCntPortion::SwFlyCntPortion: no SwFlyInContentFrame!");
+}
+
+sw::DrawFlyCntPortion::DrawFlyCntPortion(SwFrameFormat const & rFormat)
+ : m_pContact(nullptr)
+{
+ rFormat.CallSwClientNotify(sw::CreatePortionHint(&m_pContact));
+ assert(m_pContact);
+}
+
+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)
+{
+ auto pNew(new sw::FlyContentPortion(pFly));
+ pNew->SetBase(rFrame, rBase, nLnAscent, nLnDescent, nFlyAsc, nFlyDesc, nFlags | AsCharFlags::UlSpace | AsCharFlags::Init);
+ return pNew;
+}
+
+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)
+{
+ auto pNew(new DrawFlyCntPortion(rFormat));
+ pNew->SetBase(rFrame, rBase, nLnAscent, nLnDescent, nFlyAsc, nFlyDesc, nFlags | AsCharFlags::UlSpace | AsCharFlags::Init);
+ return pNew;
+}
+
+sw::DrawFlyCntPortion::~DrawFlyCntPortion() {};
+sw::FlyContentPortion::~FlyContentPortion() {};
+
+SdrObject* sw::FlyContentPortion::GetSdrObj(const SwTextFrame&)
+{
+ return m_pFly->GetVirtDrawObj();
+}
+
+SdrObject* sw::DrawFlyCntPortion::GetSdrObj(const SwTextFrame& rFrame)
+{
+ SdrObject* pSdrObj;
+ // Determine drawing object ('master' or 'virtual') by frame
+ pSdrObj = m_pContact->GetDrawObjectByAnchorFrame(rFrame);
+ if(!pSdrObj)
+ {
+ SAL_WARN("sw.core", "SwFlyCntPortion::SetBase(..) - No drawing object found by <GetDrawContact()->GetDrawObjectByAnchorFrame( rFrame )>");
+ pSdrObj = m_pContact->GetMaster();
+ }
+
+ // Call <SwAnchoredDrawObject::MakeObjPos()> to assure that flag at
+ // the <DrawFrameFormat> and at the <SwAnchoredDrawObject> instance are
+ // correctly set
+ if(pSdrObj)
+ m_pContact->GetAnchoredObj(pSdrObj)->MakeObjPos();
+ return pSdrObj;
+}
+
+/**
+ * After setting the RefPoints, the ascent needs to be recalculated
+ * because it is dependent on RelPos
+ *
+ * @param rBase CAUTION: needs to be an absolute value!
+ */
+void SwFlyCntPortion::SetBase( const SwTextFrame& rFrame, const Point &rBase,
+ tools::Long nLnAscent, tools::Long nLnDescent,
+ tools::Long nFlyAsc, tools::Long nFlyDesc,
+ AsCharFlags nFlags )
+{
+ // Use new class to position object
+ // Determine drawing object
+ SdrObject* pSdrObj = GetSdrObj(rFrame);
+ if (!pSdrObj)
+ return;
+
+ // position object
+ objectpositioning::SwAsCharAnchoredObjectPosition aObjPositioning(
+ *pSdrObj,
+ rBase, nFlags,
+ nLnAscent, nLnDescent, nFlyAsc, nFlyDesc );
+
+ // Scope of local variable <aObjPosInProgress>
+ {
+ SwObjPositioningInProgress aObjPosInProgress( *pSdrObj );
+ aObjPositioning.CalcPosition();
+ }
+
+ if (auto pFormat = FindFrameFormat(pSdrObj))
+ {
+ if (pFormat->GetOtherTextBoxFormats()
+ && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+ {
+ // TODO: Improve security with moving this sync call to other place,
+ // where it works for typing but not during layout calc.
+ const bool bModified = pFormat->GetDoc()->getIDocumentState().IsEnableSetModified();
+ pFormat->GetDoc()->getIDocumentState().SetEnableSetModified(false);
+ SwTextBoxHelper::synchronizeGroupTextBoxProperty(SwTextBoxHelper::changeAnchor, pFormat,
+ pFormat->FindRealSdrObject());
+ SwTextBoxHelper::synchronizeGroupTextBoxProperty(SwTextBoxHelper::syncTextBoxSize,
+ pFormat, pFormat->FindRealSdrObject());
+ pFormat->GetDoc()->getIDocumentState().SetEnableSetModified(bModified);
+ }
+ }
+
+ SetAlign( aObjPositioning.GetLineAlignment() );
+
+ m_aRef = aObjPositioning.GetAnchorPos();
+ if( nFlags & AsCharFlags::Rotate )
+ SvXSize( aObjPositioning.GetObjBoundRectInclSpacing().SSize() );
+ else
+ SvLSize( aObjPositioning.GetObjBoundRectInclSpacing().SSize() );
+ if( Height() )
+ {
+ // GetRelPosY returns the relative position to baseline (if 0, the
+ // upper border of the FlyCnt if on the baseline of a line)
+ SwTwips nRelPos = aObjPositioning.GetRelPosY();
+ if ( nRelPos < 0 )
+ {
+ mnAscent = -nRelPos;
+ if( mnAscent > Height() )
+ Height( mnAscent );
+ }
+ else
+ {
+ mnAscent = 0;
+ Height( Height() + o3tl::narrowing<sal_uInt16>(nRelPos) );
+ }
+ }
+ else
+ {
+ Height( 1 );
+ mnAscent = 0;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */