LibreOffice Module sw (master) 1
guess.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 <editeng/unolingu.hxx>
21#include <breakit.hxx>
23#include "guess.hxx"
24#include "inftxt.hxx"
25#include <pagefrm.hxx>
26#include <tgrditem.hxx>
27#include <com/sun/star/i18n/BreakType.hpp>
28#include <com/sun/star/i18n/WordType.hpp>
29#include <com/sun/star/i18n/XBreakIterator.hpp>
31#include <svl/urihelper.hxx>
32#include "porfld.hxx"
33#include <paratr.hxx>
34#include <doc.hxx>
36
37using namespace ::com::sun::star;
38using namespace ::com::sun::star::uno;
39using namespace ::com::sun::star::i18n;
40using namespace ::com::sun::star::beans;
41using namespace ::com::sun::star::linguistic2;
42
43namespace{
44
45bool IsBlank(sal_Unicode ch) { return ch == CH_BLANK || ch == CH_FULL_BLANK || ch == CH_NB_SPACE || ch == CH_SIX_PER_EM; }
46
47}
48
49// provides information for line break calculation
50// returns true if no line break has to be performed
51// otherwise possible break or hyphenation position is determined
53 const sal_uInt16 nPorHeight )
54{
55 m_nCutPos = rInf.GetIdx();
56
57 // Empty strings are always 0
58 if( !rInf.GetLen() || rInf.GetText().isEmpty() )
59 return false;
60
61 OSL_ENSURE( rInf.GetIdx() < TextFrameIndex(rInf.GetText().getLength()),
62 "+SwTextGuess::Guess: invalid SwTextFormatInfo" );
63
64 OSL_ENSURE( nPorHeight, "+SwTextGuess::Guess: no height" );
65
66 sal_uInt16 nMaxSizeDiff;
67
68 const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
69
70 sal_uInt16 nMaxComp = ( SwFontScript::CJK == rInf.GetFont()->GetActual() ) &&
71 rSI.CountCompChg() &&
72 ! rInf.IsMulti() &&
73 ! rPor.InFieldGrp() &&
74 ! rPor.IsDropPortion() ?
75 10000 :
76 0 ;
77
79 TextFrameIndex nMaxLen = TextFrameIndex(rInf.GetText().getLength()) - rInf.GetIdx();
80
82
83 // tdf#104668 space chars at the end should be cut if the compatibility option is enabled
84 // for LTR mode only
85 if ( !rInf.GetTextFrame()->IsRightToLeft() )
86 {
89 {
90 if ( rAdjust == SvxAdjust::Right || rAdjust == SvxAdjust::Center )
91 {
92 TextFrameIndex nSpaceCnt(0);
93 for (sal_Int32 i = rInf.GetText().getLength() - 1;
94 sal_Int32(rInf.GetIdx()) <= i; --i)
95 {
96 sal_Unicode cChar = rInf.GetText()[i];
97 if ( cChar != CH_BLANK && cChar != CH_FULL_BLANK && cChar != CH_SIX_PER_EM )
98 break;
99 ++nSpaceCnt;
100 }
101 TextFrameIndex nCharsCnt = nMaxLen - nSpaceCnt;
102 if ( nSpaceCnt && nCharsCnt < rPor.GetLen() )
103 {
104 if (nSpaceCnt)
105 rInf.GetTextSize( &rSI, rInf.GetIdx() + nCharsCnt, nSpaceCnt,
106 nMaxComp, m_nExtraBlankWidth, nMaxSizeDiff );
107 nMaxLen = nCharsCnt;
108 if ( !nMaxLen )
109 return true;
110 }
111 }
112 }
113 }
114
115 if ( rInf.GetLen() < nMaxLen )
116 nMaxLen = rInf.GetLen();
117
118 if( !nMaxLen )
119 return false;
120
121 sal_uInt16 nItalic = 0;
122 if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
123 {
124 bool bAddItalic = true;
125
126 // do not add extra italic value if we have an active character grid
127 if ( rInf.SnapToGrid() )
128 {
129 SwTextGridItem const*const pGrid(
131 bAddItalic = !pGrid || GRID_LINES_CHARS != pGrid->GetGridType();
132 }
133
134 // do not add extra italic value for an isolated blank:
135 if (TextFrameIndex(1) == rInf.GetLen() &&
136 CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx())])
137 {
138 bAddItalic = false;
139 }
140
143 {
144 // Content is allowed over the margin: in this case over-margin content caused by italic
145 // formatting is OK.
146 bAddItalic = false;
147 }
148
149 nItalic = bAddItalic ? nPorHeight / 12 : 0;
150
151 nLineWidth -= nItalic;
152
153 // #i46524# LineBreak bug with italics
154 if ( nLineWidth < 0 ) nLineWidth = 0;
155 }
156
157 const sal_Int32 nLeftRightBorderSpace =
158 (!rPor.GetJoinBorderWithNext() ? rInf.GetFont()->GetRightBorderSpace() : 0) +
159 (!rPor.GetJoinBorderWithPrev() ? rInf.GetFont()->GetLeftBorderSpace() : 0);
160
161 nLineWidth -= nLeftRightBorderSpace;
162
163 const bool bUnbreakableNumberings = rInf.GetTextFrame()->GetDoc()
165
166 // first check if everything fits to line
167 if ( ( nLineWidth * 2 > SwTwips(sal_Int32(nMaxLen)) * nPorHeight ) ||
168 ( bUnbreakableNumberings && rPor.IsNumberPortion() ) )
169 {
170 // call GetTextSize with maximum compression (for kanas)
171 rInf.GetTextSize( &rSI, rInf.GetIdx(), nMaxLen,
172 nMaxComp, m_nBreakWidth, nMaxSizeDiff );
173
174 if ( ( m_nBreakWidth <= nLineWidth ) || ( bUnbreakableNumberings && rPor.IsNumberPortion() ) )
175 {
176 // portion fits to line
177 m_nCutPos = rInf.GetIdx() + nMaxLen;
178 if( nItalic &&
179 (m_nCutPos >= TextFrameIndex(rInf.GetText().getLength()) ||
180 // #i48035# Needed for CalcFitToContent
181 // if first line ends with a manual line break
182 rInf.GetText()[sal_Int32(m_nCutPos)] == CH_BREAK))
183 m_nBreakWidth = m_nBreakWidth + nItalic;
184
185 // save maximum width for later use
186 if ( nMaxSizeDiff )
187 rInf.SetMaxWidthDiff( &rPor, nMaxSizeDiff );
188
189 m_nBreakWidth += nLeftRightBorderSpace;
190
191 return true;
192 }
193 }
194
195 bool bHyph = rInf.IsHyphenate() && !rInf.IsHyphForbud();
196 TextFrameIndex nHyphPos(0);
197
198 // nCutPos is the first character not fitting to the current line
199 // nHyphPos is the first character not fitting to the current line,
200 // considering an additional "-" for hyphenation
201 if( bHyph )
202 {
203 // nHyphZone is the first character not fitting in the hyphenation zone,
204 // or 0, if the whole line in the hyphenation zone,
205 // or -1, if no hyphenation zone defined (i.e. it is 0)
206 sal_Int32 nHyphZone = -1;
207 const css::beans::PropertyValues & rHyphValues = rInf.GetHyphValues();
208 assert( rHyphValues.getLength() > 5 && rHyphValues[5].Name == UPN_HYPH_ZONE );
209 // hyphenation zone (distance from the line end in twips)
210 sal_uInt16 nTextHyphenZone;
211 if ( rHyphValues[5].Value >>= nTextHyphenZone )
212 nHyphZone = nTextHyphenZone >= nLineWidth
213 ? 0
214 : sal_Int32(rInf.GetTextBreak( nLineWidth - nTextHyphenZone,
215 nMaxLen, nMaxComp, rInf.GetCachedVclData().get() ));
216
217 m_nCutPos = rInf.GetTextBreak( nLineWidth, nMaxLen, nMaxComp, nHyphPos, rInf.GetCachedVclData().get() );
218
219 // don't try to hyphenate in the hyphenation zone
220 if ( nHyphZone != -1 && TextFrameIndex(COMPLETE_STRING) != m_nCutPos )
221 {
222 sal_Int32 nZonePos = sal_Int32(m_nCutPos);
223 // disable hyphenation, if there is a space within the hyphenation zone
224 // Note: for better interoperability, not fitting space character at
225 // rInf.GetIdx()[nHyphZone] always disables the hyphenation, don't need to calculate
226 // with its fitting part. Moreover, do not check double or more spaces there, they
227 // are accepted outside of the hyphenation zone, too.
228 for (; sal_Int32(rInf.GetIdx()) <= nZonePos && nHyphZone <= nZonePos; --nZonePos )
229 {
230 sal_Unicode cChar = rInf.GetText()[nZonePos];
231 if ( cChar == CH_BLANK || cChar == CH_FULL_BLANK || cChar == CH_SIX_PER_EM )
232 {
233 bHyph = false;
234 }
235 }
236 }
237
240 {
241 // check URL from preceding space - similar to what AutoFormat does
242 const CharClass& rCC = GetAppCharClass();
243 sal_Int32 begin(m_nCutPos == TextFrameIndex(COMPLETE_STRING) ? rInf.GetText().getLength() : sal_Int32(m_nCutPos));
244 sal_Int32 end(begin);
245 for (; 0 < begin; --begin)
246 {
247 sal_Unicode cChar = rInf.GetText()[begin - 1];
248 if (cChar == CH_BLANK || cChar == CH_FULL_BLANK || cChar == CH_SIX_PER_EM)
249 {
250 break;
251 }
252 }
253 for (; end < rInf.GetText().getLength(); ++end)
254 {
255 sal_Unicode cChar = rInf.GetText()[end];
256 if (cChar == CH_BLANK || cChar == CH_FULL_BLANK || cChar == CH_SIX_PER_EM)
257 {
258 break;
259 }
260 }
261 if (!URIHelper::FindFirstURLInText(rInf.GetText(), begin, end, rCC).isEmpty())
262 {
263 bHyph = false;
264 }
265 }
266
267 // search start of the last word, if needed
268 if ( bHyph )
269 {
270 // nLastWord is the space character before the last word
271 sal_Int32 nLastWord = rInf.GetText().getLength() - 1;
272 bool bHyphenationNoLastWord = false;
273 assert( rHyphValues.getLength() > 3 && rHyphValues[3].Name == UPN_HYPH_NO_LAST_WORD );
274 if ( rHyphValues[3].Value >>= bHyphenationNoLastWord )
275 {
276 // skip spaces after the last word
277 bool bCutBlank = false;
278 for (; sal_Int32(rInf.GetIdx()) <= nLastWord; --nLastWord )
279 {
280 sal_Unicode cChar = rInf.GetText()[nLastWord];
281 if ( cChar != CH_BLANK && cChar != CH_FULL_BLANK && cChar != CH_SIX_PER_EM )
282 bCutBlank = true;
283 else if ( bCutBlank )
284 break;
285 }
286 }
287
288 // don't hyphenate the last word of the paragraph
289 if ( bHyphenationNoLastWord && sal_Int32(m_nCutPos) > nLastWord &&
291 // if the last word is multiple line long, e.g. an URL,
292 // apply this only if the space before the word is there
293 // in the actual line, i.e. start the long word in a new
294 // line, but still allows to break its last parts
295 sal_Int32(rInf.GetIdx()) < nLastWord )
296 {
297 m_nCutPos = TextFrameIndex(nLastWord);
298 }
299 }
300
301 if ( !nHyphPos && rInf.GetIdx() )
302 nHyphPos = rInf.GetIdx() - TextFrameIndex(1);
303 }
304 else
305 {
306 m_nCutPos = rInf.GetTextBreak( nLineWidth, nMaxLen, nMaxComp, rInf.GetCachedVclData().get() );
307
308#if OSL_DEBUG_LEVEL > 1
310 {
311 sal_uInt16 nMinSize;
312 rInf.GetTextSize( &rSI, rInf.GetIdx(), m_nCutPos - rInf.GetIdx(),
313 nMaxComp, nMinSize, nMaxSizeDiff );
314 OSL_ENSURE( nMinSize <= nLineWidth, "What a Guess!!!" );
315 }
316#endif
317 }
318
319 if( m_nCutPos > rInf.GetIdx() + nMaxLen )
320 {
321 // second check if everything fits to line
322 m_nCutPos = m_nBreakPos = rInf.GetIdx() + nMaxLen - TextFrameIndex(1);
323 rInf.GetTextSize( &rSI, rInf.GetIdx(), nMaxLen, nMaxComp,
324 m_nBreakWidth, nMaxSizeDiff );
325
326 // The following comparison should always give true, otherwise
327 // there likely has been a pixel rounding error in GetTextBreak
328 if ( m_nBreakWidth <= nLineWidth )
329 {
330 if (nItalic && (m_nBreakPos + TextFrameIndex(1)) >= TextFrameIndex(rInf.GetText().getLength()))
331 m_nBreakWidth = m_nBreakWidth + nItalic;
332
333 // save maximum width for later use
334 if ( nMaxSizeDiff )
335 rInf.SetMaxWidthDiff( &rPor, nMaxSizeDiff );
336
337 m_nBreakWidth += nLeftRightBorderSpace;
338
339 return true;
340 }
341 }
342
343 // we have to trigger an underflow for a footnote portion
344 // which does not fit to the current line
345 if ( rPor.IsFootnotePortion() )
346 {
347 m_nBreakPos = rInf.GetIdx();
349 return false;
350 }
351
352 TextFrameIndex nPorLen(0);
353 // do not call the break iterator nCutPos is a blank
354 sal_Unicode cCutChar = m_nCutPos < TextFrameIndex(rInf.GetText().getLength())
355 ? rInf.GetText()[sal_Int32(m_nCutPos)]
356 : 0;
357 if (IsBlank(cCutChar))
358 {
361
362 if ( rAdjust == SvxAdjust::Left )
363 {
364 // we step back until a non blank character has been found
365 // or there is only one more character left
366 while (nX && TextFrameIndex(rInf.GetText().getLength()) < m_nBreakPos &&
367 IsBlank(rInf.GetChar(--nX)))
368 --m_nBreakPos;
369 }
370 else // #i20878#
371 {
372 while (nX && m_nBreakPos > rInf.GetLineStart() + TextFrameIndex(1) &&
373 IsBlank(rInf.GetChar(--nX)))
374 --m_nBreakPos;
375 }
376
377 if( m_nBreakPos > rInf.GetIdx() )
378 nPorLen = m_nBreakPos - rInf.GetIdx();
379 while (++m_nCutPos < TextFrameIndex(rInf.GetText().getLength()) &&
380 IsBlank(rInf.GetChar(m_nCutPos)))
381 ; // nothing
382
384 }
385 else
386 {
387 // New: We should have a look into the last portion, if it was a
388 // field portion. For this, we expand the text of the field portion
389 // into our string. If the line break position is inside of before
390 // the field portion, we trigger an underflow.
391
392 TextFrameIndex nOldIdx = rInf.GetIdx();
393 sal_Unicode cFieldChr = 0;
394
395#if OSL_DEBUG_LEVEL > 0
396 OUString aDebugString;
397#endif
398
399 // be careful: a field portion can be both: 0x01 (common field)
400 // or 0x02 (the follow of a footnode)
401 if ( rInf.GetLast() && rInf.GetLast()->InFieldGrp() &&
402 ! rInf.GetLast()->IsFootnotePortion() &&
403 rInf.GetIdx() > rInf.GetLineStart() &&
405 (cFieldChr = rInf.GetText()[sal_Int32(rInf.GetIdx()) - 1]))
406 {
407 SwFieldPortion* pField = static_cast<SwFieldPortion*>(rInf.GetLast());
408 OUString aText;
409 pField->GetExpText( rInf, aText );
410
411 if ( !aText.isEmpty() )
412 {
413 m_nFieldDiff = TextFrameIndex(aText.getLength() - 1);
415 nHyphPos = nHyphPos + m_nFieldDiff;
416
417#if OSL_DEBUG_LEVEL > 0
418 aDebugString = rInf.GetText();
419#endif
420
421 // this is pretty nutso... reverted at the end...
422 OUString& rOldText = const_cast<OUString&> (rInf.GetText());
423 rOldText = rOldText.replaceAt(sal_Int32(rInf.GetIdx()) - 1, 1, aText);
424 rInf.SetIdx( rInf.GetIdx() + m_nFieldDiff );
425 }
426 else
427 cFieldChr = 0;
428 }
429
430 LineBreakHyphenationOptions aHyphOpt;
431 Reference< XHyphenator > xHyph;
432 if( bHyph )
433 {
434 xHyph = ::GetHyphenator();
435 aHyphOpt = LineBreakHyphenationOptions( xHyph,
436 rInf.GetHyphValues(), sal_Int32(nHyphPos));
437 }
438
439 // Get Language for break iterator.
440 // We have to switch the current language if we have a script
441 // change at nCutPos. Otherwise LATIN punctuation would never
442 // be allowed to be hanging punctuation.
443 // NEVER call GetLang if the string has been modified!!!
444 LanguageType aLang = rInf.GetFont()->GetLanguage();
445
446 // If we are inside a field portion, we use a temporary string which
447 // differs from the string at the textnode. Therefore we are not allowed
448 // to call the GetLang function.
449 if ( m_nCutPos && ! rPor.InFieldGrp() )
450 {
451 const CharClass& rCC = GetAppCharClass();
452
453 // step back until a non-punctuation character is reached
454 TextFrameIndex nLangIndex = m_nCutPos;
455
456 // If a field has been expanded right in front of us we do not
457 // step further than the beginning of the expanded field
458 // (which is the position of the field placeholder in our
459 // original string).
460 const TextFrameIndex nDoNotStepOver = CH_TXTATR_BREAKWORD == cFieldChr
461 ? rInf.GetIdx() - m_nFieldDiff - TextFrameIndex(1)
462 : TextFrameIndex(0);
463
464 if ( nLangIndex > nDoNotStepOver &&
465 TextFrameIndex(rInf.GetText().getLength()) == nLangIndex)
466 --nLangIndex;
467
468 while ( nLangIndex > nDoNotStepOver &&
469 !rCC.isLetterNumeric(rInf.GetText(), sal_Int32(nLangIndex)))
470 --nLangIndex;
471
472 // last "real" character is not inside our current portion
473 // we have to check the script type of the last "real" character
474 if ( nLangIndex < rInf.GetIdx() )
475 {
476 sal_uInt16 nScript = g_pBreakIt->GetRealScriptOfText( rInf.GetText(),
477 sal_Int32(nLangIndex));
478 OSL_ENSURE( nScript, "Script is not between 1 and 4" );
479
480 // compare current script with script from last "real" character
481 if ( SwFontScript(nScript - 1) != rInf.GetFont()->GetActual() )
482 {
483 aLang = rInf.GetTextFrame()->GetLangOfChar(
484 CH_TXTATR_BREAKWORD == cFieldChr
485 ? nDoNotStepOver
486 : nLangIndex,
487 nScript, true);
488 }
489 }
490 }
491
492 const ForbiddenCharacters aForbidden(
494
495 const bool bAllowHanging = rInf.IsHanging() && ! rInf.IsMulti() &&
496 ! rInf.GetTextFrame()->IsInTab() &&
497 ! rPor.InFieldGrp();
498
499 LineBreakUserOptions aUserOpt(
500 aForbidden.beginLine, aForbidden.endLine,
501 rInf.HasForbiddenChars(), bAllowHanging, false );
502
503 // !!! We must have a local copy of the locale, because inside
504 // getLineBreak the LinguEventListener can trigger a new formatting,
505 // which can corrupt the locale pointer inside pBreakIt.
506 const lang::Locale aLocale = g_pBreakIt->GetLocale( aLang );
507
508 // determines first possible line break from nCutPos to
509 // start index of current line
510 LineBreakResults aResult = g_pBreakIt->GetBreakIter()->getLineBreak(
511 rInf.GetText(), sal_Int32(m_nCutPos), aLocale,
512 sal_Int32(rInf.GetLineStart()), aHyphOpt, aUserOpt );
513
514 m_nBreakPos = TextFrameIndex(aResult.breakIndex);
515
516 // if we are formatting multi portions we want to allow line breaks
517 // at the border between single line and multi line portion
518 // we have to be careful with footnote portions, they always come in
519 // with an index 0
520 if ( m_nBreakPos < rInf.GetLineStart() && rInf.IsFirstMulti() &&
521 ! rInf.IsFootnoteInside() )
522 m_nBreakPos = rInf.GetLineStart();
523
525
526 bHyph = BreakType::HYPHENATION == aResult.breakType;
527
529 {
530 // found hyphenation position within line
531 // nBreakPos is set to the hyphenation position
532 m_xHyphWord = aResult.rHyphenatedWord;
533 m_nBreakPos += TextFrameIndex(m_xHyphWord->getHyphenationPos() + 1);
534
535 // if not in interactive mode, we have to break behind a soft hyphen
536 if ( ! rInf.IsInterHyph() && rInf.GetIdx() )
537 {
538 sal_Int32 const nSoftHyphPos =
539 m_xHyphWord->getWord().indexOf( CHAR_SOFTHYPHEN );
540
541 if ( nSoftHyphPos >= 0 &&
542 m_nBreakStart + TextFrameIndex(nSoftHyphPos) <= m_nBreakPos &&
543 m_nBreakPos > rInf.GetLineStart() )
544 m_nBreakPos = rInf.GetIdx() - TextFrameIndex(1);
545 }
546
547 if( m_nBreakPos >= rInf.GetIdx() )
548 {
549 nPorLen = m_nBreakPos - rInf.GetIdx();
550 if ('-' == rInf.GetText()[ sal_Int32(m_nBreakPos) - 1 ])
551 m_xHyphWord = nullptr;
552 }
553 }
554 else if ( !bHyph && m_nBreakPos >= rInf.GetLineStart() )
555 {
556 OSL_ENSURE(sal_Int32(m_nBreakPos) != COMPLETE_STRING, "we should have found a break pos");
557
558 // found break position within line
559 m_xHyphWord = nullptr;
560
561 // check, if break position is soft hyphen and an underflow
562 // has to be triggered
563 if( m_nBreakPos > rInf.GetLineStart() && rInf.GetIdx() &&
564 CHAR_SOFTHYPHEN == rInf.GetText()[ sal_Int32(m_nBreakPos) - 1 ])
565 {
566 m_nBreakPos = rInf.GetIdx() - TextFrameIndex(1);
567 }
568
569 if( rAdjust != SvxAdjust::Left )
570 {
571 // Delete any blanks at the end of a line, but be careful:
572 // If a field has been expanded, we do not want to delete any
573 // blanks inside the field portion. This would cause an unwanted
574 // underflow
576 while( nX > rInf.GetLineStart() &&
577 ( CH_TXTATR_BREAKWORD != cFieldChr || nX > rInf.GetIdx() ) &&
578 ( CH_BLANK == rInf.GetChar( --nX ) ||
579 CH_SIX_PER_EM == rInf.GetChar( nX ) ||
580 CH_FULL_BLANK == rInf.GetChar( nX ) ) )
581 m_nBreakPos = nX;
582 }
583 if( m_nBreakPos > rInf.GetIdx() )
584 nPorLen = m_nBreakPos - rInf.GetIdx();
585 }
586 else
587 {
588 // no line break found, setting nBreakPos to COMPLETE_STRING
589 // causes a break cut
591 OSL_ENSURE( m_nCutPos >= rInf.GetIdx(), "Deep cut" );
592 nPorLen = m_nCutPos - rInf.GetIdx();
593 }
594
596 {
597 const TextFrameIndex nHangingLen = m_nBreakPos - m_nCutPos;
598 SwPosSize aTmpSize = rInf.GetTextSize( &rSI, m_nCutPos, nHangingLen );
599 aTmpSize.Width(aTmpSize.Width() + nLeftRightBorderSpace);
600 OSL_ENSURE( !m_pHanging, "A hanging portion is hanging around" );
601 m_pHanging.reset( new SwHangingPortion( std::move(aTmpSize) ) );
602 m_pHanging->SetLen( nHangingLen );
603 nPorLen = m_nCutPos - rInf.GetIdx();
604 }
605
606 // If we expanded a field, we must repair the original string.
607 // In case we do not trigger an underflow, we correct the nBreakPos
608 // value, but we cannot correct the nBreakStart value:
609 // If we have found a hyphenation position, nBreakStart can lie before
610 // the field.
611 if ( CH_TXTATR_BREAKWORD == cFieldChr )
612 {
613 if ( m_nBreakPos < rInf.GetIdx() )
614 m_nBreakPos = nOldIdx - TextFrameIndex(1);
616 {
617 OSL_ENSURE( m_nBreakPos >= m_nFieldDiff, "I've got field trouble!" );
619 }
620
621 OSL_ENSURE( m_nCutPos >= rInf.GetIdx() && m_nCutPos >= m_nFieldDiff,
622 "I've got field trouble, part2!" );
624
625 OUString& rOldText = const_cast<OUString&> (rInf.GetText());
626 OUString aReplacement( cFieldChr );
627 rOldText = rOldText.replaceAt(sal_Int32(nOldIdx) - 1, sal_Int32(m_nFieldDiff) + 1, aReplacement);
628 rInf.SetIdx( nOldIdx );
629
630#if OSL_DEBUG_LEVEL > 0
631 OSL_ENSURE( aDebugString == rInf.GetText(),
632 "Somebody, somebody, somebody put something in my string" );
633#endif
634 }
635 }
636
637 if( nPorLen )
638 {
639 rInf.GetTextSize( &rSI, rInf.GetIdx(), nPorLen,
640 nMaxComp, m_nBreakWidth, nMaxSizeDiff,
641 rInf.GetCachedVclData().get() );
642
643 // save maximum width for later use
644 if ( nMaxSizeDiff )
645 rInf.SetMaxWidthDiff( &rPor, nMaxSizeDiff );
646
647 m_nBreakWidth += nItalic + nLeftRightBorderSpace;
648 }
649 else
650 m_nBreakWidth = 0;
651
652 if (m_nBreakStart > rInf.GetIdx() + nPorLen + m_nFieldDiff)
653 {
654 rInf.GetTextSize(&rSI, rInf.GetIdx() + nPorLen,
655 m_nBreakStart - rInf.GetIdx() - nPorLen - m_nFieldDiff, nMaxComp,
656 m_nExtraBlankWidth, nMaxSizeDiff, rInf.GetCachedVclData().get());
657 }
658
659 if( m_pHanging )
660 {
662 // Keep following SwBreakPortion in the same line.
663 if ( CH_BREAK == rInf.GetChar( m_nBreakPos + m_pHanging->GetLen() ) )
664 return true;
665 }
666
667 return false;
668}
669
670// returns true if word at position nPos has a different spelling
671// if hyphenated at this position (old german spelling)
673 const TextFrameIndex nPos)
674{
675 // get word boundaries
676 Boundary aBound = g_pBreakIt->GetBreakIter()->getWordBoundary(
677 rInf.GetText(), sal_Int32(nPos),
679 WordType::DICTIONARY_WORD, true );
680 m_nBreakStart = TextFrameIndex(aBound.startPos);
681 sal_Int32 nWordLen = aBound.endPos - sal_Int32(m_nBreakStart);
682
683 // if everything else fails, we want to cut at nPos
684 m_nCutPos = nPos;
685
686 OUString const aText( rInf.GetText().copy(sal_Int32(m_nBreakStart), nWordLen) );
687
688 // check, if word has alternative spelling
689 Reference< XHyphenator > xHyph( ::GetHyphenator() );
690 OSL_ENSURE( xHyph.is(), "Hyphenator is missing");
692 m_xHyphWord = xHyph->queryAlternativeSpelling( aText,
694 sal::static_int_cast<sal_Int16>(sal_Int32(nPos - m_nBreakStart)),
695 rInf.GetHyphValues() );
696 return m_xHyphWord.is() && m_xHyphWord->isAlternativeSpelling();
697}
698
699/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nLineWidth
@ HYPHENATE_URLS
tdf#152952
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...
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:34
bool isLetterNumeric(const OUString &rStr, sal_Int32 nPos) const
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
virtual const css::i18n::ForbiddenCharacters * getForbiddenCharacters(LanguageType nLang, bool bLocaleData) const =0
Return the forbidden characters.
SvxAdjust GetAdjust() const
const SvxAdjustItem & GetAdjust(bool=true) const
Definition: paratr.hxx:194
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:62
const css::lang::Locale & GetLocale(const LanguageType aLang)
Definition: breakit.hxx:67
sal_uInt16 GetRealScriptOfText(const OUString &rText, sal_Int32 nPos) const
Definition: breakit.cxx:84
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:765
IDocumentSettingAccess const & getIDocumentSettingAccess() const
Definition: doc.cxx:184
virtual bool GetExpText(const SwTextSizeInfo &rInf, OUString &rText) const override
Definition: porfld.cxx:453
FontItalic GetItalic() const
Definition: swfont.hxx:282
sal_uInt16 GetRightBorderSpace() const
Definition: swfont.hxx:892
SwFontScript GetActual() const
Definition: swfont.hxx:184
LanguageType GetLanguage() const
Definition: swfont.hxx:283
sal_uInt16 GetLeftBorderSpace() const
Definition: swfont.hxx:907
bool IsInTab() const
Definition: frame.hxx:956
bool IsRightToLeft() const
Definition: frame.hxx:988
SwPageFrame * FindPageFrame()
Definition: frame.hxx:681
bool GetJoinBorderWithPrev() const
Definition: porlin.hxx:177
TextFrameIndex GetLen() const
Definition: porlin.hxx:77
bool GetJoinBorderWithNext() const
Definition: porlin.hxx:178
bool IsFootnotePortion() const
Definition: porlin.hxx:129
bool IsDropPortion() const
Definition: porlin.hxx:130
bool InFieldGrp() const
Definition: porlin.hxx:111
bool IsNumberPortion() const
Definition: porlin.hxx:144
SwScriptInfo & GetScriptInfo()
Definition: porlay.hxx:291
SwTwips Width() const
Definition: possiz.hxx:51
size_t CountCompChg() const
Definition: scriptinfo.hxx:163
SwLinePortion * GetLast()
Definition: inftxt.hxx:564
bool IsInterHyph() const
Definition: inftxt.hxx:585
TextFrameIndex GetLineStart() const
Definition: inftxt.hxx:593
bool IsHyphenate() const
If the Hyphenator returns ERROR or the language is set to NOLANGUAGE we do not hyphenate.
Definition: inftxt.cxx:1496
SwTwips GetLineWidth()
Returns the distance between the current horizontal position and the end of the line.
Definition: inftxt.cxx:1773
const css::beans::PropertyValues & GetHyphValues() const
Definition: inftxt.cxx:1417
bool IsHyphForbud() const
Definition: inftxt.hxx:568
SwDoc & GetDoc()
Definition: txtfrm.hxx:466
LanguageType GetLangOfChar(TextFrameIndex nIndex, sal_uInt16 nScript, bool bNoChar=false) const
Definition: txtfrm.cxx:1343
SwTextNode const * GetTextNodeForParaProps() const
Definition: txtfrm.cxx:1303
SwTextGrid GetGridType() const
Definition: tgrditem.hxx:81
bool AlternativeSpelling(const SwTextFormatInfo &rInf, const TextFrameIndex nPos)
Definition: guess.cxx:672
sal_uInt16 m_nExtraBlankWidth
Definition: guess.hxx:41
sal_uInt16 m_nBreakWidth
Definition: guess.hxx:40
TextFrameIndex m_nBreakPos
Definition: guess.hxx:37
std::unique_ptr< SwHangingPortion > m_pHanging
Definition: guess.hxx:34
TextFrameIndex m_nBreakStart
Definition: guess.hxx:36
css::uno::Reference< css::linguistic2::XHyphenatedWord > m_xHyphWord
Definition: guess.hxx:33
bool Guess(const SwTextPortion &rPor, SwTextFormatInfo &rInf, const sal_uInt16 nHeight)
Definition: guess.cxx:52
TextFrameIndex m_nCutPos
Definition: guess.hxx:35
TextFrameIndex m_nFieldDiff
Definition: guess.hxx:38
SwParaPortion * GetParaPortion()
Definition: inftxt.hxx:121
This portion represents a part of the paragraph string.
Definition: portxt.hxx:27
SwTextFrame * GetTextFrame()
Definition: inftxt.hxx:288
void SetMaxWidthDiff(const SwLinePortion *nKey, sal_uInt16 nVal)
Definition: inftxt.hxx:298
TextFrameIndex GetTextBreak(const tools::Long nLineWidth, const TextFrameIndex nMaxLen, const sal_uInt16 nComp, vcl::text::TextLayoutCache const *) const
Definition: inftxt.cxx:437
const std::shared_ptr< const vcl::text::TextLayoutCache > & GetCachedVclData() const
Definition: inftxt.hxx:332
SwFont * GetFont()
Definition: inftxt.hxx:232
void SetIdx(const TextFrameIndex nNew)
Definition: inftxt.hxx:274
bool IsHanging() const
Definition: inftxt.hxx:210
SwPosSize GetTextSize(OutputDevice *pOut, const SwScriptInfo *pSI, const OUString &rText, TextFrameIndex nIdx, TextFrameIndex nLen) const
Definition: inftxt.cxx:385
sal_Unicode GetChar(TextFrameIndex const nPos) const
Definition: inftxt.hxx:241
TextFrameIndex GetLen() const
Definition: inftxt.hxx:275
bool NotEOL() const
Definition: inftxt.hxx:195
bool IsFootnoteInside() const
Definition: inftxt.hxx:200
bool IsFirstMulti() const
Definition: inftxt.hxx:206
const OUString & GetText() const
Definition: inftxt.hxx:240
TextFrameIndex GetIdx() const
Definition: inftxt.hxx:273
bool SnapToGrid() const
Definition: inftxt.hxx:216
bool HasForbiddenChars() const
Definition: inftxt.hxx:214
bool IsMulti() const
Definition: inftxt.hxx:204
ITALIC_NONE
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:171
CharClass & GetAppCharClass()
Definition: init.cxx:706
constexpr OUStringLiteral UPN_HYPH_ZONE
constexpr OUStringLiteral UPN_HYPH_NO_LAST_WORD
sal_uInt16 nPos
SVL_DLLPUBLIC OUString FindFirstURLInText(OUString const &rText, sal_Int32 &rBegin, sal_Int32 &rEnd, CharClass const &rCharClass, INetURLObject::EncodeMechanism eMechanism=INetURLObject::EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
double getLength(const B2DPolygon &rCandidate)
Value
int i
enumrange< T >::Iterator begin(enumrange< T >)
end
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2595
SvxAdjust
const sal_Unicode CH_BREAK
Definition: swfont.hxx:43
const sal_Unicode CH_NB_SPACE
Definition: swfont.hxx:48
const sal_Unicode CH_SIX_PER_EM
Definition: swfont.hxx:49
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
SwFontScript
Definition: swfont.hxx:124
const sal_Unicode CH_FULL_BLANK
Definition: swfont.hxx:47
uno::Reference< linguistic2::XHyphenator > GetHyphenator()
Definition: swtypes.cxx:57
tools::Long SwTwips
Definition: swtypes.hxx:51
#define CHAR_SOFTHYPHEN
Definition: swtypes.hxx:175
constexpr sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:57
@ GRID_LINES_CHARS
Definition: tgrditem.hxx:30
sal_uInt16 sal_Unicode