summaryrefslogtreecommitdiffstats
path: root/sw/source/core/text/porlin.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/porlin.cxx')
-rw-r--r--sw/source/core/text/porlin.cxx358
1 files changed, 358 insertions, 0 deletions
diff --git a/sw/source/core/text/porlin.cxx b/sw/source/core/text/porlin.cxx
new file mode 100644
index 0000000000..a420d64301
--- /dev/null
+++ b/sw/source/core/text/porlin.cxx
@@ -0,0 +1,358 @@
+/* -*- 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 <vcl/outdev.hxx>
+#include <SwPortionHandler.hxx>
+
+#include "porlin.hxx"
+#include "portxt.hxx"
+#include "inftxt.hxx"
+#include "pormulti.hxx"
+#if OSL_DEBUG_LEVEL > 0
+
+static bool ChkChain( SwLinePortion *pStart )
+{
+ SwLinePortion *pPor = pStart->GetNextPortion();
+ sal_uInt16 nCount = 0;
+ while( pPor )
+ {
+ ++nCount;
+ OSL_ENSURE( nCount < 200 && pPor != pStart,
+ "ChkChain(): lost in chains" );
+ if( nCount >= 200 || pPor == pStart )
+ {
+ // the lifesaver
+ pPor = pStart->GetNextPortion();
+ pStart->SetNextPortion(nullptr);
+ pPor->Truncate();
+ pStart->SetNextPortion( pPor );
+ return false;
+ }
+ pPor = pPor->GetNextPortion();
+ }
+ return true;
+}
+#endif
+
+SwLinePortion::~SwLinePortion()
+{
+}
+
+SwLinePortion *SwLinePortion::Compress()
+{
+ return GetLen() || Width() ? this : nullptr;
+}
+
+sal_uInt16 SwLinePortion::GetViewWidth( const SwTextSizeInfo & ) const
+{
+ return 0;
+}
+
+SwLinePortion::SwLinePortion( ) :
+ mpNextPortion( nullptr ),
+ mnLineLength( 0 ),
+ mnAscent( 0 ),
+ mnHangingBaseline( 0 ),
+ mnWhichPor( PortionType::NONE ),
+ m_bJoinBorderWithPrev(false),
+ m_bJoinBorderWithNext(false)
+{
+}
+
+void SwLinePortion::PrePaint( const SwTextPaintInfo& rInf,
+ const SwLinePortion* pLast ) const
+{
+ OSL_ENSURE( rInf.OnWin(), "SwLinePortion::PrePaint: don't prepaint on a printer");
+ OSL_ENSURE( !Width(), "SwLinePortion::PrePaint: For Width()==0 only!");
+
+ const sal_uInt16 nViewWidth = GetViewWidth( rInf );
+
+ if( ! nViewWidth )
+ return;
+
+ const sal_uInt16 nHalfView = nViewWidth / 2;
+ sal_uInt16 nLastWidth = pLast->Width() + pLast->ExtraBlankWidth();
+
+ if ( pLast->InSpaceGrp() && rInf.GetSpaceAdd(/*bShrink=*/true) )
+ nLastWidth += pLast->CalcSpacing( rInf.GetSpaceAdd(/*bShrink=*/true), rInf );
+
+ sal_uInt16 nPos;
+ SwTextPaintInfo aInf( rInf );
+
+ const bool bBidiPor = rInf.GetTextFrame()->IsRightToLeft() !=
+ bool( vcl::text::ComplexTextLayoutFlags::BiDiRtl & rInf.GetOut()->GetLayoutMode() );
+
+ Degree10 nDir = bBidiPor ?
+ 1800_deg10 :
+ rInf.GetFont()->GetOrientation( rInf.GetTextFrame()->IsVertical() );
+
+ // pLast == this *only* for the 1st portion in the line so nLastWidth is 0;
+ // allow this too, will paint outside the frame but might look better...
+ if (nLastWidth > nHalfView || pLast == this)
+ {
+ switch (nDir.get())
+ {
+ case 0:
+ nPos = sal_uInt16( rInf.X() );
+ nPos += nLastWidth - nHalfView;
+ aInf.X( nPos );
+ break;
+ case 900:
+ nPos = sal_uInt16( rInf.Y() );
+ nPos -= nLastWidth - nHalfView;
+ aInf.Y( nPos );
+ break;
+ case 1800:
+ nPos = sal_uInt16( rInf.X() );
+ nPos -= nLastWidth - nHalfView;
+ aInf.X( nPos );
+ break;
+ case 2700:
+ nPos = sal_uInt16( rInf.Y() );
+ nPos += nLastWidth - nHalfView;
+ aInf.Y( nPos );
+ break;
+ }
+ }
+
+ SwLinePortion *pThis = const_cast<SwLinePortion*>(this);
+ pThis->Width( nViewWidth );
+ Paint( aInf );
+ pThis->Width(0);
+}
+
+void SwLinePortion::CalcTextSize( const SwTextSizeInfo &rInf )
+{
+ if( GetLen() == rInf.GetLen() )
+ *static_cast<SwPosSize*>(this) = GetTextSize( rInf );
+ else
+ {
+ SwTextSizeInfo aInf( rInf );
+ aInf.SetLen( GetLen() );
+ *static_cast<SwPosSize*>(this) = GetTextSize( aInf );
+ }
+}
+
+// all following portions will be deleted
+void SwLinePortion::Truncate_()
+{
+ SwLinePortion *pPos = mpNextPortion;
+ do
+ {
+ OSL_ENSURE( pPos != this, "SwLinePortion::Truncate: loop" );
+ SwLinePortion *pLast = pPos;
+ pPos = pPos->GetNextPortion();
+ pLast->SetNextPortion( nullptr );
+ delete pLast;
+
+ } while( pPos );
+
+ mpNextPortion = nullptr;
+}
+
+// It always will be inserted after us.
+SwLinePortion *SwLinePortion::Insert( SwLinePortion *pIns )
+{
+ pIns->FindLastPortion()->SetNextPortion( mpNextPortion );
+ SetNextPortion( pIns );
+#if OSL_DEBUG_LEVEL > 0
+ ChkChain( this );
+#endif
+ return pIns;
+}
+
+SwLinePortion *SwLinePortion::FindLastPortion()
+{
+ SwLinePortion *pPos = this;
+ // Find the end and link pLinPortion to the last one...
+ while( pPos->GetNextPortion() )
+ {
+ pPos = pPos->GetNextPortion();
+ }
+ return pPos;
+}
+
+SwLinePortion *SwLinePortion::Append( SwLinePortion *pIns )
+{
+ SwLinePortion *pPos = FindLastPortion();
+ pPos->SetNextPortion( pIns );
+ pIns->SetNextPortion( nullptr );
+#if OSL_DEBUG_LEVEL > 0
+ ChkChain( this );
+#endif
+ return pIns;
+}
+
+SwLinePortion *SwLinePortion::Cut( SwLinePortion *pVictim )
+{
+ SwLinePortion *pPrev = pVictim->FindPrevPortion( this );
+ OSL_ENSURE( pPrev, "SwLinePortion::Cut(): can't cut" );
+ // note: if pVictim is a follow then clearing pPrev's m_bHasFollow here is
+ // tricky because it could be that the HookChar inserted a tab portion
+ // between 2 field portions
+ pPrev->SetNextPortion( pVictim->GetNextPortion() );
+ pVictim->SetNextPortion(nullptr);
+ return pVictim;
+}
+
+SwLinePortion *SwLinePortion::FindPrevPortion( const SwLinePortion *pRoot )
+{
+ OSL_ENSURE( pRoot != this, "SwLinePortion::FindPrevPortion(): invalid root" );
+ SwLinePortion *pPos = const_cast<SwLinePortion*>(pRoot);
+ while( pPos->GetNextPortion() && pPos->GetNextPortion() != this )
+ {
+ pPos = pPos->GetNextPortion();
+ }
+ OSL_ENSURE( pPos->GetNextPortion(),
+ "SwLinePortion::FindPrevPortion: blowing in the wind");
+ return pPos;
+}
+
+TextFrameIndex SwLinePortion::GetModelPositionForViewPoint(const sal_uInt16 nOfst) const
+{
+ if( nOfst > ( PrtWidth() / 2 ) )
+ return GetLen();
+ else
+ return TextFrameIndex(0);
+}
+
+SwPosSize SwLinePortion::GetTextSize( const SwTextSizeInfo & ) const
+{
+ OSL_ENSURE( false, "SwLinePortion::GetTextSize: don't ask me about sizes, "
+ "I'm only a stupid SwLinePortion" );
+ return SwPosSize();
+}
+
+bool SwLinePortion::Format( SwTextFormatInfo &rInf )
+{
+ if( rInf.X() > rInf.Width() )
+ {
+ Truncate();
+ rInf.SetUnderflow( this );
+ return true;
+ }
+
+ const SwLinePortion *pLast = rInf.GetLast();
+ Height( pLast->Height() );
+ SetAscent( pLast->GetAscent() );
+ const sal_uInt16 nNewWidth = o3tl::narrowing<sal_uInt16>(rInf.X() + PrtWidth());
+ // Only portions with true width can return true
+ // Notes for example never set bFull==true
+ if( rInf.Width() <= nNewWidth && PrtWidth() && ! IsKernPortion() )
+ {
+ Truncate();
+ if( nNewWidth > rInf.Width() )
+ PrtWidth( nNewWidth - rInf.Width() );
+ rInf.GetLast()->FormatEOL( rInf );
+ return true;
+ }
+ return false;
+}
+
+// Format end of line
+
+void SwLinePortion::FormatEOL( SwTextFormatInfo & )
+{ }
+
+void SwLinePortion::Move(SwTextPaintInfo & rInf) const
+{
+ bool bB2T = rInf.GetDirection() == DIR_BOTTOM2TOP;
+ const bool bFrameDir = rInf.GetTextFrame()->IsRightToLeft();
+ bool bCounterDir = ( ! bFrameDir && DIR_RIGHT2LEFT == rInf.GetDirection() ) ||
+ ( bFrameDir && DIR_LEFT2RIGHT == rInf.GetDirection() );
+
+ SwTwips nTmp = PrtWidth() + ExtraBlankWidth();
+ if ( InSpaceGrp() && rInf.GetSpaceAdd(/*bShrink=*/true) )
+ {
+ nTmp += CalcSpacing( rInf.GetSpaceAdd(/*bShrink=*/true), rInf );
+ if( rInf.IsRotated() )
+ rInf.Y( rInf.Y() + ( bB2T ? -nTmp : nTmp ) );
+ else if ( bCounterDir )
+ rInf.X( rInf.X() - nTmp );
+ else
+ rInf.X( rInf.X() + nTmp );
+ }
+ else
+ {
+ if( InFixMargGrp() && !IsMarginPortion() )
+ {
+ rInf.IncSpaceIdx();
+ rInf.IncKanaIdx();
+ }
+ if( rInf.IsRotated() )
+ rInf.Y(rInf.Y() + (bB2T ? -nTmp : nTmp));
+ else if ( bCounterDir )
+ rInf.X(rInf.X() - nTmp);
+ else
+ rInf.X(rInf.X() + nTmp);
+ }
+ if (IsMultiPortion() && static_cast<SwMultiPortion const*>(this)->HasTabulator())
+ rInf.IncSpaceIdx();
+
+ rInf.SetIdx( rInf.GetIdx() + GetLen() );
+}
+
+SwTwips SwLinePortion::CalcSpacing( tools::Long , const SwTextSizeInfo & ) const
+{
+ return 0;
+}
+
+bool SwLinePortion::GetExpText( const SwTextSizeInfo &, OUString & ) const
+{
+ return false;
+}
+
+void SwLinePortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Special( GetLen(), OUString(), GetWhichPor() );
+}
+
+void SwLinePortion::dumpAsXml(xmlTextWriterPtr pWriter, const OUString& rText, TextFrameIndex& nOffset) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwLinePortion"));
+ dumpAsXmlAttributes(pWriter, rText, nOffset);
+ nOffset += GetLen();
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+void SwLinePortion::dumpAsXmlAttributes(xmlTextWriterPtr pWriter, std::u16string_view rText, TextFrameIndex nOffset) const
+{
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("symbol"), BAD_CAST(typeid(*this).name()));
+ (void)xmlTextWriterWriteAttribute(
+ pWriter, BAD_CAST("width"),
+ BAD_CAST(OString::number(Width()).getStr()));
+ (void)xmlTextWriterWriteAttribute(
+ pWriter, BAD_CAST("height"),
+ BAD_CAST(OString::number(Height()).getStr()));
+ (void)xmlTextWriterWriteAttribute(
+ pWriter, BAD_CAST("length"),
+ BAD_CAST(OString::number(static_cast<sal_Int32>(mnLineLength)).getStr()));
+ (void)xmlTextWriterWriteAttribute(
+ pWriter, BAD_CAST("type"),
+ BAD_CAST(sw::PortionTypeToString(GetWhichPor())));
+ OUString aText( rText.substr(sal_Int32(nOffset), sal_Int32(GetLen())) );
+ for (int i = 0; i < 32; ++i)
+ aText = aText.replace(i, '*');
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("portion"),
+ BAD_CAST(aText.toUtf8().getStr()));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */