LibreOffice Module sw (master)  1
portxt.cxx
Go to the documentation of this file.
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 <com/sun/star/i18n/ScriptType.hpp>
21 #include <com/sun/star/i18n/XBreakIterator.hpp>
22 #include <i18nlangtag/mslangid.hxx>
23 #include <breakit.hxx>
24 #include <hintids.hxx>
26 #include <SwPortionHandler.hxx>
27 #include "porlay.hxx"
28 #include "inftxt.hxx"
29 #include "guess.hxx"
30 #include "porglue.hxx"
31 #include "portab.hxx"
32 #include "porfld.hxx"
33 #include <pagefrm.hxx>
34 #include <tgrditem.hxx>
35 #include <wrong.hxx>
36 #include <viewsh.hxx>
38 #include <IDocumentMarkAccess.hxx>
39 #include <viewopt.hxx>
40 #include <editeng/borderline.hxx>
41 
42 #include <IMark.hxx>
43 #include <pam.hxx>
44 #include <doc.hxx>
45 #include <xmloff/odffields.hxx>
46 
47 using namespace ::sw::mark;
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::i18n::ScriptType;
50 
51 // Returns for how many characters an extra space has to be added
52 // (for justified alignment).
54  const OUString* pStr, const SwLinePortion& rPor)
55 {
56  TextFrameIndex nPos, nEnd;
57  const SwScriptInfo* pSI = nullptr;
58 
59  if ( pStr )
60  {
61  // passing a string means we are inside a field
62  nPos = TextFrameIndex(0);
63  nEnd = TextFrameIndex(pStr->getLength());
64  }
65  else
66  {
67  nPos = rInf.GetIdx();
68  nEnd = rInf.GetIdx() + rPor.GetLen();
69  pStr = &rInf.GetText();
70  pSI = &const_cast<SwParaPortion*>(rInf.GetParaPortion())->GetScriptInfo();
71  }
72 
73  TextFrameIndex nCnt(0);
74  sal_uInt8 nScript = 0;
75 
76  // If portion consists of Asian characters and language is not
77  // Korean, we add extra space to each character.
78  // first we get the script type
79  if ( pSI )
80  nScript = pSI->ScriptType( nPos );
81  else
82  nScript = static_cast<sal_uInt8>(
83  g_pBreakIt->GetBreakIter()->getScriptType(*pStr, sal_Int32(nPos)));
84 
85  // Note: rInf.GetIdx() can differ from nPos,
86  // e.g., when rPor is a field portion. nPos referes to the string passed
87  // to the function, rInf.GetIdx() referes to the original string.
88 
89  // We try to find out which justification mode is required. This is done by
90  // evaluating the script type and the language attribute set for this portion
91 
92  // Asian Justification: Each character get some extra space
93  if ( nEnd > nPos && ASIAN == nScript )
94  {
95  LanguageType aLang =
96  rInf.GetTextFrame()->GetLangOfChar(rInf.GetIdx(), nScript);
97 
98  if (!MsLangId::isKorean(aLang))
99  {
100  const SwLinePortion* pPor = rPor.GetNextPortion();
101  if ( pPor && ( pPor->IsKernPortion() ||
102  pPor->IsControlCharPortion() ||
103  pPor->IsPostItsPortion() ) )
104  pPor = pPor->GetNextPortion();
105 
106  nCnt += SwScriptInfo::CountCJKCharacters( *pStr, nPos, nEnd, aLang );
107 
108  if ( !pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ||
109  pPor->IsBreakPortion() )
110  --nCnt;
111 
112  return nCnt;
113  }
114  }
115 
116  // Kashida Justification: Insert Kashidas
117  if ( nEnd > nPos && pSI && COMPLEX == nScript )
118  {
119  if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() )
120  {
121  const sal_Int32 nKashRes = pSI->KashidaJustify( nullptr, nullptr, nPos, nEnd - nPos );
122  // i60591: need to check result of KashidaJustify
123  // determine if kashida justification is applicable
124  if (nKashRes != -1)
125  return TextFrameIndex(nKashRes);
126  }
127  }
128 
129  // Thai Justification: Each character cell gets some extra space
130  if ( nEnd > nPos && COMPLEX == nScript )
131  {
132  LanguageType aLang =
133  rInf.GetTextFrame()->GetLangOfChar(rInf.GetIdx(), nScript);
134 
135  if ( LANGUAGE_THAI == aLang )
136  {
137  nCnt = SwScriptInfo::ThaiJustify( *pStr, nullptr, nullptr, nPos, nEnd - nPos );
138 
139  const SwLinePortion* pPor = rPor.GetNextPortion();
140  if ( pPor && ( pPor->IsKernPortion() ||
141  pPor->IsControlCharPortion() ||
142  pPor->IsPostItsPortion() ) )
143  pPor = pPor->GetNextPortion();
144 
145  if ( nCnt && ( ! pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ) )
146  --nCnt;
147 
148  return nCnt;
149  }
150  }
151 
152  // Here starts the good old "Look for blanks and add space to them" part.
153  // Note: We do not want to add space to an isolated latin blank in front
154  // of some complex characters in RTL environment
155  const bool bDoNotAddSpace =
156  LATIN == nScript && (nEnd == nPos + TextFrameIndex(1)) && pSI &&
157  ( i18n::ScriptType::COMPLEX ==
158  pSI->ScriptType(nPos + TextFrameIndex(1))) &&
159  rInf.GetTextFrame() && rInf.GetTextFrame()->IsRightToLeft();
160 
161  if ( bDoNotAddSpace )
162  return nCnt;
163 
164  TextFrameIndex nTextEnd = std::min(nEnd, TextFrameIndex(pStr->getLength()));
165  for ( ; nPos < nTextEnd; ++nPos )
166  {
167  if (CH_BLANK == (*pStr)[ sal_Int32(nPos) ])
168  ++nCnt;
169  }
170 
171  // We still have to examine the next character:
172  // If the next character is ASIAN and not KOREAN we have
173  // to add an extra space
174  // nPos referes to the original string, even if a field string has
175  // been passed to this function
176  nPos = rInf.GetIdx() + rPor.GetLen();
177  if (nPos < TextFrameIndex(rInf.GetText().getLength()))
178  {
179  sal_uInt8 nNextScript = 0;
180  const SwLinePortion* pPor = rPor.GetNextPortion();
181  if ( pPor && pPor->IsKernPortion() )
182  pPor = pPor->GetNextPortion();
183 
184  if (!pPor || pPor->InFixMargGrp())
185  return nCnt;
186 
187  // next character is inside a field?
188  if ( CH_TXTATR_BREAKWORD == rInf.GetChar( nPos ) && pPor->InExpGrp() )
189  {
190  bool bOldOnWin = rInf.OnWin();
191  const_cast<SwTextSizeInfo &>(rInf).SetOnWin( false );
192 
193  OUString aStr;
194  pPor->GetExpText( rInf, aStr );
195  const_cast<SwTextSizeInfo &>(rInf).SetOnWin( bOldOnWin );
196 
197  nNextScript = static_cast<sal_uInt8>(g_pBreakIt->GetBreakIter()->getScriptType( aStr, 0 ));
198  }
199  else
200  nNextScript = static_cast<sal_uInt8>(
201  g_pBreakIt->GetBreakIter()->getScriptType(rInf.GetText(), sal_Int32(nPos)));
202 
203  if( ASIAN == nNextScript )
204  {
205  LanguageType aLang =
206  rInf.GetTextFrame()->GetLangOfChar(nPos, nNextScript);
207 
208  if (!MsLangId::isKorean(aLang))
209  ++nCnt;
210  }
211  }
212 
213  return nCnt;
214 }
215 
217 {
218  SwTextPortion *const pNew(new SwTextPortion);
219  static_cast<SwLinePortion&>(*pNew) = rPortion;
220  pNew->SetWhichPor( PortionType::Text ); // overwrite that!
221  return pNew;
222 }
223 
225 {
226  // The word/char is larger than the line
227  // Special case 1: The word is larger than the line
228  // We truncate ...
229  const sal_uInt16 nLineWidth = static_cast<sal_uInt16>(rInf.Width() - rInf.X());
230  TextFrameIndex nLen = rGuess.CutPos() - rInf.GetIdx();
231  if (nLen > TextFrameIndex(0))
232  {
233  // special case: guess does not always provide the correct
234  // width, only in common cases.
235  if ( !rGuess.BreakWidth() )
236  {
237  rInf.SetLen( nLen );
238  SetLen( nLen );
239  CalcTextSize( rInf );
240 
241  // changing these values requires also changing them in
242  // guess.cxx
243  sal_uInt16 nItalic = 0;
244  if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
245  {
246  nItalic = Height() / 12;
247  }
248  Width( Width() + nItalic );
249  }
250  else
251  {
252  Width( rGuess.BreakWidth() );
253  SetLen( nLen );
254  }
255  }
256  // special case: first character does not fit to line
257  else if ( rGuess.CutPos() == rInf.GetLineStart() )
258  {
259  SetLen( TextFrameIndex(1) );
260  Width( nLineWidth );
261  }
262  else
263  {
264  SetLen( TextFrameIndex(0) );
265  Width( 0 );
266  }
267 }
268 
270 {
271  Truncate();
272  Height( 0 );
273  Width( 0 );
274  SetLen( TextFrameIndex(0) );
275  SetAscent( 0 );
276  rInf.SetUnderflow( this );
277 }
278 
279 static bool lcl_HasContent( const SwFieldPortion& rField, SwTextFormatInfo const &rInf )
280 {
281  OUString aText;
282  return rField.GetExpText( rInf, aText ) && !aText.isEmpty();
283 }
284 
286 {
287  // 5744: If only the hyphen does not fit anymore, we still need to wrap
288  // the word, or else return true!
289  if( rInf.IsUnderflow() && rInf.GetSoftHyphPos() )
290  {
291  // soft hyphen portion has triggered an underflow event because
292  // of an alternative spelling position
293  bool bFull = false;
294  const bool bHyph = rInf.ChgHyph( true );
295  if( rInf.IsHyphenate() )
296  {
297  SwTextGuess aGuess;
298  // check for alternative spelling left from the soft hyphen
299  // this should usually be true but
300  aGuess.AlternativeSpelling(rInf, rInf.GetSoftHyphPos() - TextFrameIndex(1));
301  bFull = CreateHyphen( rInf, aGuess );
302  OSL_ENSURE( bFull, "Problem with hyphenation!!!" );
303  }
304  rInf.ChgHyph( bHyph );
305  rInf.SetSoftHyphPos( TextFrameIndex(0) );
306  return bFull;
307  }
308 
309  SwTextGuess aGuess;
310  const bool bFull = !aGuess.Guess( *this, rInf, Height() );
311 
312  // these are the possible cases:
313  // A Portion fits to current line
314  // B Portion does not fit to current line but a possible line break
315  // within the portion has been found by the break iterator, 2 subcases
316  // B1 break is hyphen
317  // B2 break is word end
318  // C Portion does not fit to current line and no possible line break
319  // has been found by break iterator, 2 subcases:
320  // C1 break iterator found a possible line break in portion before us
321  // ==> this break is used (underflow)
322  // C2 break iterator does not found a possible line break at all:
323  // ==> line break
324 
325  // case A: line not yet full
326  if ( !bFull )
327  {
328  Width( aGuess.BreakWidth() );
329  // Caution!
330  if( !InExpGrp() || InFieldGrp() )
331  SetLen( rInf.GetLen() );
332 
333  short nKern = rInf.GetFont()->CheckKerning();
334  if( nKern > 0 && rInf.Width() < rInf.X() + Width() + nKern )
335  {
336  nKern = static_cast<short>(rInf.Width() - rInf.X() - Width() - 1);
337  if( nKern < 0 )
338  nKern = 0;
339  }
340  if( nKern )
341  new SwKernPortion( *this, nKern );
342  }
343  // special case: hanging portion
344  else if( bFull && aGuess.GetHangingPortion() )
345  {
346  Width( aGuess.BreakWidth() );
347  SetLen( aGuess.BreakPos() - rInf.GetIdx() );
348  aGuess.GetHangingPortion()->SetAscent( GetAscent() );
349  Insert( aGuess.ReleaseHangingPortion() );
350  }
351  // breakPos >= index
352  else if (aGuess.BreakPos() >= rInf.GetIdx() && aGuess.BreakPos() != TextFrameIndex(COMPLETE_STRING))
353  {
354  // case B1
355  if( aGuess.HyphWord().is() && aGuess.BreakPos() > rInf.GetLineStart()
356  && ( aGuess.BreakPos() > rInf.GetIdx() ||
357  ( rInf.GetLast() && ! rInf.GetLast()->IsFlyPortion() ) ) )
358  {
359  CreateHyphen( rInf, aGuess );
360  if ( rInf.GetFly() )
361  rInf.GetRoot()->SetMidHyph( true );
362  else
363  rInf.GetRoot()->SetEndHyph( true );
364  }
365  // case C1
366  // - Footnote portions with fake line start (i.e., not at beginning of line)
367  // should keep together with the text portion. (Note: no keep together
368  // with only footnote portions.
369  // - TabPortions not at beginning of line should keep together with the
370  // text portion, if they are not followed by a blank
371  // (work around different definition of tab stop character - breaking or
372  // non breaking character - in compatibility mode)
373  else if ( ( IsFootnotePortion() && rInf.IsFakeLineStart() &&
374 
375  rInf.IsOtherThanFootnoteInside() ) ||
376  ( rInf.GetLast() &&
378  rInf.GetLast()->InTabGrp() &&
379  rInf.GetLineStart() + rInf.GetLast()->GetLen() < rInf.GetIdx() &&
380  aGuess.BreakPos() == rInf.GetIdx() &&
381  CH_BLANK != rInf.GetChar( rInf.GetIdx() ) &&
382  0x3000 != rInf.GetChar( rInf.GetIdx() ) ) )
383  BreakUnderflow( rInf );
384  // case B2
385  else if( rInf.GetIdx() > rInf.GetLineStart() ||
386  aGuess.BreakPos() > rInf.GetIdx() ||
387  // this is weird: during formatting the follow of a field
388  // the values rInf.GetIdx and rInf.GetLineStart are replaced
389  // IsFakeLineStart indicates GetIdx > GetLineStart
390  rInf.IsFakeLineStart() ||
391  rInf.GetFly() ||
392  rInf.IsFirstMulti() ||
393  ( rInf.GetLast() &&
394  ( rInf.GetLast()->IsFlyPortion() ||
395  ( rInf.GetLast()->InFieldGrp() &&
396  ! rInf.GetLast()->InNumberGrp() &&
397  ! rInf.GetLast()->IsErgoSumPortion() &&
398  lcl_HasContent(*static_cast<SwFieldPortion*>(rInf.GetLast()),rInf ) ) ) ) )
399  {
400  // GetLineWidth() takes care of DocumentSettingId::TAB_OVER_MARGIN.
401  if (aGuess.BreakWidth() <= rInf.GetLineWidth())
402  Width( aGuess.BreakWidth() );
403  else
404  // this actually should not happen
405  Width( sal_uInt16(rInf.Width() - rInf.X()) );
406 
407  SetLen( aGuess.BreakPos() - rInf.GetIdx() );
408 
409  OSL_ENSURE( aGuess.BreakStart() >= aGuess.FieldDiff(),
410  "Trouble with expanded field portions during line break" );
411  TextFrameIndex const nRealStart = aGuess.BreakStart() - aGuess.FieldDiff();
412  if( aGuess.BreakPos() < nRealStart && !InExpGrp() )
413  {
414  SwHolePortion *pNew = new SwHolePortion( *this );
415  pNew->SetLen( nRealStart - aGuess.BreakPos() );
416  Insert( pNew );
417  }
418  }
419  else // case C2, last exit
420  BreakCut( rInf, aGuess );
421  }
422  // breakPos < index or no breakpos at all
423  else
424  {
425  bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
426  if (aGuess.BreakPos() != TextFrameIndex(COMPLETE_STRING) &&
427  aGuess.BreakPos() != rInf.GetLineStart() &&
428  ( !bFirstPor || rInf.GetFly() || rInf.GetLast()->IsFlyPortion() ||
429  rInf.IsFirstMulti() ) &&
430  ( !rInf.GetLast()->IsBlankPortion() ||
431  SwBlankPortion::MayUnderflow(rInf, rInf.GetIdx() - TextFrameIndex(1), true)))
432  { // case C1 (former BreakUnderflow())
433  BreakUnderflow( rInf );
434  }
435  else
436  // case C2, last exit
437  BreakCut( rInf, aGuess );
438  }
439 
440  return bFull;
441 }
442 
444 {
445  // GetLineWidth() takes care of DocumentSettingId::TAB_OVER_MARGIN.
446  if( rInf.GetLineWidth() < 0 || (!GetLen() && !InExpGrp()) )
447  {
448  Height( 0 );
449  Width( 0 );
450  SetLen( TextFrameIndex(0) );
451  SetAscent( 0 );
452  SetNextPortion( nullptr ); // ????
453  return true;
454  }
455 
456  OSL_ENSURE( rInf.RealWidth() || (rInf.X() == rInf.Width()),
457  "SwTextPortion::Format: missing real width" );
458  OSL_ENSURE( Height(), "SwTextPortion::Format: missing height" );
459 
460  return Format_( rInf );
461 }
462 
463 // Format end of line
464 // 5083: We can have awkward cases e.g.:
465 // "from {Santa}"
466 // Santa wraps, "from " turns into "from" and " " in a justified
467 // paragraph, in which the glue gets expanded instead of merged
468 // with the MarginPortion.
469 
470 // rInf.nIdx points to the next word, nIdx-1 is the portion's last char
472 {
473  if( !(
475  !GetNextPortion()->GetNextPortion() ) ) &&
476  GetLen() &&
477  rInf.GetIdx() < TextFrameIndex(rInf.GetText().getLength()) &&
478  TextFrameIndex(1) < rInf.GetIdx() &&
479  ' ' == rInf.GetChar(rInf.GetIdx() - TextFrameIndex(1)) &&
480  !rInf.GetLast()->IsHolePortion()) )
481  return;
482 
483  // calculate number of blanks
484  TextFrameIndex nX(rInf.GetIdx() - TextFrameIndex(1));
485  TextFrameIndex nHoleLen(1);
486  while( nX && nHoleLen < GetLen() && CH_BLANK == rInf.GetChar( --nX ) )
487  nHoleLen++;
488 
489  // First set ourselves and the insert, because there could be
490  // a SwLineLayout
491  sal_uInt16 nBlankSize;
492  if( nHoleLen == GetLen() )
493  nBlankSize = Width();
494  else
495  nBlankSize = sal_Int32(nHoleLen) * rInf.GetTextSize(OUString(' ')).Width();
496  Width( Width() - nBlankSize );
497  rInf.X( rInf.X() - nBlankSize );
498  SetLen( GetLen() - nHoleLen );
499  SwLinePortion *pHole = new SwHolePortion( *this );
500  static_cast<SwHolePortion *>( pHole )->SetBlankWidth( nBlankSize );
501  static_cast<SwHolePortion *>( pHole )->SetLen( nHoleLen );
502  Insert( pHole );
503 
504 }
505 
506 TextFrameIndex SwTextPortion::GetCursorOfst(const sal_uInt16 nOfst) const
507 {
508  OSL_ENSURE( false, "SwTextPortion::GetCursorOfst: don't use this method!" );
509  return SwLinePortion::GetCursorOfst( nOfst );
510 }
511 
512 // The GetTextSize() assumes that the own length is correct
514 {
515  SwPosSize aSize = rInf.GetTextSize();
516  if( !GetJoinBorderWithPrev() )
517  aSize.Width(aSize.Width() + rInf.GetFont()->GetLeftBorderSpace() );
518  if( !GetJoinBorderWithNext() )
519  aSize.Width(aSize.Width() + rInf.GetFont()->GetRightBorderSpace() );
520 
521  aSize.Height(aSize.Height() +
522  rInf.GetFont()->GetTopBorderSpace() +
523  rInf.GetFont()->GetBottomBorderSpace() );
524 
525  return aSize;
526 }
527 
528 void SwTextPortion::Paint( const SwTextPaintInfo &rInf ) const
529 {
530  if (rInf.OnWin() && TextFrameIndex(1) == rInf.GetLen()
531  && CH_TXT_ATR_FIELDEND == rInf.GetText()[sal_Int32(rInf.GetIdx())])
532  {
533  assert(false); // this is some debugging only code
534  rInf.DrawBackBrush( *this );
535  const OUString aText(CH_TXT_ATR_SUBST_FIELDEND);
536  rInf.DrawText(aText, *this, TextFrameIndex(0), TextFrameIndex(aText.getLength()));
537  }
538  else if (rInf.OnWin() && TextFrameIndex(1) == rInf.GetLen()
539  && CH_TXT_ATR_FIELDSTART == rInf.GetText()[sal_Int32(rInf.GetIdx())])
540  {
541  assert(false); // this is some debugging only code
542  rInf.DrawBackBrush( *this );
543  const OUString aText(CH_TXT_ATR_SUBST_FIELDSTART);
544  rInf.DrawText(aText, *this, TextFrameIndex(0), TextFrameIndex(aText.getLength()));
545  }
546  else if( GetLen() )
547  {
548  rInf.DrawBackBrush( *this );
549  rInf.DrawBorder( *this );
550 
551  // do we have to repaint a post it portion?
552  if( rInf.OnWin() && mpNextPortion && !mpNextPortion->Width() )
553  mpNextPortion->PrePaint( rInf, this );
554 
555  auto const* pWrongList = rInf.GetpWrongList();
556  auto const* pGrammarCheckList = rInf.GetGrammarCheckList();
557  auto const* pSmarttags = rInf.GetSmartTags();
558 
559  const bool bWrong = nullptr != pWrongList;
560  const bool bGrammarCheck = nullptr != pGrammarCheckList;
561  const bool bSmartTags = nullptr != pSmarttags;
562 
563  if ( bWrong || bSmartTags || bGrammarCheck )
564  rInf.DrawMarkedText( *this, rInf.GetLen(), bWrong, bSmartTags, bGrammarCheck );
565  else
566  rInf.DrawText( *this, rInf.GetLen() );
567  }
568 }
569 
570 bool SwTextPortion::GetExpText( const SwTextSizeInfo &, OUString & ) const
571 {
572  return false;
573 }
574 
575 // Responsible for the justified paragraph. They calculate the blank
576 // count and the resulting added space.
578  TextFrameIndex& rCharCnt) const
579 {
580  TextFrameIndex nCnt(0);
581  TextFrameIndex nPos(0);
582 
583  if ( rInf.SnapToGrid() )
584  {
585  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetTextFrame()->FindPageFrame()));
586  if (pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars())
587  return TextFrameIndex(0);
588  }
589 
590  if ( InExpGrp() )
591  {
592  if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
593  {
594  // OnWin() likes to return a blank instead of an empty string from
595  // time to time. We cannot use that here at all, however.
596  bool bOldOnWin = rInf.OnWin();
597  const_cast<SwTextSizeInfo &>(rInf).SetOnWin( false );
598 
599  OUString aStr;
600  GetExpText( rInf, aStr );
601  const_cast<SwTextSizeInfo &>(rInf).SetOnWin( bOldOnWin );
602 
603  nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
604  nPos = TextFrameIndex(aStr.getLength());
605  }
606  }
607  else if( !IsDropPortion() )
608  {
609  nCnt = nCnt + lcl_AddSpace( rInf, nullptr, *this );
610  nPos = GetLen();
611  }
612  rCharCnt = rCharCnt + nPos;
613  return nCnt;
614 }
615 
616 long SwTextPortion::CalcSpacing( long nSpaceAdd, const SwTextSizeInfo &rInf ) const
617 {
618  TextFrameIndex nCnt(0);
619 
620  if ( rInf.SnapToGrid() )
621  {
622  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetTextFrame()->FindPageFrame()));
623  if (pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars())
624  return 0;
625  }
626 
627  if ( InExpGrp() )
628  {
629  if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
630  {
631  // OnWin() likes to return a blank instead of an empty string from
632  // time to time. We cannot use that here at all, however.
633  bool bOldOnWin = rInf.OnWin();
634  const_cast<SwTextSizeInfo &>(rInf).SetOnWin( false );
635 
636  OUString aStr;
637  GetExpText( rInf, aStr );
638  const_cast<SwTextSizeInfo &>(rInf).SetOnWin( bOldOnWin );
639  if( nSpaceAdd > 0 )
640  nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
641  else
642  {
643  nSpaceAdd = -nSpaceAdd;
644  nCnt = TextFrameIndex(aStr.getLength());
645  }
646  }
647  }
648  else if( !IsDropPortion() )
649  {
650  if( nSpaceAdd > 0 )
651  nCnt = nCnt + lcl_AddSpace( rInf, nullptr, *this );
652  else
653  {
654  nSpaceAdd = -nSpaceAdd;
655  nCnt = GetLen();
656  SwLinePortion* pPor = GetNextPortion();
657 
658  // we do not want an extra space in front of margin portions
659  if ( nCnt )
660  {
661  while ( pPor && !pPor->Width() && ! pPor->IsHolePortion() )
662  pPor = pPor->GetNextPortion();
663 
664  if ( !pPor || pPor->InFixMargGrp() || pPor->IsHolePortion() )
665  --nCnt;
666  }
667  }
668  }
669 
670  return sal_Int32(nCnt) * nSpaceAdd / SPACING_PRECISION_FACTOR;
671 }
672 
674 {
675  rPH.Text( GetLen(), GetWhichPor(), Height(), Width() );
676 }
677 
679  : SwTextPortion()
680 {
682 }
683 
685 {
686  return SwTextPortion::Format(rTextFormatInfo);
687 }
688 
690 {
691  if ( Width() )
692  {
693  rInf.DrawViewOpt( *this, PortionType::InputField );
694  SwTextSlot aPaintText( &rInf, this, true, true, OUString() );
695  SwTextPortion::Paint( rInf );
696  }
697 }
698 
699 bool SwTextInputFieldPortion::GetExpText( const SwTextSizeInfo &rInf, OUString &rText ) const
700 {
701  sal_Int32 nIdx(rInf.GetIdx());
702  sal_Int32 nLen(rInf.GetLen());
703  if ( rInf.GetChar( rInf.GetIdx() ) == CH_TXT_ATR_INPUTFIELDSTART )
704  {
705  ++nIdx;
706  --nLen;
707  }
708  if (rInf.GetChar(rInf.GetIdx() + rInf.GetLen() - TextFrameIndex(1)) == CH_TXT_ATR_INPUTFIELDEND)
709  {
710  --nLen;
711  }
712  rText = rInf.GetText().copy( nIdx, std::min( nLen, rInf.GetText().getLength() - nIdx ) );
713 
714  return true;
715 }
716 
718 {
719  SwTextSlot aFormatText( &rInf, this, true, false );
720  if (rInf.GetLen() == TextFrameIndex(0))
721  {
722  return SwPosSize( 0, 0 );
723  }
724 
725  return rInf.GetTextSize();
726 }
727 
729  : nBlankWidth( 0 )
730 {
731  SetLen( TextFrameIndex(1) );
732  Height( rPor.Height() );
733  SetAscent( rPor.GetAscent() );
735 }
736 
738 
739 void SwHolePortion::Paint( const SwTextPaintInfo &rInf ) const
740 {
741  if( !rInf.GetOut() )
742  return;
743 
744  // #i16816# export stuff only needed for tagged pdf support
746  return;
747 
748  // #i68503# the hole must have no decoration for a consistent visual appearance
749  const SwFont* pOrigFont = rInf.GetFont();
750  std::unique_ptr<SwFont> pHoleFont;
751  std::unique_ptr<SwFontSave> pFontSave;
752  if( pOrigFont->GetUnderline() != LINESTYLE_NONE
753  || pOrigFont->GetOverline() != LINESTYLE_NONE
754  || pOrigFont->GetStrikeout() != STRIKEOUT_NONE )
755  {
756  pHoleFont.reset(new SwFont( *pOrigFont ));
757  pHoleFont->SetUnderline( LINESTYLE_NONE );
758  pHoleFont->SetOverline( LINESTYLE_NONE );
759  pHoleFont->SetStrikeout( STRIKEOUT_NONE );
760  pFontSave.reset(new SwFontSave( rInf, pHoleFont.get() ));
761  }
762 
763  const OUString aText( ' ' );
764  rInf.DrawText(aText, *this, TextFrameIndex(0), TextFrameIndex(1));
765 
766  pFontSave.reset();
767  pHoleFont.reset();
768 }
769 
771 {
772  return rInf.IsFull() || rInf.X() >= rInf.Width();
773 }
774 
776 {
777  rPH.Text( GetLen(), GetWhichPor() );
778 }
779 
780 void SwFieldMarkPortion::Paint( const SwTextPaintInfo & /*rInf*/) const
781 {
782  // These shouldn't be painted!
783  //SwTextPortion::Paint(rInf);
784 }
785 
787 {
788  Width(0);
789  return false;
790 }
791 
793 {
794  SwPosition const aPosition(rInf.GetTextFrame()->MapViewToModelPos(rInf.GetIdx()));
795 
796  IFieldmark const*const pBM = rInf.GetTextFrame()->GetDoc().getIDocumentMarkAccess()->getFieldmarkFor( aPosition );
797 
798  OSL_ENSURE(pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX,
799  "Where is my form field bookmark???");
800 
801  if (pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX)
802  {
803  const ICheckboxFieldmark* pCheckboxFm = dynamic_cast<ICheckboxFieldmark const*>(pBM);
804  bool bChecked = pCheckboxFm && pCheckboxFm->IsChecked();
805  rInf.DrawCheckBox(*this, bChecked);
806  }
807 }
808 
810 {
811  SwPosition const aPosition(rInf.GetTextFrame()->MapViewToModelPos(rInf.GetIdx()));
812  IFieldmark const*const pBM = rInf.GetTextFrame()->GetDoc().getIDocumentMarkAccess()->getFieldmarkFor( aPosition );
813  OSL_ENSURE(pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX, "Where is my form field bookmark???");
814  if (pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX)
815  {
816  Width( rInf.GetTextHeight( ) );
817  Height( rInf.GetTextHeight( ) );
818  SetAscent( rInf.GetAscent( ) );
819  }
820  return false;
821 }
822 
823 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsFirstMulti() const
Definition: inftxt.hxx:212
sal_uInt16 GetLeftBorderSpace() const
Definition: swfont.hxx:905
TextFrameIndex FieldDiff() const
Definition: guess.hxx:57
void DrawBackBrush(const SwLinePortion &rPor) const
Definition: inftxt.cxx:1124
short CheckKerning()
Definition: swfont.hxx:320
Marks a position in the document model.
Definition: pam.hxx:35
virtual void FormatEOL(SwTextFormatInfo &rInf) override
Definition: portxt.cxx:471
sal_uInt16 BreakWidth() const
Definition: guess.hxx:53
bool IsUnderflow() const
Definition: inftxt.hxx:588
LanguageType GetLangOfChar(TextFrameIndex nIndex, sal_uInt16 nScript, bool bNoChar=false) const
Definition: txtfrm.cxx:1332
#define CH_TXT_ATR_SUBST_FIELDSTART
Definition: hintids.hxx:54
sal_uInt16 Height() const
Definition: possiz.hxx:44
SwFont * GetFont()
Definition: inftxt.hxx:238
bool InNumberGrp() const
Definition: porlin.hxx:101
SwHolePortion(const SwTextPortion &rPor)
Definition: portxt.cxx:728
bool GetJoinBorderWithPrev() const
Definition: porlin.hxx:167
void BreakCut(SwTextFormatInfo &rInf, const SwTextGuess &rGuess)
Definition: portxt.cxx:224
void CalcTextSize(const SwTextSizeInfo &rInfo)
Definition: porlin.cxx:142
sal_uInt16 GetRightBorderSpace() const
Definition: swfont.hxx:890
#define CH_TXT_ATR_SUBST_FIELDEND
Definition: hintids.hxx:55
The SwPortionHandler interface implements a visitor for the layout engine's text portions.
#define ODF_FORMCHECKBOX
void DrawBorder(const SwLinePortion &rPor) const
Draw character border around a line portion.
Definition: inftxt.cxx:1271
sal_uInt16 GetTextHeight() const
Definition: inftxt.hxx:717
virtual void Paint(const SwTextPaintInfo &rInf) const override
Definition: portxt.cxx:689
static TextFrameIndex lcl_AddSpace(const SwTextSizeInfo &rInf, const OUString *pStr, const SwLinePortion &rPor)
Definition: portxt.cxx:53
bool Guess(const SwTextPortion &rPor, SwTextFormatInfo &rInf, const sal_uInt16 nHeight)
Definition: guess.cxx:56
void SetLen(TextFrameIndex const nLen)
Definition: porlin.hxx:74
#define ASIAN
sw::WrongListIterator * GetGrammarCheckList() const
Definition: inftxt.hxx:458
void DrawText(const OUString &rText, const SwLinePortion &rPor, TextFrameIndex nIdx=TextFrameIndex(0), TextFrameIndex nLen=TextFrameIndex(COMPLETE_STRING), const bool bKern=false) const
Definition: inftxt.hxx:746
sal_uInt16 RealWidth() const
Definition: inftxt.hxx:554
FontStrikeout GetStrikeout() const
Definition: swfont.hxx:272
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1552
static bool lcl_HasContent(const SwFieldPortion &rField, SwTextFormatInfo const &rInf)
Definition: portxt.cxx:279
bool InFieldGrp() const
Definition: porlin.hxx:103
bool Format_(SwTextFormatInfo &rInf)
Definition: portxt.cxx:285
SwPosSize GetTextSize(OutputDevice *pOut, const SwScriptInfo *pSI, const OUString &rText, TextFrameIndex nIdx, TextFrameIndex nLen) const
Definition: inftxt.cxx:387
virtual void Text(TextFrameIndex nLength, PortionType nType, sal_Int32 nHeight=0, sal_Int32 nWidth=0)=0
(empty) destructor
bool AlternativeSpelling(const SwTextFormatInfo &rInf, const TextFrameIndex nPos)
Definition: guess.cxx:561
Collection of SwLineLayout instances, represents the paragraph text in Writer layout.
Definition: porlay.hxx:229
bool ChgHyph(const bool bNew)
Definition: inftxt.cxx:1910
bool IsFull() const
Definition: inftxt.hxx:568
virtual void Paint(const SwTextPaintInfo &rInf) const override
Definition: portxt.cxx:528
virtual void Paint(const SwTextPaintInfo &rInf) const override
Definition: portxt.cxx:780
bool IsControlCharPortion() const
Definition: porlin.hxx:135
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:43
sw::WrongListIterator * GetSmartTags() const
Definition: inftxt.hxx:461
LINESTYLE_NONE
bool IsBreakPortion() const
Definition: porlin.hxx:113
sal_Unicode GetChar(TextFrameIndex const nPos) const
Definition: inftxt.hxx:247
virtual ::sw::mark::IFieldmark * getFieldmarkFor(const SwPosition &pos) const =0
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:47
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:34
void DrawCheckBox(const SwFieldFormCheckboxPortion &rPor, bool bChecked) const
Definition: inftxt.cxx:1065
TextFrameIndex BreakStart() const
Definition: guess.hxx:55
static sal_uInt16 MayUnderflow(const SwTextFormatInfo &rInf, TextFrameIndex nIdx, bool bUnderflow)
If a Line is full of HardBlanks and overflows, we must not generate underflows! Causes problems with ...
Definition: porexp.cxx:104
void SetUnderline(const FontLineStyle eUnderline)
Definition: swfont.hxx:542
virtual bool Format(SwTextFormatInfo &rInf) override
Definition: portxt.cxx:443
virtual bool GetExpText(const SwTextSizeInfo &rInf, OUString &rText) const override
Definition: porfld.cxx:442
TextFrameIndex GetLineStart() const
Definition: inftxt.hxx:595
TextFrameIndex BreakPos() const
Definition: guess.hxx:56
bool InFixMargGrp() const
Definition: porlin.hxx:107
This portion represents a part of the paragraph string.
Definition: portxt.hxx:27
static bool IsArabicText(const OUString &rText, TextFrameIndex nStt, TextFrameIndex nLen)
Checks if text is Arabic text.
Definition: porlay.cxx:1911
static SwTextPortion * CopyLinePortion(const SwLinePortion &rPortion)
Definition: portxt.cxx:216
void SetEndHyph(const bool bNew)
Definition: porlay.hxx:112
bool IsCombinedPortion() const
Definition: porlin.hxx:128
virtual bool Format(SwTextFormatInfo &rInf) override
Definition: portxt.cxx:770
virtual TextFrameIndex GetCursorOfst(sal_uInt16 nOfst) const
the parameter is actually SwTwips apparently?
Definition: porlin.cxx:226
SwPosSize(const sal_uInt16 nW=0, const sal_uInt16 nH=0)
Definition: possiz.hxx:31
virtual bool GetExpText(const SwTextSizeInfo &rInf, OUString &rText) const
Definition: porlin.cxx:314
virtual SwLinePortion * Compress() override
Definition: portxt.cxx:737
SwTwips GetLineWidth()
Returns the distance between the current horizontal position and the end of the line.
Definition: inftxt.cxx:1702
vcl::RenderContext * GetOut()
Definition: inftxt.hxx:231
SwPageFrame * FindPageFrame()
Definition: frame.hxx:658
SwParaPortion * GetParaPortion()
Definition: inftxt.hxx:128
void SetWhichPor(const PortionType nNew)
Definition: porlin.hxx:93
void SetUnderflow(SwLinePortion *pNew)
Definition: inftxt.hxx:606
bool IsFlyPortion() const
Definition: porlin.hxx:124
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2516
TextFrameIndex CutPos() const
Definition: guess.hxx:54
FontLineStyle GetOverline() const
Definition: swfont.hxx:270
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
bool IsKernPortion() const
Definition: porlin.hxx:131
sal_uInt16 GetTopBorderSpace() const
Definition: swfont.hxx:860
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:52
sal_uInt16 Width() const
Definition: inftxt.hxx:533
SwLineLayout * GetRoot()
Definition: inftxt.hxx:562
bool NotEOL() const
Definition: inftxt.hxx:201
static bool IsExportTaggedPDF(const OutputDevice &rOut)
TextFrameIndex GetIdx() const
Definition: inftxt.hxx:278
bool IsDropPortion() const
Definition: porlin.hxx:120
ITALIC_NONE
void PrePaint(const SwTextPaintInfo &rInf, const SwLinePortion *pLast) const
Definition: porlin.cxx:81
bool SnapToGrid() const
Definition: inftxt.hxx:222
TextFrameIndex GetLen() const
Definition: porlin.hxx:73
sw::WrongListIterator * GetpWrongList() const
Definition: inftxt.hxx:455
bool InTabGrp() const
Definition: porlin.hxx:99
SwTextFrame * GetTextFrame()
Definition: inftxt.hxx:291
const OUString & GetText() const
Definition: inftxt.hxx:246
virtual bool GetExpText(const SwTextSizeInfo &rInf, OUString &rText) const override
Definition: portxt.cxx:699
#define LANGUAGE_THAI
bool IsHolePortion() const
Definition: porlin.hxx:125
void Truncate()
Definition: porlin.hxx:195
SwLinePortion * mpNextPortion
Definition: porlin.hxx:53
FontLineStyle GetUnderline() const
Definition: swfont.hxx:268
SwTwips X() const
Definition: inftxt.hxx:385
virtual bool Format(SwTextFormatInfo &rInf) override
Definition: portxt.cxx:786
Base class for anything that can be part of a line in the Writer layout.
Definition: porlin.hxx:49
virtual long CalcSpacing(long nSpaceAdd, const SwTextSizeInfo &rInf) const override
Definition: portxt.cxx:616
void SetSoftHyphPos(TextFrameIndex const nNew)
Definition: inftxt.hxx:609
bool CreateHyphen(SwTextFormatInfo &rInf, SwTextGuess const &rGuess)
Definition: txthyph.cxx:254
virtual bool Format(SwTextFormatInfo &rInf) override
Definition: portxt.cxx:684
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:48
sal_Int16 ScriptType(const TextFrameIndex nPos) const
Definition: porlay.cxx:1439
bool IsHyphenate() const
If the Hyphenator returns ERROR or the language is set to NOLANGUAGE we do not hyphenate.
Definition: inftxt.cxx:1439
void SetLen(const TextFrameIndex nNew)
Definition: inftxt.hxx:281
virtual bool GetExpText(const SwTextSizeInfo &rInf, OUString &rText) const override
Definition: portxt.cxx:570
bool InExpGrp() const
Definition: porlin.hxx:106
For the text replacement and restoration of SwTextSizeInfo.
Definition: inftxt.hxx:677
unsigned char sal_uInt8
PortionType GetWhichPor() const
Definition: porlin.hxx:94
bool IsFootnotePortion() const
Definition: porlin.hxx:119
FontItalic GetItalic() const
Definition: swfont.hxx:278
bool IsErgoSumPortion() const
Definition: porlin.hxx:114
virtual void Paint(const SwTextPaintInfo &rInf) const override
Definition: portxt.cxx:739
static TextFrameIndex ThaiJustify(const OUString &rText, long *pKernArray, long *pScrArray, TextFrameIndex nIdx, TextFrameIndex nLen, TextFrameIndex nNumberOfBlanks=TextFrameIndex(0), long nSpaceAdd=0)
Performs a thai justification on the kerning array.
Definition: porlay.cxx:2085
IDocumentSettingAccess const & getIDocumentSettingAccess() const
Definition: doc.cxx:208
virtual TextFrameIndex GetCursorOfst(sal_uInt16 nOfst) const override
the parameter is actually SwTwips apparently?
Definition: portxt.cxx:506
bool OnWin() const
Definition: inftxt.hxx:199
bool IsRightToLeft() const
Definition: frame.hxx:963
SwHangingPortion * GetHangingPortion() const
Definition: guess.hxx:51
TextFrameIndex GetLen() const
Definition: inftxt.hxx:280
sal_uInt16 GetBottomBorderSpace() const
Definition: swfont.hxx:875
virtual bool Format(SwTextFormatInfo &rInf) override
Definition: portxt.cxx:809
static bool isKorean(LanguageType nLang)
sal_uInt16 Width() const
Definition: possiz.hxx:46
TextFrameIndex GetSpaceCnt(const SwTextSizeInfo &rInf, TextFrameIndex &rCnt) const
Definition: portxt.cxx:577
SwLinePortion * GetLast()
Definition: inftxt.hxx:566
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:53
void SetNextPortion(SwLinePortion *pNew)
Definition: porlin.hxx:75
bool IsSnapToChars() const
Definition: tgrditem.hxx:100
SwHangingPortion * ReleaseHangingPortion()
Definition: guess.hxx:52
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter()
Definition: breakit.hxx:62
size_t CountKashida() const
Definition: scriptinfo.hxx:146
bool IsFakeLineStart() const
Definition: inftxt.hxx:577
void SetAscent(const sal_uInt16 nNewAsc)
Definition: porlin.hxx:78
void BreakUnderflow(SwTextFormatInfo &rInf)
Definition: portxt.cxx:269
#define SPACING_PRECISION_FACTOR
Definition: scriptinfo.hxx:37
virtual void HandlePortion(SwPortionHandler &rPH) const override
Definition: portxt.cxx:775
SwDoc & GetDoc()
Definition: txtfrm.hxx:448
bool IsOtherThanFootnoteInside() const
Definition: inftxt.hxx:208
SwTextGrid GetGridType() const
Definition: tgrditem.hxx:81
virtual void Paint(const SwTextPaintInfo &rInf) const override
Definition: portxt.cxx:792
STRIKEOUT_NONE
virtual SwPosSize GetTextSize(const SwTextSizeInfo &rInfo) const override
Definition: portxt.cxx:513
SwFlyPortion * GetFly()
Definition: inftxt.hxx:614
void SetMidHyph(const bool bNew)
Definition: porlay.hxx:114
bool GetJoinBorderWithNext() const
Definition: porlin.hxx:168
SwLinePortion * GetNextPortion() const
Definition: porlin.hxx:71
static TextFrameIndex CountCJKCharacters(const OUString &rText, TextFrameIndex nPos, TextFrameIndex nEnd, LanguageType aLang)
Definition: porlay.cxx:2359
sal_Int32 KashidaJustify(long *pKernArray, long *pScrArray, TextFrameIndex nStt, TextFrameIndex nLen, long nSpaceAdd=0) const
Performs a kashida justification on the kerning array.
Definition: porlay.cxx:1826
sal_Int32 nPos
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
virtual SwPosSize GetTextSize(const SwTextSizeInfo &rInfo) const override
Definition: portxt.cxx:717
SwPosition MapViewToModelPos(TextFrameIndex nIndex) const
Definition: txtfrm.cxx:1237
aStr
sal_uInt16 & GetAscent()
Definition: porlin.hxx:76
#define COMPLEX
virtual SwLinePortion * Insert(SwLinePortion *pPortion)
Definition: porlin.cxx:172
void DrawMarkedText(const SwLinePortion &rPor, TextFrameIndex nLen, const bool bWrong, const bool bSmartTags, const bool bGrammarCheck) const
Definition: inftxt.hxx:760
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
TextFrameIndex GetSoftHyphPos() const
Definition: inftxt.hxx:608
void DrawViewOpt(const SwLinePortion &rPor, PortionType nWhich) const
Definition: inftxt.cxx:1283
bool IsPostItsPortion() const
Definition: porlin.hxx:127
virtual void HandlePortion(SwPortionHandler &rPH) const override
Definition: portxt.cxx:673
const css::uno::Reference< css::linguistic2::XHyphenatedWord > & HyphWord() const
Definition: guess.hxx:58
sal_uInt16 GetAscent() const
Definition: inftxt.hxx:710
bool IsBlankPortion() const
Definition: porlin.hxx:112